diff --git a/log/log.go b/log/log.go index 5cf1b9abd..345d9f599 100644 --- a/log/log.go +++ b/log/log.go @@ -20,18 +20,11 @@ type Logger interface { // If logger implements the Wither interface, the result of // logger.With(keyvals...) is returned. func With(logger Logger, keyvals ...interface{}) Logger { - if w, ok := logger.(Wither); ok { - return w.With(keyvals...) - } - // Limiting the capacity of the stored keyvals ensures that a new - // backing array is created if the slice must grow in Log or With. - // Using the extra capacity without copying risks a data race that - // would violate the Logger interface contract. - n := len(keyvals) - return &withLogger{ - logger: logger, - keyvals: keyvals[:n:n], + w, ok := logger.(Wither) + if !ok { + w = &withLogger{logger: logger} } + return w.With(keyvals...) } type withLogger struct { @@ -44,6 +37,10 @@ func (l *withLogger) Log(keyvals ...interface{}) error { } func (l *withLogger) With(keyvals ...interface{}) Logger { + // Limiting the capacity of the stored keyvals ensures that a new + // backing array is created if the slice must grow in Log or With. + // Using the extra capacity without copying risks a data race that + // would violate the Logger interface contract. n := len(l.keyvals) + len(keyvals) return &withLogger{ logger: l.logger, diff --git a/log/log_test.go b/log/log_test.go index 837a6f4de..de6c19876 100644 --- a/log/log_test.go +++ b/log/log_test.go @@ -10,14 +10,16 @@ import ( func TestWith(t *testing.T) { buf := &bytes.Buffer{} + kvs := []interface{}{"a", 123} logger := log.NewJSONLogger(buf) - logger = log.With(logger, "a", 123) + logger = log.With(logger, kvs...) + kvs[1] = 0 // With should copy its key values logger = log.With(logger, "b", "c") // With should stack if err := logger.Log("msg", "message"); err != nil { t.Fatal(err) } if want, have := `{"a":123,"b":"c","msg":"message"}`+"\n", buf.String(); want != have { - t.Errorf("want\n\t%#v, have\n\t%#v", want, have) + t.Errorf("\nwant: %s\nhave: %s", want, have) } }