-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjson_log_sink.go
139 lines (117 loc) · 3.97 KB
/
json_log_sink.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package simplelogr
import (
"encoding/json"
"io"
"os"
"time"
"github.com/pkg/errors"
)
// JSONLogSink emits structured JSON representations of log Entry objects
type JSONLogSink struct {
options JSONLogSinkOptions
}
// NewJSONLogSink creates a new JSONLogSink with the provided options
func NewJSONLogSink(options JSONLogSinkOptions) *JSONLogSink {
return &JSONLogSink{
options: options,
}
}
// Log implements LogSink, encoding the given Entry as JSON before writing it to the configured io.Writer
func (j JSONLogSink) Log(e Entry) error {
obj := map[string]interface{}{}
if j.options.TimestampKey != "" {
obj[j.options.TimestampKey] = j.options.TimestampEncoder(e.Timestamp)
}
if j.options.SeverityKey != "" {
obj[j.options.SeverityKey] = j.options.SeverityEncoder(e.Level, e.Error)
}
if len(e.Names) > 0 && j.options.NameKey != "" {
obj[j.options.NameKey] = j.options.NameEncoder(e.Names)
}
if e.Message != "" && j.options.MessageKey != "" {
obj[j.options.MessageKey] = e.Message
}
if e.Error != nil && (j.options.ErrorKey != "" || j.options.StackTraceKey != "") {
encodedErr := j.options.ErrorEncoder(e.Error)
if j.options.ErrorKey != "" && encodedErr.Message != "" {
obj[j.options.ErrorKey] = encodedErr.Message
}
if j.options.StackTraceKey != "" && encodedErr.StackTrace != "" {
obj[j.options.StackTraceKey] = encodedErr.StackTrace
}
}
for i := 0; i < len(e.KVs); i += 2 {
k := e.KVs[i]
v := e.KVs[i+1]
kStr, ok := k.(string)
if !ok {
return errors.Errorf("logging keys must be strings, got %T: %v", k, k)
}
obj[kStr] = v
}
if err := json.NewEncoder(j.options.Output).Encode(obj); err != nil {
return errors.Wrap(err, "failed to encode log entry as JSON")
}
return nil
}
// JSONLogSinkOptions configures the behaviour of a JSONLogSink
type JSONLogSinkOptions struct {
// Output configures where to write structured JSON logs to
Output io.Writer
// SeverityKey determines the top level JSON object key to store the log severity name in
SeverityKey string
// SeverityEncoder identifies the severity name based on the verbosity level and the presence of any errors
SeverityEncoder func(level int, err error) string
// NameKey determines the top level JSON object key to store the logger name in
NameKey string
// NameEncoder collapses the series of Logger names down into one string for logging
NameEncoder func(names []string) string
// MessageKey determines the top level JSON object key to store the log message in
MessageKey string
// TimestampKey determines the top level JSON object key to store the timestamp in
TimestampKey string
// TimestampEncoder formats timestamps into string representations
TimestampEncoder func(t time.Time) string
// ErrorKey determines the top level JSON object key to store any error messages in
ErrorKey string
// StackTraceKey determines the top level JSON object key to store any stack trace information in
StackTraceKey string
// ErrorEncoder extracts loggable EncodedError information from an error
ErrorEncoder func(err error) EncodedError
}
// AssertDefaults replaces all uninitialised options with reasonable defaults
func (j *JSONLogSinkOptions) AssertDefaults() {
if j.Output == nil {
j.Output = os.Stderr
}
if j.SeverityKey == "" {
j.SeverityKey = DefaultSeverityKey
}
if j.SeverityEncoder == nil {
j.SeverityEncoder = DefaultSeverityEncoder(DefaultSeverity, DefaultErrorSeverity, DefaultSeverityThresholds)
}
if j.NameKey == "" {
j.NameKey = DefaultNameKey
}
if j.NameEncoder == nil {
j.NameEncoder = DefaultNameEncoder(DefaultNameSeparator)
}
if j.MessageKey == "" {
j.MessageKey = DefaultMessageKey
}
if j.TimestampKey == "" {
j.TimestampKey = DefaultTimestampKey
}
if j.TimestampEncoder == nil {
j.TimestampEncoder = DefaultTimestampEncoder(DefaultTimestampFormat)
}
if j.ErrorKey == "" {
j.ErrorKey = DefaultErrorKey
}
if j.StackTraceKey == "" {
j.StackTraceKey = DefaultStackTraceKey
}
if j.ErrorEncoder == nil {
j.ErrorEncoder = DefaultErrorEncoder
}
}