2018-11-11 20:42:26 +01:00
|
|
|
package formatter
|
2018-08-23 15:35:55 +02:00
|
|
|
|
|
|
|
import (
|
2018-11-09 13:59:58 +01:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
2018-08-23 15:35:55 +02:00
|
|
|
"text/template"
|
|
|
|
"time"
|
|
|
|
|
2019-01-02 17:29:34 +01:00
|
|
|
"github.com/mgutz/ansi"
|
2018-08-23 15:35:55 +02:00
|
|
|
"gopkg.in/mcuadros/go-syslog.v2/format"
|
2018-11-11 20:54:10 +01:00
|
|
|
"gopkg.in/mgo.v2/bson"
|
2018-08-23 15:35:55 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
},
|
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"),
|
2018-08-23 15:35:55 +02:00
|
|
|
}
|
|
|
|
syslogTmpl = template.Must(template.New("syslog").Funcs(tmplFuncs).Parse(
|
2019-01-02 17:29:34 +01:00
|
|
|
"{{color \"yellow\" (rfc822 (index . \"timestamp\")) }} {{index . \"hostname\"}} " +
|
2018-08-23 15:35:55 +02:00
|
|
|
"{{index . \"app_name\"}}" +
|
|
|
|
"{{ if (ne (index . \"proc_id\") \"-\")}}[{{index . \"proc_id\"}}]{{end}}: " +
|
2019-01-02 17:29:34 +01:00
|
|
|
"{{ sevName (index . \"severity\") }} " +
|
2018-08-23 15:35:55 +02:00
|
|
|
"{{index . \"message\"}}",
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
2018-11-11 20:42:26 +01:00
|
|
|
type Format int
|
2018-11-09 13:59:58 +01:00
|
|
|
|
2018-11-11 20:42:26 +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"
|
2018-11-11 20:54:10 +01:00
|
|
|
case FormatBSON:
|
|
|
|
return "bson"
|
2018-11-11 20:42:26 +01:00
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
func (rf Format) WriteFormatted(w io.Writer, msg format.LogParts) error {
|
|
|
|
return WriteFormatted(w, rf, msg)
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseFormat(s string) (Format, error) {
|
2018-11-09 13:59:58 +01:00
|
|
|
switch s {
|
|
|
|
case "json":
|
2018-11-11 20:42:26 +01:00
|
|
|
return FormatJSON, nil
|
2018-11-09 13:59:58 +01:00
|
|
|
case "syslog":
|
2018-11-11 20:42:26 +01:00
|
|
|
return FormatSyslog, nil
|
2018-11-11 20:54:10 +01:00
|
|
|
case "bson":
|
|
|
|
return FormatBSON, nil
|
2018-11-09 13:59:58 +01:00
|
|
|
default:
|
|
|
|
return 0, fmt.Errorf("Undefined format `%s`", s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
2018-11-11 20:42:26 +01:00
|
|
|
FormatSyslog = iota // 0
|
|
|
|
FormatJSON = iota
|
2018-11-11 20:54:10 +01:00
|
|
|
FormatBSON = iota
|
2018-11-09 13:59:58 +01:00
|
|
|
)
|
|
|
|
|
2018-11-11 20:42:26 +01:00
|
|
|
func WriteFormatted(w io.Writer, f Format, msg format.LogParts) error {
|
2018-11-09 13:59:58 +01:00
|
|
|
switch f {
|
2018-11-11 20:42:26 +01:00
|
|
|
case FormatSyslog:
|
2018-11-09 13:59:58 +01:00
|
|
|
return syslogTmpl.Execute(w, msg)
|
2018-11-11 20:42:26 +01:00
|
|
|
case FormatJSON:
|
2018-11-09 13:59:58 +01:00
|
|
|
enc := json.NewEncoder(w)
|
|
|
|
enc.SetIndent("", " ")
|
|
|
|
return enc.Encode(msg)
|
2018-11-11 20:54:10 +01:00
|
|
|
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
|
|
|
}
|