1 package log_test
2
3 import (
4 "bytes"
5 "errors"
6 "io/ioutil"
7 "testing"
8
9 "github.com/go-kit/log"
10 )
11
12 func TestJSONLoggerCaller(t *testing.T) {
13 t.Parallel()
14 buf := &bytes.Buffer{}
15 logger := log.NewJSONLogger(buf)
16 logger = log.With(logger, "caller", log.DefaultCaller)
17
18 if err := logger.Log(); err != nil {
19 t.Fatal(err)
20 }
21 if want, have := `{"caller":"json_logger_test.go:18"}`+"\n", buf.String(); want != have {
22 t.Errorf("\nwant %#v\nhave %#v", want, have)
23 }
24 }
25
26 func TestJSONLogger(t *testing.T) {
27 t.Parallel()
28 buf := &bytes.Buffer{}
29 logger := log.NewJSONLogger(buf)
30 if err := logger.Log("err", errors.New("err"), "m", map[string]int{"0": 0}, "a", []int{1, 2, 3}); err != nil {
31 t.Fatal(err)
32 }
33 if want, have := `{"a":[1,2,3],"err":"err","m":{"0":0}}`+"\n", buf.String(); want != have {
34 t.Errorf("\nwant %#v\nhave %#v", want, have)
35 }
36 }
37
38 func TestJSONLoggerMissingValue(t *testing.T) {
39 t.Parallel()
40 buf := &bytes.Buffer{}
41 logger := log.NewJSONLogger(buf)
42 if err := logger.Log("k"); err != nil {
43 t.Fatal(err)
44 }
45 if want, have := `{"k":"(MISSING)"}`+"\n", buf.String(); want != have {
46 t.Errorf("\nwant %#v\nhave %#v", want, have)
47 }
48 }
49
50 func TestJSONLoggerNilStringerKey(t *testing.T) {
51 t.Parallel()
52
53 buf := &bytes.Buffer{}
54 logger := log.NewJSONLogger(buf)
55 if err := logger.Log((*stringer)(nil), "v"); err != nil {
56 t.Fatal(err)
57 }
58 if want, have := `{"NULL":"v"}`+"\n", buf.String(); want != have {
59 t.Errorf("\nwant %#v\nhave %#v", want, have)
60 }
61 }
62
63 func TestJSONLoggerPanicStringerValue(t *testing.T) {
64 t.Parallel()
65
66 buf := &bytes.Buffer{}
67 logger := log.NewJSONLogger(buf)
68 if err := logger.Log("k", unsafeStringer{}); err != nil {
69 t.Fatal(err)
70 }
71 if want, have := `{"k":"PANIC in String method: error"}`+"\n", buf.String(); want != have {
72 t.Errorf("\nwant %#v\nhave %#v", want, have)
73 }
74 }
75
76 func TestJSONLoggerNilErrorValue(t *testing.T) {
77 t.Parallel()
78
79 buf := &bytes.Buffer{}
80 logger := log.NewJSONLogger(buf)
81 if err := logger.Log("err", (*stringError)(nil)); err != nil {
82 t.Fatal(err)
83 }
84 if want, have := `{"err":null}`+"\n", buf.String(); want != have {
85 t.Errorf("\nwant %#v\nhave %#v", want, have)
86 }
87 }
88
89 func TestJSONLoggerPanicErrorValue(t *testing.T) {
90 t.Parallel()
91
92 buf := &bytes.Buffer{}
93 logger := log.NewJSONLogger(buf)
94 if err := logger.Log("err", unsafeError{}); err != nil {
95 t.Fatal(err)
96 }
97 if want, have := `{"err":"PANIC in Error method: error"}`+"\n", buf.String(); want != have {
98 t.Errorf("\nwant %#v\nhave %#v", want, have)
99 }
100 }
101
102 func TestJSONLoggerNoHTMLEscape(t *testing.T) {
103 t.Parallel()
104 buf := &bytes.Buffer{}
105 logger := log.NewJSONLogger(buf)
106 if err := logger.Log("k", "<&>"); err != nil {
107 t.Fatal(err)
108 }
109 if want, have := `{"k":"<&>"}`+"\n", buf.String(); want != have {
110 t.Errorf("\nwant %#v\nhave%#v", want, have)
111 }
112 }
113
114
115 type aller struct{}
116
117 func (aller) MarshalJSON() ([]byte, error) {
118 return []byte("\"json\""), nil
119 }
120
121 func (aller) MarshalText() ([]byte, error) {
122 return []byte("text"), nil
123 }
124
125 func (aller) String() string {
126 return "string"
127 }
128
129 func (aller) Error() string {
130 return "error"
131 }
132
133
134 type textstringer struct{}
135
136 func (textstringer) MarshalText() ([]byte, error) {
137 return []byte("text"), nil
138 }
139
140 func (textstringer) String() string {
141 return "string"
142 }
143
144 func TestJSONLoggerStringValue(t *testing.T) {
145 t.Parallel()
146 tests := []struct {
147 v interface{}
148 expected string
149 }{
150 {
151 v: aller{},
152 expected: `{"v":"json"}`,
153 },
154 {
155 v: textstringer{},
156 expected: `{"v":"text"}`,
157 },
158 {
159 v: stringer("string"),
160 expected: `{"v":"string"}`,
161 },
162 }
163
164 for _, test := range tests {
165 buf := &bytes.Buffer{}
166 logger := log.NewJSONLogger(buf)
167 if err := logger.Log("v", test.v); err != nil {
168 t.Fatal(err)
169 }
170
171 if want, have := test.expected+"\n", buf.String(); want != have {
172 t.Errorf("\nwant %#v\nhave %#v", want, have)
173 }
174 }
175 }
176
177 type stringer string
178
179 func (s stringer) String() string {
180 return string(s)
181 }
182
183 type stringError string
184
185 func (s stringError) Error() string {
186 return string(s)
187 }
188
189 type unsafeStringer struct{}
190
191 func (s unsafeStringer) String() string {
192 panic("error")
193 }
194
195 type unsafeError struct{}
196
197 func (s unsafeError) Error() string {
198 panic("error")
199 }
200
201 func BenchmarkJSONLoggerSimple(b *testing.B) {
202 benchmarkRunner(b, log.NewJSONLogger(ioutil.Discard), baseMessage)
203 }
204
205 func BenchmarkJSONLoggerContextual(b *testing.B) {
206 benchmarkRunner(b, log.NewJSONLogger(ioutil.Discard), withMessage)
207 }
208
209 func TestJSONLoggerConcurrency(t *testing.T) {
210 t.Parallel()
211 testConcurrency(t, log.NewJSONLogger(ioutil.Discard), 10000)
212 }
213
View as plain text