circolog/formatter/format.go

131 lines
3 KiB
Go
Raw Permalink Normal View History

package formatter
2018-08-23 15:35:55 +02:00
import (
2018-11-09 13:59:58 +01:00
"encoding/json"
"fmt"
"hash/fnv"
2018-11-09 13:59:58 +01:00
"io"
2018-08-23 15:35:55 +02:00
"text/template"
"time"
2019-03-25 02:46:03 +01:00
"git.lattuga.net/boyska/circolog/data"
2019-01-02 17:29:34 +01:00
"github.com/mgutz/ansi"
"gopkg.in/mgo.v2/bson"
2018-08-23 15:35:55 +02:00
)
// Formatter is an interface, so that multiple implementations can exist
2019-03-25 02:46:03 +01:00
type Formatter func(data.Message) string
2018-08-23 15:35:55 +02:00
var tmplFuncs template.FuncMap
var syslogTmpl *template.Template
func init() {
tmplFuncs := template.FuncMap{
"dateFormat": func(dt time.Time, fmt string) string {
return dt.Format(fmt)
},
"rfc822": func(dt time.Time) string {
return dt.Format(time.RFC822)
},
2019-01-02 13:57:34 +01:00
"sevName": func(s int) string {
2019-01-02 17:29:34 +01:00
names := []string{"emerg ", "alert ", "crit ", "err ", "warn ", "notice", "info ", "dbg "}
switch {
case s < 2: // emerg..alert
return ansi.Color(names[s], "red+b")
case s < 4: // emerg..err
return ansi.Color(names[s], "red")
case s < 6: // warn..notice
return ansi.Color(names[s], "white+b")
case s >= len(names):
2019-01-02 13:57:34 +01:00
return "???"
2019-01-02 17:29:34 +01:00
default:
return names[s]
2019-01-02 13:57:34 +01:00
}
},
2019-01-02 17:29:34 +01:00
"color": func(color, text string) string {
return ansi.Color(text, color) // slow; should use colorfunc
},
"red": ansi.ColorFunc("red+b"),
"autoColor": func(s string) string {
// from https://weechat.org/blog/post/2011/08/28/Beautify-your-WeeChat
palette := []string{"31", "35", "38", "40", "49", "63", "70", "80", "92", "99", "112", "126", "130", "138", "142", "148", "167", "169", "174", "176", "178", "184", "186", "210", "212", "215", "247"}
hash := fnv.New32()
hash.Write([]byte(s))
picked := palette[int(hash.Sum32())%len(palette)]
return ansi.Color(s, picked)
},
2018-08-23 15:35:55 +02:00
}
syslogTmpl = template.Must(template.New("syslog").Funcs(tmplFuncs).Parse(
"{{color \"yellow\" (rfc822 (index . \"time\")) }} {{index . \"host\"}} " +
2019-03-24 19:54:41 +01:00
"{{index . \"prog\" | autoColor}}" +
2018-08-23 15:35:55 +02:00
"{{ if (ne (index . \"proc_id\") \"-\")}}[{{index . \"proc_id\"}}]{{end}}: " +
2019-03-24 19:54:41 +01:00
"{{ sevName (index . \"sev\") }} " +
"{{index . \"msg\"}}",
2018-08-23 15:35:55 +02:00
))
}
type Format int
2018-11-09 13:59:58 +01:00
func (rf *Format) Set(v string) error {
newvalue, err := parseFormat(v)
if err != nil {
return err
}
*rf = newvalue
return nil
}
func (rf Format) String() string {
switch rf {
case FormatJSON:
return "json"
case FormatSyslog:
return "syslog"
case FormatBSON:
return "bson"
}
return ""
}
2019-03-25 02:46:03 +01:00
func (rf Format) WriteFormatted(w io.Writer, msg data.Message) error {
return WriteFormatted(w, rf, msg)
}
func parseFormat(s string) (Format, error) {
2018-11-09 13:59:58 +01:00
switch s {
case "json":
return FormatJSON, nil
2018-11-09 13:59:58 +01:00
case "syslog":
return FormatSyslog, nil
case "bson":
return FormatBSON, nil
2018-11-09 13:59:58 +01:00
default:
return 0, fmt.Errorf("Undefined format `%s`", s)
}
}
const (
FormatSyslog = iota // 0
FormatJSON = iota
FormatBSON = iota
2018-11-09 13:59:58 +01:00
)
2019-03-25 02:46:03 +01:00
func WriteFormatted(w io.Writer, f Format, msg data.Message) error {
2018-11-09 13:59:58 +01:00
switch f {
case FormatSyslog:
2018-11-09 13:59:58 +01:00
return syslogTmpl.Execute(w, msg)
case FormatJSON:
2018-11-09 13:59:58 +01:00
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
return enc.Encode(msg)
case FormatBSON:
enc, err := bson.Marshal(msg)
if err != nil {
return err
}
_, err = w.Write(enc)
return err
2018-11-09 13:59:58 +01:00
}
return nil
2018-08-23 15:35:55 +02:00
}