blob: 2605753599faf140f7a91f3fc462da4c0971ef64 [file] [log] [blame]
Jonathan Hartf86817b2018-08-17 10:35:54 -07001package logrus
2
3import (
Matteo Scandolo1f49bf52018-11-20 13:56:45 -08004 "bytes"
Jonathan Hartf86817b2018-08-17 10:35:54 -07005 "encoding/json"
6 "fmt"
7)
8
9type fieldKey string
Jonathan Hartf86817b2018-08-17 10:35:54 -070010
Matteo Scandolo1f49bf52018-11-20 13:56:45 -080011// FieldMap allows customization of the key names for default fields.
12type FieldMap map[fieldKey]string
Jonathan Hartf86817b2018-08-17 10:35:54 -070013
14func (f FieldMap) resolve(key fieldKey) string {
15 if k, ok := f[key]; ok {
16 return k
17 }
18
19 return string(key)
20}
21
Matteo Scandolo1f49bf52018-11-20 13:56:45 -080022// JSONFormatter formats logs into parsable json
Jonathan Hartf86817b2018-08-17 10:35:54 -070023type JSONFormatter struct {
24 // TimestampFormat sets the format used for marshaling timestamps.
25 TimestampFormat string
26
27 // DisableTimestamp allows disabling automatic timestamps in output
28 DisableTimestamp bool
29
Matteo Scandolo1f49bf52018-11-20 13:56:45 -080030 // DataKey allows users to put all the log entry parameters into a nested dictionary at a given key.
31 DataKey string
32
33 // FieldMap allows users to customize the names of keys for default fields.
Jonathan Hartf86817b2018-08-17 10:35:54 -070034 // As an example:
35 // formatter := &JSONFormatter{
36 // FieldMap: FieldMap{
Matteo Scandolo1f49bf52018-11-20 13:56:45 -080037 // FieldKeyTime: "@timestamp",
Jonathan Hartf86817b2018-08-17 10:35:54 -070038 // FieldKeyLevel: "@level",
Matteo Scandolo1f49bf52018-11-20 13:56:45 -080039 // FieldKeyMsg: "@message",
40 // FieldKeyFunc: "@caller",
Jonathan Hartf86817b2018-08-17 10:35:54 -070041 // },
42 // }
43 FieldMap FieldMap
Matteo Scandolo1f49bf52018-11-20 13:56:45 -080044
45 // PrettyPrint will indent all json logs
46 PrettyPrint bool
Jonathan Hartf86817b2018-08-17 10:35:54 -070047}
48
Matteo Scandolo1f49bf52018-11-20 13:56:45 -080049// Format renders a single log entry
Jonathan Hartf86817b2018-08-17 10:35:54 -070050func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
Matteo Scandolo1f49bf52018-11-20 13:56:45 -080051 data := make(Fields, len(entry.Data)+4)
Jonathan Hartf86817b2018-08-17 10:35:54 -070052 for k, v := range entry.Data {
53 switch v := v.(type) {
54 case error:
55 // Otherwise errors are ignored by `encoding/json`
Matteo Scandolo1f49bf52018-11-20 13:56:45 -080056 // https://github.com/sirupsen/logrus/issues/137
Jonathan Hartf86817b2018-08-17 10:35:54 -070057 data[k] = v.Error()
58 default:
59 data[k] = v
60 }
61 }
Matteo Scandolo1f49bf52018-11-20 13:56:45 -080062
63 if f.DataKey != "" {
64 newData := make(Fields, 4)
65 newData[f.DataKey] = data
66 data = newData
67 }
68
69 prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
Jonathan Hartf86817b2018-08-17 10:35:54 -070070
71 timestampFormat := f.TimestampFormat
72 if timestampFormat == "" {
Matteo Scandolo1f49bf52018-11-20 13:56:45 -080073 timestampFormat = defaultTimestampFormat
Jonathan Hartf86817b2018-08-17 10:35:54 -070074 }
75
Matteo Scandolo1f49bf52018-11-20 13:56:45 -080076 if entry.err != "" {
77 data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err
78 }
Jonathan Hartf86817b2018-08-17 10:35:54 -070079 if !f.DisableTimestamp {
80 data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
81 }
82 data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
83 data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
Matteo Scandolo1f49bf52018-11-20 13:56:45 -080084 if entry.HasCaller() {
85 data[f.FieldMap.resolve(FieldKeyFunc)] = entry.Caller.Function
86 data[f.FieldMap.resolve(FieldKeyFile)] = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
87 }
Jonathan Hartf86817b2018-08-17 10:35:54 -070088
Matteo Scandolo1f49bf52018-11-20 13:56:45 -080089 var b *bytes.Buffer
90 if entry.Buffer != nil {
91 b = entry.Buffer
92 } else {
93 b = &bytes.Buffer{}
94 }
95
96 encoder := json.NewEncoder(b)
97 if f.PrettyPrint {
98 encoder.SetIndent("", " ")
99 }
100 if err := encoder.Encode(data); err != nil {
Jonathan Hartf86817b2018-08-17 10:35:54 -0700101 return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
102 }
Matteo Scandolo1f49bf52018-11-20 13:56:45 -0800103
104 return b.Bytes(), nil
Jonathan Hartf86817b2018-08-17 10:35:54 -0700105}