123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- package formatter
- import (
- "encoding/json"
- "fmt"
- "hash/fnv"
- "io"
- "text/template"
- "time"
- "github.com/mgutz/ansi"
- "gopkg.in/mcuadros/go-syslog.v2/format"
- "gopkg.in/mgo.v2/bson"
- )
- // Formatter is an interface, so that multiple implementations can exist
- type Formatter func(format.LogParts) string
- 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)
- },
- "sevName": func(s int) string {
- 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):
- return "???"
- default:
- return names[s]
- }
- },
- "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)
- },
- }
- syslogTmpl = template.Must(template.New("syslog").Funcs(tmplFuncs).Parse(
- "{{color \"yellow\" (rfc822 (index . \"timestamp\")) }} {{index . \"hostname\"}} " +
- "{{index . \"app_name\" | autoColor}}" +
- "{{ if (ne (index . \"proc_id\") \"-\")}}[{{index . \"proc_id\"}}]{{end}}: " +
- "{{ sevName (index . \"severity\") }} " +
- "{{index . \"message\"}}",
- ))
- }
- type Format int
- 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 ""
- }
- func (rf Format) WriteFormatted(w io.Writer, msg format.LogParts) error {
- return WriteFormatted(w, rf, msg)
- }
- func parseFormat(s string) (Format, error) {
- switch s {
- case "json":
- return FormatJSON, nil
- case "syslog":
- return FormatSyslog, nil
- case "bson":
- return FormatBSON, nil
- default:
- return 0, fmt.Errorf("Undefined format `%s`", s)
- }
- }
- const (
- FormatSyslog = iota // 0
- FormatJSON = iota
- FormatBSON = iota
- )
- func WriteFormatted(w io.Writer, f Format, msg format.LogParts) error {
- switch f {
- case FormatSyslog:
- return syslogTmpl.Execute(w, msg)
- case FormatJSON:
- 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
- }
- return nil
- }
|