11 type jsonLogger struct {
15 // NewJSONLogger returns a Logger that encodes keyvals to the Writer as a
16 // single JSON object. Each log event produces no more than one call to
17 // w.Write. The passed Writer must be safe for concurrent use by multiple
18 // goroutines if the returned Logger will be used concurrently.
19 func NewJSONLogger(w io.Writer) Logger {
23 func (l *jsonLogger) Log(keyvals ...interface{}) error {
24 n := (len(keyvals) + 1) / 2 // +1 to handle case when len is odd
25 m := make(map[string]interface{}, n)
26 for i := 0; i < len(keyvals); i += 2 {
28 var v interface{} = ErrMissingValue
29 if i+1 < len(keyvals) {
34 return json.NewEncoder(l.Writer).Encode(m)
37 func merge(dst map[string]interface{}, k, v interface{}) {
39 switch x := k.(type) {
48 // We want json.Marshaler and encoding.TextMarshaller to take priority over
49 // err.Error() and v.String(). But json.Marshall (called later) does that by
50 // default so we force a no-op if it's one of those 2 case.
51 switch x := v.(type) {
53 case encoding.TextMarshaler:
63 func safeString(str fmt.Stringer) (s string) {
65 if panicVal := recover(); panicVal != nil {
66 if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() {
77 func safeError(err error) (s interface{}) {
79 if panicVal := recover(); panicVal != nil {
80 if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() {