1 package zerolog
2
3 import (
4 "bytes"
5 "errors"
6 "fmt"
7 "net"
8 "reflect"
9 "runtime"
10 "strconv"
11 "strings"
12 "testing"
13 "time"
14 )
15
16 func TestLog(t *testing.T) {
17 t.Run("empty", func(t *testing.T) {
18 out := &bytes.Buffer{}
19 log := New(out)
20 log.Log().Msg("")
21 if got, want := decodeIfBinaryToString(out.Bytes()), "{}\n"; got != want {
22 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
23 }
24 })
25
26 t.Run("one-field", func(t *testing.T) {
27 out := &bytes.Buffer{}
28 log := New(out)
29 log.Log().Str("foo", "bar").Msg("")
30 if got, want := decodeIfBinaryToString(out.Bytes()), `{"foo":"bar"}`+"\n"; got != want {
31 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
32 }
33 })
34
35 t.Run("two-field", func(t *testing.T) {
36 out := &bytes.Buffer{}
37 log := New(out)
38 log.Log().
39 Str("foo", "bar").
40 Int("n", 123).
41 Msg("")
42 if got, want := decodeIfBinaryToString(out.Bytes()), `{"foo":"bar","n":123}`+"\n"; got != want {
43 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
44 }
45 })
46 }
47
48 func TestInfo(t *testing.T) {
49 t.Run("empty", func(t *testing.T) {
50 out := &bytes.Buffer{}
51 log := New(out)
52 log.Info().Msg("")
53 if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"info"}`+"\n"; got != want {
54 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
55 }
56 })
57
58 t.Run("one-field", func(t *testing.T) {
59 out := &bytes.Buffer{}
60 log := New(out)
61 log.Info().Str("foo", "bar").Msg("")
62 if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"info","foo":"bar"}`+"\n"; got != want {
63 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
64 }
65 })
66
67 t.Run("two-field", func(t *testing.T) {
68 out := &bytes.Buffer{}
69 log := New(out)
70 log.Info().
71 Str("foo", "bar").
72 Int("n", 123).
73 Msg("")
74 if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"info","foo":"bar","n":123}`+"\n"; got != want {
75 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
76 }
77 })
78 }
79
80 func TestEmptyLevelFieldName(t *testing.T) {
81 fieldName := LevelFieldName
82 LevelFieldName = ""
83
84 t.Run("empty setting", func(t *testing.T) {
85 out := &bytes.Buffer{}
86 log := New(out)
87 log.Info().
88 Str("foo", "bar").
89 Int("n", 123).
90 Msg("")
91 if got, want := decodeIfBinaryToString(out.Bytes()), `{"foo":"bar","n":123}`+"\n"; got != want {
92 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
93 }
94 })
95 LevelFieldName = fieldName
96 }
97
98 func TestWith(t *testing.T) {
99 out := &bytes.Buffer{}
100 ctx := New(out).With().
101 Str("string", "foo").
102 Stringer("stringer", net.IP{127, 0, 0, 1}).
103 Stringer("stringer_nil", nil).
104 Bytes("bytes", []byte("bar")).
105 Hex("hex", []byte{0x12, 0xef}).
106 RawJSON("json", []byte(`{"some":"json"}`)).
107 AnErr("some_err", nil).
108 Err(errors.New("some error")).
109 Bool("bool", true).
110 Int("int", 1).
111 Int8("int8", 2).
112 Int16("int16", 3).
113 Int32("int32", 4).
114 Int64("int64", 5).
115 Uint("uint", 6).
116 Uint8("uint8", 7).
117 Uint16("uint16", 8).
118 Uint32("uint32", 9).
119 Uint64("uint64", 10).
120 Float32("float32", 11.101).
121 Float64("float64", 12.30303).
122 Time("time", time.Time{})
123 _, file, line, _ := runtime.Caller(0)
124 caller := fmt.Sprintf("%s:%d", file, line+3)
125 log := ctx.Caller().Logger()
126 log.Log().Msg("")
127 if got, want := decodeIfBinaryToString(out.Bytes()), `{"string":"foo","stringer":"127.0.0.1","stringer_nil":null,"bytes":"bar","hex":"12ef","json":{"some":"json"},"error":"some error","bool":true,"int":1,"int8":2,"int16":3,"int32":4,"int64":5,"uint":6,"uint8":7,"uint16":8,"uint32":9,"uint64":10,"float32":11.101,"float64":12.30303,"time":"0001-01-01T00:00:00Z","caller":"`+caller+`"}`+"\n"; got != want {
128 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
129 }
130
131
132 out.Reset()
133 _, file, line, _ = runtime.Caller(0)
134 caller = fmt.Sprintf("%s:%d", file, line+5)
135 log = ctx.CallerWithSkipFrameCount(3).Logger()
136 func() {
137 log.Log().Msg("")
138 }()
139
140
141 if got, want := decodeIfBinaryToString(out.Bytes()), `{"string":"foo","stringer":"127.0.0.1","stringer_nil":null,"bytes":"bar","hex":"12ef","json":{"some":"json"},"error":"some error","bool":true,"int":1,"int8":2,"int16":3,"int32":4,"int64":5,"uint":6,"uint8":7,"uint16":8,"uint32":9,"uint64":10,"float32":11.101,"float64":12.30303,"time":"0001-01-01T00:00:00Z","caller":"`+caller+`"}`+"\n"; got != want {
142 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
143 }
144 }
145
146 func TestFieldsMap(t *testing.T) {
147 out := &bytes.Buffer{}
148 log := New(out)
149 log.Log().Fields(map[string]interface{}{
150 "nil": nil,
151 "string": "foo",
152 "bytes": []byte("bar"),
153 "error": errors.New("some error"),
154 "bool": true,
155 "int": int(1),
156 "int8": int8(2),
157 "int16": int16(3),
158 "int32": int32(4),
159 "int64": int64(5),
160 "uint": uint(6),
161 "uint8": uint8(7),
162 "uint16": uint16(8),
163 "uint32": uint32(9),
164 "uint64": uint64(10),
165 "float32": float32(11),
166 "float64": float64(12),
167 "ipv6": net.IP{0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34},
168 "dur": 1 * time.Second,
169 "time": time.Time{},
170 "obj": obj{"a", "b", 1},
171 }).Msg("")
172 if got, want := decodeIfBinaryToString(out.Bytes()), `{"bool":true,"bytes":"bar","dur":1000,"error":"some error","float32":11,"float64":12,"int":1,"int16":3,"int32":4,"int64":5,"int8":2,"ipv6":"2001:db8:85a3::8a2e:370:7334","nil":null,"obj":{"Pub":"a","Tag":"b","priv":1},"string":"foo","time":"0001-01-01T00:00:00Z","uint":6,"uint16":8,"uint32":9,"uint64":10,"uint8":7}`+"\n"; got != want {
173 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
174 }
175 }
176
177 func TestFieldsMapPnt(t *testing.T) {
178 out := &bytes.Buffer{}
179 log := New(out)
180 log.Log().Fields(map[string]interface{}{
181 "string": new(string),
182 "bool": new(bool),
183 "int": new(int),
184 "int8": new(int8),
185 "int16": new(int16),
186 "int32": new(int32),
187 "int64": new(int64),
188 "uint": new(uint),
189 "uint8": new(uint8),
190 "uint16": new(uint16),
191 "uint32": new(uint32),
192 "uint64": new(uint64),
193 "float32": new(float32),
194 "float64": new(float64),
195 "dur": new(time.Duration),
196 "time": new(time.Time),
197 }).Msg("")
198 if got, want := decodeIfBinaryToString(out.Bytes()), `{"bool":false,"dur":0,"float32":0,"float64":0,"int":0,"int16":0,"int32":0,"int64":0,"int8":0,"string":"","time":"0001-01-01T00:00:00Z","uint":0,"uint16":0,"uint32":0,"uint64":0,"uint8":0}`+"\n"; got != want {
199 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
200 }
201 }
202
203 func TestFieldsMapNilPnt(t *testing.T) {
204 var (
205 stringPnt *string
206 boolPnt *bool
207 intPnt *int
208 int8Pnt *int8
209 int16Pnt *int16
210 int32Pnt *int32
211 int64Pnt *int64
212 uintPnt *uint
213 uint8Pnt *uint8
214 uint16Pnt *uint16
215 uint32Pnt *uint32
216 uint64Pnt *uint64
217 float32Pnt *float32
218 float64Pnt *float64
219 durPnt *time.Duration
220 timePnt *time.Time
221 )
222 out := &bytes.Buffer{}
223 log := New(out)
224 fields := map[string]interface{}{
225 "string": stringPnt,
226 "bool": boolPnt,
227 "int": intPnt,
228 "int8": int8Pnt,
229 "int16": int16Pnt,
230 "int32": int32Pnt,
231 "int64": int64Pnt,
232 "uint": uintPnt,
233 "uint8": uint8Pnt,
234 "uint16": uint16Pnt,
235 "uint32": uint32Pnt,
236 "uint64": uint64Pnt,
237 "float32": float32Pnt,
238 "float64": float64Pnt,
239 "dur": durPnt,
240 "time": timePnt,
241 }
242
243 log.Log().Fields(fields).Msg("")
244 if got, want := decodeIfBinaryToString(out.Bytes()), `{"bool":null,"dur":null,"float32":null,"float64":null,"int":null,"int16":null,"int32":null,"int64":null,"int8":null,"string":null,"time":null,"uint":null,"uint16":null,"uint32":null,"uint64":null,"uint8":null}`+"\n"; got != want {
245 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
246 }
247 }
248
249 func TestFieldsSlice(t *testing.T) {
250 out := &bytes.Buffer{}
251 log := New(out)
252 log.Log().Fields([]interface{}{
253 "nil", nil,
254 "string", "foo",
255 "bytes", []byte("bar"),
256 "error", errors.New("some error"),
257 "bool", true,
258 "int", int(1),
259 "int8", int8(2),
260 "int16", int16(3),
261 "int32", int32(4),
262 "int64", int64(5),
263 "uint", uint(6),
264 "uint8", uint8(7),
265 "uint16", uint16(8),
266 "uint32", uint32(9),
267 "uint64", uint64(10),
268 "float32", float32(11),
269 "float64", float64(12),
270 "ipv6", net.IP{0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34},
271 "dur", 1 * time.Second,
272 "time", time.Time{},
273 "obj", obj{"a", "b", 1},
274 }).Msg("")
275 if got, want := decodeIfBinaryToString(out.Bytes()), `{"nil":null,"string":"foo","bytes":"bar","error":"some error","bool":true,"int":1,"int8":2,"int16":3,"int32":4,"int64":5,"uint":6,"uint8":7,"uint16":8,"uint32":9,"uint64":10,"float32":11,"float64":12,"ipv6":"2001:db8:85a3::8a2e:370:7334","dur":1000,"time":"0001-01-01T00:00:00Z","obj":{"Pub":"a","Tag":"b","priv":1}}`+"\n"; got != want {
276 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
277 }
278 }
279
280 func TestFieldsSliceExtraneous(t *testing.T) {
281 out := &bytes.Buffer{}
282 log := New(out)
283 log.Log().Fields([]interface{}{
284 "string", "foo",
285 "error", errors.New("some error"),
286 32, "valueForNonStringKey",
287 "bool", true,
288 "int", int(1),
289 "keyWithoutValue",
290 }).Msg("")
291 if got, want := decodeIfBinaryToString(out.Bytes()), `{"string":"foo","error":"some error","bool":true,"int":1}`+"\n"; got != want {
292 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
293 }
294 }
295
296 func TestFieldsNotMapSlice(t *testing.T) {
297 out := &bytes.Buffer{}
298 log := New(out)
299 log.Log().
300 Fields(obj{"a", "b", 1}).
301 Fields("string").
302 Fields(1).
303 Msg("")
304 if got, want := decodeIfBinaryToString(out.Bytes()), `{}`+"\n"; got != want {
305 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
306 }
307 }
308
309 func TestFields(t *testing.T) {
310 out := &bytes.Buffer{}
311 log := New(out)
312 now := time.Now()
313 _, file, line, _ := runtime.Caller(0)
314 caller := fmt.Sprintf("%s:%d", file, line+3)
315 log.Log().
316 Caller().
317 Str("string", "foo").
318 Stringer("stringer", net.IP{127, 0, 0, 1}).
319 Stringer("stringer_nil", nil).
320 Bytes("bytes", []byte("bar")).
321 Hex("hex", []byte{0x12, 0xef}).
322 RawJSON("json", []byte(`{"some":"json"}`)).
323 Func(func(e *Event) { e.Str("func", "func_output") }).
324 AnErr("some_err", nil).
325 Err(errors.New("some error")).
326 Bool("bool", true).
327 Int("int", 1).
328 Int8("int8", 2).
329 Int16("int16", 3).
330 Int32("int32", 4).
331 Int64("int64", 5).
332 Uint("uint", 6).
333 Uint8("uint8", 7).
334 Uint16("uint16", 8).
335 Uint32("uint32", 9).
336 Uint64("uint64", 10).
337 IPAddr("IPv4", net.IP{192, 168, 0, 100}).
338 IPAddr("IPv6", net.IP{0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34}).
339 MACAddr("Mac", net.HardwareAddr{0x00, 0x14, 0x22, 0x01, 0x23, 0x45}).
340 IPPrefix("Prefix", net.IPNet{IP: net.IP{192, 168, 0, 100}, Mask: net.CIDRMask(24, 32)}).
341 Float32("float32", 11.1234).
342 Float64("float64", 12.321321321).
343 Dur("dur", 1*time.Second).
344 Time("time", time.Time{}).
345 TimeDiff("diff", now, now.Add(-10*time.Second)).
346 Msg("")
347 if got, want := decodeIfBinaryToString(out.Bytes()), `{"caller":"`+caller+`","string":"foo","stringer":"127.0.0.1","stringer_nil":null,"bytes":"bar","hex":"12ef","json":{"some":"json"},"func":"func_output","error":"some error","bool":true,"int":1,"int8":2,"int16":3,"int32":4,"int64":5,"uint":6,"uint8":7,"uint16":8,"uint32":9,"uint64":10,"IPv4":"192.168.0.100","IPv6":"2001:db8:85a3::8a2e:370:7334","Mac":"00:14:22:01:23:45","Prefix":"192.168.0.100/24","float32":11.1234,"float64":12.321321321,"dur":1000,"time":"0001-01-01T00:00:00Z","diff":10000}`+"\n"; got != want {
348 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
349 }
350 }
351
352 func TestFieldsArrayEmpty(t *testing.T) {
353 out := &bytes.Buffer{}
354 log := New(out)
355 log.Log().
356 Strs("string", []string{}).
357 Stringers("stringer", []fmt.Stringer{}).
358 Errs("err", []error{}).
359 Bools("bool", []bool{}).
360 Ints("int", []int{}).
361 Ints8("int8", []int8{}).
362 Ints16("int16", []int16{}).
363 Ints32("int32", []int32{}).
364 Ints64("int64", []int64{}).
365 Uints("uint", []uint{}).
366 Uints8("uint8", []uint8{}).
367 Uints16("uint16", []uint16{}).
368 Uints32("uint32", []uint32{}).
369 Uints64("uint64", []uint64{}).
370 Floats32("float32", []float32{}).
371 Floats64("float64", []float64{}).
372 Durs("dur", []time.Duration{}).
373 Times("time", []time.Time{}).
374 Msg("")
375 if got, want := decodeIfBinaryToString(out.Bytes()), `{"string":[],"stringer":[],"err":[],"bool":[],"int":[],"int8":[],"int16":[],"int32":[],"int64":[],"uint":[],"uint8":[],"uint16":[],"uint32":[],"uint64":[],"float32":[],"float64":[],"dur":[],"time":[]}`+"\n"; got != want {
376 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
377 }
378 }
379
380 func TestFieldsArraySingleElement(t *testing.T) {
381 out := &bytes.Buffer{}
382 log := New(out)
383 log.Log().
384 Strs("string", []string{"foo"}).
385 Stringers("stringer", []fmt.Stringer{net.IP{127, 0, 0, 1}}).
386 Errs("err", []error{errors.New("some error")}).
387 Bools("bool", []bool{true}).
388 Ints("int", []int{1}).
389 Ints8("int8", []int8{2}).
390 Ints16("int16", []int16{3}).
391 Ints32("int32", []int32{4}).
392 Ints64("int64", []int64{5}).
393 Uints("uint", []uint{6}).
394 Uints8("uint8", []uint8{7}).
395 Uints16("uint16", []uint16{8}).
396 Uints32("uint32", []uint32{9}).
397 Uints64("uint64", []uint64{10}).
398 Floats32("float32", []float32{11}).
399 Floats64("float64", []float64{12}).
400 Durs("dur", []time.Duration{1 * time.Second}).
401 Times("time", []time.Time{{}}).
402 Msg("")
403 if got, want := decodeIfBinaryToString(out.Bytes()), `{"string":["foo"],"stringer":["127.0.0.1"],"err":["some error"],"bool":[true],"int":[1],"int8":[2],"int16":[3],"int32":[4],"int64":[5],"uint":[6],"uint8":[7],"uint16":[8],"uint32":[9],"uint64":[10],"float32":[11],"float64":[12],"dur":[1000],"time":["0001-01-01T00:00:00Z"]}`+"\n"; got != want {
404 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
405 }
406 }
407
408 func TestFieldsArrayMultipleElement(t *testing.T) {
409 out := &bytes.Buffer{}
410 log := New(out)
411 log.Log().
412 Strs("string", []string{"foo", "bar"}).
413 Stringers("stringer", []fmt.Stringer{nil, net.IP{127, 0, 0, 1}}).
414 Errs("err", []error{errors.New("some error"), nil}).
415 Bools("bool", []bool{true, false}).
416 Ints("int", []int{1, 0}).
417 Ints8("int8", []int8{2, 0}).
418 Ints16("int16", []int16{3, 0}).
419 Ints32("int32", []int32{4, 0}).
420 Ints64("int64", []int64{5, 0}).
421 Uints("uint", []uint{6, 0}).
422 Uints8("uint8", []uint8{7, 0}).
423 Uints16("uint16", []uint16{8, 0}).
424 Uints32("uint32", []uint32{9, 0}).
425 Uints64("uint64", []uint64{10, 0}).
426 Floats32("float32", []float32{11, 0}).
427 Floats64("float64", []float64{12, 0}).
428 Durs("dur", []time.Duration{1 * time.Second, 0}).
429 Times("time", []time.Time{{}, {}}).
430 Msg("")
431 if got, want := decodeIfBinaryToString(out.Bytes()), `{"string":["foo","bar"],"stringer":[null,"127.0.0.1"],"err":["some error",null],"bool":[true,false],"int":[1,0],"int8":[2,0],"int16":[3,0],"int32":[4,0],"int64":[5,0],"uint":[6,0],"uint8":[7,0],"uint16":[8,0],"uint32":[9,0],"uint64":[10,0],"float32":[11,0],"float64":[12,0],"dur":[1000,0],"time":["0001-01-01T00:00:00Z","0001-01-01T00:00:00Z"]}`+"\n"; got != want {
432 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
433 }
434 }
435
436 func TestFieldsDisabled(t *testing.T) {
437 out := &bytes.Buffer{}
438 log := New(out).Level(InfoLevel)
439 now := time.Now()
440 log.Debug().
441 Str("string", "foo").
442 Stringer("stringer", net.IP{127, 0, 0, 1}).
443 Bytes("bytes", []byte("bar")).
444 Hex("hex", []byte{0x12, 0xef}).
445 AnErr("some_err", nil).
446 Err(errors.New("some error")).
447 Func(func(e *Event) { e.Str("func", "func_output") }).
448 Bool("bool", true).
449 Int("int", 1).
450 Int8("int8", 2).
451 Int16("int16", 3).
452 Int32("int32", 4).
453 Int64("int64", 5).
454 Uint("uint", 6).
455 Uint8("uint8", 7).
456 Uint16("uint16", 8).
457 Uint32("uint32", 9).
458 Uint64("uint64", 10).
459 Float32("float32", 11).
460 Float64("float64", 12).
461 Dur("dur", 1*time.Second).
462 Time("time", time.Time{}).
463 TimeDiff("diff", now, now.Add(-10*time.Second)).
464 Msg("")
465 if got, want := decodeIfBinaryToString(out.Bytes()), ""; got != want {
466 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
467 }
468 }
469
470 func TestMsgf(t *testing.T) {
471 out := &bytes.Buffer{}
472 log := New(out)
473 log.Log().Msgf("one %s %.1f %d %v", "two", 3.4, 5, errors.New("six"))
474 if got, want := decodeIfBinaryToString(out.Bytes()), `{"message":"one two 3.4 5 six"}`+"\n"; got != want {
475 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
476 }
477 }
478
479 func TestWithAndFieldsCombined(t *testing.T) {
480 out := &bytes.Buffer{}
481 log := New(out).With().Str("f1", "val").Str("f2", "val").Logger()
482 log.Log().Str("f3", "val").Msg("")
483 if got, want := decodeIfBinaryToString(out.Bytes()), `{"f1":"val","f2":"val","f3":"val"}`+"\n"; got != want {
484 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
485 }
486 }
487
488 func TestLevel(t *testing.T) {
489 t.Run("Disabled", func(t *testing.T) {
490 out := &bytes.Buffer{}
491 log := New(out).Level(Disabled)
492 log.Info().Msg("test")
493 if got, want := decodeIfBinaryToString(out.Bytes()), ""; got != want {
494 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
495 }
496 })
497
498 t.Run("NoLevel/Disabled", func(t *testing.T) {
499 out := &bytes.Buffer{}
500 log := New(out).Level(Disabled)
501 log.Log().Msg("test")
502 if got, want := decodeIfBinaryToString(out.Bytes()), ""; got != want {
503 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
504 }
505 })
506
507 t.Run("NoLevel/Info", func(t *testing.T) {
508 out := &bytes.Buffer{}
509 log := New(out).Level(InfoLevel)
510 log.Log().Msg("test")
511 if got, want := decodeIfBinaryToString(out.Bytes()), `{"message":"test"}`+"\n"; got != want {
512 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
513 }
514 })
515
516 t.Run("NoLevel/Panic", func(t *testing.T) {
517 out := &bytes.Buffer{}
518 log := New(out).Level(PanicLevel)
519 log.Log().Msg("test")
520 if got, want := decodeIfBinaryToString(out.Bytes()), `{"message":"test"}`+"\n"; got != want {
521 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
522 }
523 })
524
525 t.Run("NoLevel/WithLevel", func(t *testing.T) {
526 out := &bytes.Buffer{}
527 log := New(out).Level(InfoLevel)
528 log.WithLevel(NoLevel).Msg("test")
529 if got, want := decodeIfBinaryToString(out.Bytes()), `{"message":"test"}`+"\n"; got != want {
530 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
531 }
532 })
533
534 t.Run("Info", func(t *testing.T) {
535 out := &bytes.Buffer{}
536 log := New(out).Level(InfoLevel)
537 log.Info().Msg("test")
538 if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"info","message":"test"}`+"\n"; got != want {
539 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
540 }
541 })
542 }
543
544 func TestGetLevel(t *testing.T) {
545 levels := []Level{
546 DebugLevel,
547 InfoLevel,
548 WarnLevel,
549 ErrorLevel,
550 FatalLevel,
551 PanicLevel,
552 NoLevel,
553 Disabled,
554 }
555 for _, level := range levels {
556 if got, want := New(nil).Level(level).GetLevel(), level; got != want {
557 t.Errorf("GetLevel() = %v, want: %v", got, want)
558 }
559 }
560 }
561
562 func TestSampling(t *testing.T) {
563 out := &bytes.Buffer{}
564 log := New(out).Sample(&BasicSampler{N: 2})
565 log.Log().Int("i", 1).Msg("")
566 log.Log().Int("i", 2).Msg("")
567 log.Log().Int("i", 3).Msg("")
568 log.Log().Int("i", 4).Msg("")
569 if got, want := decodeIfBinaryToString(out.Bytes()), "{\"i\":1}\n{\"i\":3}\n"; got != want {
570 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
571 }
572 }
573
574 func TestDiscard(t *testing.T) {
575 out := &bytes.Buffer{}
576 log := New(out)
577 log.Log().Discard().Str("a", "b").Msgf("one %s %.1f %d %v", "two", 3.4, 5, errors.New("six"))
578 if got, want := decodeIfBinaryToString(out.Bytes()), ""; got != want {
579 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
580 }
581
582
583 log.Log().Discard().Discard().Str("a", "b").Msgf("one %s %.1f %d %v", "two", 3.4, 5, errors.New("six"))
584 if got, want := decodeIfBinaryToString(out.Bytes()), ""; got != want {
585 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
586 }
587 }
588
589 type levelWriter struct {
590 ops []struct {
591 l Level
592 p string
593 }
594 }
595
596 func (lw *levelWriter) Write(p []byte) (int, error) {
597 return len(p), nil
598 }
599
600 func (lw *levelWriter) WriteLevel(lvl Level, p []byte) (int, error) {
601 p = decodeIfBinaryToBytes(p)
602 lw.ops = append(lw.ops, struct {
603 l Level
604 p string
605 }{lvl, string(p)})
606 return len(p), nil
607 }
608
609 func TestLevelWriter(t *testing.T) {
610 lw := &levelWriter{
611 ops: []struct {
612 l Level
613 p string
614 }{},
615 }
616
617
618 SetGlobalLevel(TraceLevel - 1)
619 log := New(lw).Level(TraceLevel - 1)
620
621 log.Trace().Msg("0")
622 log.Debug().Msg("1")
623 log.Info().Msg("2")
624 log.Warn().Msg("3")
625 log.Error().Msg("4")
626 log.Log().Msg("nolevel-1")
627 log.WithLevel(TraceLevel).Msg("5")
628 log.WithLevel(DebugLevel).Msg("6")
629 log.WithLevel(InfoLevel).Msg("7")
630 log.WithLevel(WarnLevel).Msg("8")
631 log.WithLevel(ErrorLevel).Msg("9")
632 log.WithLevel(NoLevel).Msg("nolevel-2")
633 log.WithLevel(-1).Msg("-1")
634 log.WithLevel(-2).Msg("-2")
635 log.WithLevel(-3).Msg("-3")
636
637 want := []struct {
638 l Level
639 p string
640 }{
641 {TraceLevel, `{"level":"trace","message":"0"}` + "\n"},
642 {DebugLevel, `{"level":"debug","message":"1"}` + "\n"},
643 {InfoLevel, `{"level":"info","message":"2"}` + "\n"},
644 {WarnLevel, `{"level":"warn","message":"3"}` + "\n"},
645 {ErrorLevel, `{"level":"error","message":"4"}` + "\n"},
646 {NoLevel, `{"message":"nolevel-1"}` + "\n"},
647 {TraceLevel, `{"level":"trace","message":"5"}` + "\n"},
648 {DebugLevel, `{"level":"debug","message":"6"}` + "\n"},
649 {InfoLevel, `{"level":"info","message":"7"}` + "\n"},
650 {WarnLevel, `{"level":"warn","message":"8"}` + "\n"},
651 {ErrorLevel, `{"level":"error","message":"9"}` + "\n"},
652 {NoLevel, `{"message":"nolevel-2"}` + "\n"},
653 {Level(-1), `{"level":"trace","message":"-1"}` + "\n"},
654 {Level(-2), `{"level":"-2","message":"-2"}` + "\n"},
655 }
656 if got := lw.ops; !reflect.DeepEqual(got, want) {
657 t.Errorf("invalid ops:\ngot:\n%v\nwant:\n%v", got, want)
658 }
659 }
660
661 func TestContextTimestamp(t *testing.T) {
662 TimestampFunc = func() time.Time {
663 return time.Date(2001, time.February, 3, 4, 5, 6, 7, time.UTC)
664 }
665 defer func() {
666 TimestampFunc = time.Now
667 }()
668 out := &bytes.Buffer{}
669 log := New(out).With().Timestamp().Str("foo", "bar").Logger()
670 log.Log().Msg("hello world")
671
672 if got, want := decodeIfBinaryToString(out.Bytes()), `{"foo":"bar","time":"2001-02-03T04:05:06Z","message":"hello world"}`+"\n"; got != want {
673 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
674 }
675 }
676
677 func TestEventTimestamp(t *testing.T) {
678 TimestampFunc = func() time.Time {
679 return time.Date(2001, time.February, 3, 4, 5, 6, 7, time.UTC)
680 }
681 defer func() {
682 TimestampFunc = time.Now
683 }()
684 out := &bytes.Buffer{}
685 log := New(out).With().Str("foo", "bar").Logger()
686 log.Log().Timestamp().Msg("hello world")
687
688 if got, want := decodeIfBinaryToString(out.Bytes()), `{"foo":"bar","time":"2001-02-03T04:05:06Z","message":"hello world"}`+"\n"; got != want {
689 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
690 }
691 }
692
693 func TestOutputWithoutTimestamp(t *testing.T) {
694 ignoredOut := &bytes.Buffer{}
695 out := &bytes.Buffer{}
696 log := New(ignoredOut).Output(out).With().Str("foo", "bar").Logger()
697 log.Log().Msg("hello world")
698
699 if got, want := decodeIfBinaryToString(out.Bytes()), `{"foo":"bar","message":"hello world"}`+"\n"; got != want {
700 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
701 }
702 }
703
704 func TestOutputWithTimestamp(t *testing.T) {
705 TimestampFunc = func() time.Time {
706 return time.Date(2001, time.February, 3, 4, 5, 6, 7, time.UTC)
707 }
708 defer func() {
709 TimestampFunc = time.Now
710 }()
711 ignoredOut := &bytes.Buffer{}
712 out := &bytes.Buffer{}
713 log := New(ignoredOut).Output(out).With().Timestamp().Str("foo", "bar").Logger()
714 log.Log().Msg("hello world")
715
716 if got, want := decodeIfBinaryToString(out.Bytes()), `{"foo":"bar","time":"2001-02-03T04:05:06Z","message":"hello world"}`+"\n"; got != want {
717 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
718 }
719 }
720
721 type loggableError struct {
722 error
723 }
724
725 func (l loggableError) MarshalZerologObject(e *Event) {
726 e.Str("message", l.error.Error()+": loggableError")
727 }
728
729 func TestErrorMarshalFunc(t *testing.T) {
730 out := &bytes.Buffer{}
731 log := New(out)
732
733
734 log.Log().Err(errors.New("err")).Msg("msg")
735 if got, want := decodeIfBinaryToString(out.Bytes()), `{"error":"err","message":"msg"}`+"\n"; got != want {
736 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
737 }
738 out.Reset()
739
740 log.Log().Err(loggableError{errors.New("err")}).Msg("msg")
741 if got, want := decodeIfBinaryToString(out.Bytes()), `{"error":{"message":"err: loggableError"},"message":"msg"}`+"\n"; got != want {
742 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
743 }
744 out.Reset()
745
746
747 originalErrorMarshalFunc := ErrorMarshalFunc
748 defer func() {
749 ErrorMarshalFunc = originalErrorMarshalFunc
750 }()
751
752 ErrorMarshalFunc = func(err error) interface{} {
753 return err.Error() + ": marshaled string"
754 }
755 log.Log().Err(errors.New("err")).Msg("msg")
756 if got, want := decodeIfBinaryToString(out.Bytes()), `{"error":"err: marshaled string","message":"msg"}`+"\n"; got != want {
757 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
758 }
759
760 out.Reset()
761 ErrorMarshalFunc = func(err error) interface{} {
762 return errors.New(err.Error() + ": new error")
763 }
764 log.Log().Err(errors.New("err")).Msg("msg")
765 if got, want := decodeIfBinaryToString(out.Bytes()), `{"error":"err: new error","message":"msg"}`+"\n"; got != want {
766 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
767 }
768
769 out.Reset()
770 ErrorMarshalFunc = func(err error) interface{} {
771 return loggableError{err}
772 }
773 log.Log().Err(errors.New("err")).Msg("msg")
774 if got, want := decodeIfBinaryToString(out.Bytes()), `{"error":{"message":"err: loggableError"},"message":"msg"}`+"\n"; got != want {
775 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
776 }
777 }
778
779 func TestCallerMarshalFunc(t *testing.T) {
780 out := &bytes.Buffer{}
781 log := New(out)
782
783
784
785 pc, file, line, _ := runtime.Caller(0)
786 caller := fmt.Sprintf("%s:%d", file, line+2)
787 log.Log().Caller().Msg("msg")
788 if got, want := decodeIfBinaryToString(out.Bytes()), `{"caller":"`+caller+`","message":"msg"}`+"\n"; got != want {
789 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
790 }
791 out.Reset()
792
793
794 origCallerMarshalFunc := CallerMarshalFunc
795 defer func() { CallerMarshalFunc = origCallerMarshalFunc }()
796 CallerMarshalFunc = func(pc uintptr, file string, line int) string {
797 parts := strings.Split(file, "/")
798 if len(parts) > 1 {
799 return strings.Join(parts[len(parts)-2:], "/") + ":" + strconv.Itoa(line)
800 }
801
802 return runtime.FuncForPC(pc).Name() + ":" + file + ":" + strconv.Itoa(line)
803 }
804 pc, file, line, _ = runtime.Caller(0)
805 caller = CallerMarshalFunc(pc, file, line+2)
806 log.Log().Caller().Msg("msg")
807 if got, want := decodeIfBinaryToString(out.Bytes()), `{"caller":"`+caller+`","message":"msg"}`+"\n"; got != want {
808 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
809 }
810 }
811
812 func TestLevelFieldMarshalFunc(t *testing.T) {
813 origLevelFieldMarshalFunc := LevelFieldMarshalFunc
814 LevelFieldMarshalFunc = func(l Level) string {
815 return strings.ToUpper(l.String())
816 }
817 defer func() {
818 LevelFieldMarshalFunc = origLevelFieldMarshalFunc
819 }()
820 out := &bytes.Buffer{}
821 log := New(out)
822
823 log.Debug().Msg("test")
824 if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"DEBUG","message":"test"}`+"\n"; got != want {
825 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
826 }
827 out.Reset()
828
829 log.Info().Msg("test")
830 if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"INFO","message":"test"}`+"\n"; got != want {
831 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
832 }
833 out.Reset()
834
835 log.Warn().Msg("test")
836 if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"WARN","message":"test"}`+"\n"; got != want {
837 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
838 }
839 out.Reset()
840
841 log.Error().Msg("test")
842 if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"ERROR","message":"test"}`+"\n"; got != want {
843 t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
844 }
845 out.Reset()
846 }
847
848 type errWriter struct {
849 error
850 }
851
852 func (w errWriter) Write(p []byte) (n int, err error) {
853 return 0, w.error
854 }
855
856 func TestErrorHandler(t *testing.T) {
857 var got error
858 want := errors.New("write error")
859 ErrorHandler = func(err error) {
860 got = err
861 }
862 log := New(errWriter{want})
863 log.Log().Msg("test")
864 if got != want {
865 t.Errorf("ErrorHandler err = %#v, want %#v", got, want)
866 }
867 }
868
869 func TestUpdateEmptyContext(t *testing.T) {
870 var buf bytes.Buffer
871 log := New(&buf)
872
873 log.UpdateContext(func(c Context) Context {
874 return c.Str("foo", "bar")
875 })
876 log.Info().Msg("no panic")
877
878 want := `{"level":"info","foo":"bar","message":"no panic"}` + "\n"
879
880 if got := decodeIfBinaryToString(buf.Bytes()); got != want {
881 t.Errorf("invalid log output:\ngot: %q\nwant: %q", got, want)
882 }
883 }
884
885 func TestLevel_String(t *testing.T) {
886 tests := []struct {
887 name string
888 l Level
889 want string
890 }{
891 {"trace", TraceLevel, "trace"},
892 {"debug", DebugLevel, "debug"},
893 {"info", InfoLevel, "info"},
894 {"warn", WarnLevel, "warn"},
895 {"error", ErrorLevel, "error"},
896 {"fatal", FatalLevel, "fatal"},
897 {"panic", PanicLevel, "panic"},
898 {"disabled", Disabled, "disabled"},
899 {"nolevel", NoLevel, ""},
900 }
901 for _, tt := range tests {
902 t.Run(tt.name, func(t *testing.T) {
903 if got := tt.l.String(); got != tt.want {
904 t.Errorf("String() = %v, want %v", got, tt.want)
905 }
906 })
907 }
908 }
909
910 func TestLevel_MarshalText(t *testing.T) {
911 tests := []struct {
912 name string
913 l Level
914 want string
915 }{
916 {"trace", TraceLevel, "trace"},
917 {"debug", DebugLevel, "debug"},
918 {"info", InfoLevel, "info"},
919 {"warn", WarnLevel, "warn"},
920 {"error", ErrorLevel, "error"},
921 {"fatal", FatalLevel, "fatal"},
922 {"panic", PanicLevel, "panic"},
923 {"disabled", Disabled, "disabled"},
924 {"nolevel", NoLevel, ""},
925 }
926 for _, tt := range tests {
927 t.Run(tt.name, func(t *testing.T) {
928 if got, err := tt.l.MarshalText(); err != nil {
929 t.Errorf("MarshalText couldn't marshal: %v", tt.l)
930 } else if string(got) != tt.want {
931 t.Errorf("String() = %v, want %v", string(got), tt.want)
932 }
933 })
934 }
935 }
936
937 func TestParseLevel(t *testing.T) {
938 type args struct {
939 levelStr string
940 }
941 tests := []struct {
942 name string
943 args args
944 want Level
945 wantErr bool
946 }{
947 {"trace", args{"trace"}, TraceLevel, false},
948 {"debug", args{"debug"}, DebugLevel, false},
949 {"info", args{"info"}, InfoLevel, false},
950 {"warn", args{"warn"}, WarnLevel, false},
951 {"error", args{"error"}, ErrorLevel, false},
952 {"fatal", args{"fatal"}, FatalLevel, false},
953 {"panic", args{"panic"}, PanicLevel, false},
954 {"disabled", args{"disabled"}, Disabled, false},
955 {"nolevel", args{""}, NoLevel, false},
956 {"-1", args{"-1"}, TraceLevel, false},
957 {"-2", args{"-2"}, Level(-2), false},
958 {"-3", args{"-3"}, Level(-3), false},
959 }
960 for _, tt := range tests {
961 t.Run(tt.name, func(t *testing.T) {
962 got, err := ParseLevel(tt.args.levelStr)
963 if (err != nil) != tt.wantErr {
964 t.Errorf("ParseLevel() error = %v, wantErr %v", err, tt.wantErr)
965 return
966 }
967 if got != tt.want {
968 t.Errorf("ParseLevel() got = %v, want %v", got, tt.want)
969 }
970 })
971 }
972 }
973
974 func TestUnmarshalTextLevel(t *testing.T) {
975 type args struct {
976 levelStr string
977 }
978 tests := []struct {
979 name string
980 args args
981 want Level
982 wantErr bool
983 }{
984 {"trace", args{"trace"}, TraceLevel, false},
985 {"debug", args{"debug"}, DebugLevel, false},
986 {"info", args{"info"}, InfoLevel, false},
987 {"warn", args{"warn"}, WarnLevel, false},
988 {"error", args{"error"}, ErrorLevel, false},
989 {"fatal", args{"fatal"}, FatalLevel, false},
990 {"panic", args{"panic"}, PanicLevel, false},
991 {"disabled", args{"disabled"}, Disabled, false},
992 {"nolevel", args{""}, NoLevel, false},
993 {"-1", args{"-1"}, TraceLevel, false},
994 {"-2", args{"-2"}, Level(-2), false},
995 {"-3", args{"-3"}, Level(-3), false},
996 }
997 for _, tt := range tests {
998 t.Run(tt.name, func(t *testing.T) {
999 var l Level
1000 err := l.UnmarshalText([]byte(tt.args.levelStr))
1001 if (err != nil) != tt.wantErr {
1002 t.Errorf("UnmarshalText() error = %v, wantErr %v", err, tt.wantErr)
1003 return
1004 }
1005 if l != tt.want {
1006 t.Errorf("UnmarshalText() got = %v, want %v", l, tt.want)
1007 }
1008 })
1009 }
1010 }
1011
View as plain text