Codebase list golang-github-go-kit-kit / 37e3bc0
Append ErrMissingValue to odd length keyvals rather than panic. Chris Hines 8 years ago
4 changed file(s) with 78 addition(s) and 22 deletion(s). Raw diff Collapse all Expand all
1616 }
1717
1818 func (l *jsonLogger) Log(keyvals ...interface{}) error {
19 if len(keyvals)%2 == 1 {
20 panic("odd number of keyvals")
21 }
22 m := make(map[string]interface{}, len(keyvals)/2)
19 n := (len(keyvals) + 1) / 2 // +1 to handle case when len is odd
20 m := make(map[string]interface{}, n)
2321 for i := 0; i < len(keyvals); i += 2 {
24 merge(m, keyvals[i], keyvals[i+1])
22 k := keyvals[i]
23 v := ErrMissingValue
24 if i+1 < len(keyvals) {
25 v = keyvals[i+1]
26 }
27 merge(m, k, v)
2528 }
2629 return json.NewEncoder(l.Writer).Encode(m)
2730 }
99 )
1010
1111 func TestJSONLogger(t *testing.T) {
12 t.Parallel()
1213 buf := &bytes.Buffer{}
1314 logger := log.NewJSONLogger(buf)
1415 if err := logger.Log("err", errors.New("err"), "m", map[string]int{"0": 0}, "a", []int{1, 2, 3}); err != nil {
1516 t.Fatal(err)
1617 }
1718 if want, have := `{"a":[1,2,3],"err":"err","m":{"0":0}}`+"\n", buf.String(); want != have {
18 t.Errorf("want %#v, have %#v", want, have)
19 t.Errorf("\nwant %#v\nhave %#v", want, have)
20 }
21 }
22
23 func TestJSONLoggerMissingValue(t *testing.T) {
24 t.Parallel()
25 buf := &bytes.Buffer{}
26 logger := log.NewJSONLogger(buf)
27 if err := logger.Log("k"); err != nil {
28 t.Fatal(err)
29 }
30 if want, have := `{"k":"(MISSING)"}`+"\n", buf.String(); want != have {
31 t.Errorf("\nwant %#v\nhave %#v", want, have)
1932 }
2033 }
2134
33 // key/value data.
44 package log
55
6 import "sync/atomic"
6 import (
7 "errors"
8 "sync/atomic"
9 )
710
811 // Logger is the fundamental interface for all log operations. Log creates a
912 // log event from keyvals, a variadic sequence of alternating keys and values.
1316 type Logger interface {
1417 Log(keyvals ...interface{}) error
1518 }
19
20 // ErrMissingValue may be appended to keyval slices with an odd length to
21 // populate the missing value.
22 var ErrMissingValue interface{} = errors.New("(MISSING)")
1623
1724 // NewContext returns a new Context that logs to logger.
1825 func NewContext(logger Logger) Context {
3643 // stored context with their generated value, appends keyvals, and passes the
3744 // result to the wrapped Logger.
3845 func (l Context) Log(keyvals ...interface{}) error {
39 if len(keyvals)%2 != 0 {
40 panic("bad keyvals")
46 kvs := append(l.keyvals, keyvals...)
47 if len(kvs)%2 != 0 {
48 kvs = append(kvs, ErrMissingValue)
4149 }
42 kvs := append(l.keyvals, keyvals...)
4350 if l.hasValuer {
4451 // If no keyvals were appended above then we must copy l.keyvals so
4552 // that future log events will reevaluate the stored Valuers.
5663 if len(keyvals) == 0 {
5764 return l
5865 }
59 if len(keyvals)%2 != 0 {
60 panic("bad keyvals")
66 kvs := append(l.keyvals, keyvals...)
67 if len(kvs)%2 != 0 {
68 kvs = append(kvs, ErrMissingValue)
6169 }
62 // Limiting the capacity of the stored keyvals ensures that a new
63 // backing array is created if the slice must grow in Log or With.
64 // Using the extra capacity without copying risks a data race that
65 // would violate the Logger interface contract.
66 n := len(l.keyvals) + len(keyvals)
6770 return Context{
68 logger: l.logger,
69 keyvals: append(l.keyvals, keyvals...)[:n:n],
71 logger: l.logger,
72 // Limiting the capacity of the stored keyvals ensures that a new
73 // backing array is created if the slice must grow in Log or With.
74 // Using the extra capacity without copying risks a data race that
75 // would violate the Logger interface contract.
76 keyvals: kvs[:len(kvs):len(kvs)],
7077 hasValuer: l.hasValuer || containsValuer(keyvals),
7178 }
7279 }
7784 if len(keyvals) == 0 {
7885 return l
7986 }
80 if len(keyvals)%2 != 0 {
81 panic("bad keyvals")
82 }
8387 // Limiting the capacity of the stored keyvals ensures that a new
8488 // backing array is created if the slice must grow in Log or With.
8589 // Using the extra capacity without copying risks a data race that
8690 // would violate the Logger interface contract.
8791 n := len(l.keyvals) + len(keyvals)
92 if len(keyvals)%2 != 0 {
93 n++
94 }
8895 kvs := make([]interface{}, 0, n)
8996 kvs = append(kvs, keyvals...)
97 if len(kvs)%2 != 0 {
98 kvs = append(kvs, ErrMissingValue)
99 }
90100 kvs = append(kvs, l.keyvals...)
91101 return Context{
92102 logger: l.logger,
1010 var discard = log.Logger(log.LoggerFunc(func(...interface{}) error { return nil }))
1111
1212 func TestContext(t *testing.T) {
13 t.Parallel()
1314 buf := &bytes.Buffer{}
1415 logger := log.NewLogfmtLogger(buf)
1516
3233 }
3334 if want, have := "p=first a=123 b=c msg=message\n", buf.String(); want != have {
3435 t.Errorf("\nwant: %shave: %s", want, have)
36 }
37 }
38
39 func TestContextMissingValue(t *testing.T) {
40 t.Parallel()
41 var output []interface{}
42 logger := log.Logger(log.LoggerFunc(func(keyvals ...interface{}) error {
43 output = keyvals
44 return nil
45 }))
46
47 lc := log.NewContext(logger)
48
49 lc.Log("k")
50 if want, have := 2, len(output); want != have {
51 t.Errorf("want len(output) == %v, have %v", want, have)
52 }
53 if want, have := log.ErrMissingValue, output[1]; want != have {
54 t.Errorf("want %#v, have %#v", want, have)
55 }
56
57 lc.With("k1").WithPrefix("k0").Log("k2")
58 if want, have := 6, len(output); want != have {
59 t.Errorf("want len(output) == %v, have %v", want, have)
60 }
61 for i := 1; i < 6; i += 2 {
62 if want, have := log.ErrMissingValue, output[i]; want != have {
63 t.Errorf("want output[%d] == %#v, have %#v", i, want, have)
64 }
3565 }
3666 }
3767