...
1 package log
2
3 import (
4 "encoding"
5 "encoding/json"
6 "fmt"
7 "io"
8 "reflect"
9 )
10
11 type jsonLogger struct {
12 io.Writer
13 }
14
15
16
17
18
19 func NewJSONLogger(w io.Writer) Logger {
20 return &jsonLogger{w}
21 }
22
23 func (l *jsonLogger) Log(keyvals ...interface{}) error {
24 n := (len(keyvals) + 1) / 2
25 m := make(map[string]interface{}, n)
26 for i := 0; i < len(keyvals); i += 2 {
27 k := keyvals[i]
28 var v interface{} = ErrMissingValue
29 if i+1 < len(keyvals) {
30 v = keyvals[i+1]
31 }
32 merge(m, k, v)
33 }
34 enc := json.NewEncoder(l.Writer)
35 enc.SetEscapeHTML(false)
36 return enc.Encode(m)
37 }
38
39 func merge(dst map[string]interface{}, k, v interface{}) {
40 var key string
41 switch x := k.(type) {
42 case string:
43 key = x
44 case fmt.Stringer:
45 key = safeString(x)
46 default:
47 key = fmt.Sprint(x)
48 }
49
50
51
52
53 switch x := v.(type) {
54 case json.Marshaler:
55 case encoding.TextMarshaler:
56 case error:
57 v = safeError(x)
58 case fmt.Stringer:
59 v = safeString(x)
60 }
61
62 dst[key] = v
63 }
64
65 func safeString(str fmt.Stringer) (s string) {
66 defer func() {
67 if panicVal := recover(); panicVal != nil {
68 if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() {
69 s = "NULL"
70 } else {
71 s = fmt.Sprintf("PANIC in String method: %v", panicVal)
72 }
73 }
74 }()
75 s = str.String()
76 return
77 }
78
79 func safeError(err error) (s interface{}) {
80 defer func() {
81 if panicVal := recover(); panicVal != nil {
82 if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() {
83 s = nil
84 } else {
85 s = fmt.Sprintf("PANIC in Error method: %v", panicVal)
86 }
87 }
88 }()
89 s = err.Error()
90 return
91 }
92
View as plain text