diff --git a/benchmark_test.go b/benchmark_test.go index 84e73705..7fc93e2d 100644 --- a/benchmark_test.go +++ b/benchmark_test.go @@ -3,6 +3,7 @@ package zerolog import ( "errors" "io/ioutil" + "net" "testing" "time" ) @@ -240,6 +241,7 @@ func BenchmarkContextFieldType(b *testing.B) { ints := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} floats := []float64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} strings := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"} + stringer := net.IP{127, 0, 0, 1} durations := []time.Duration{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} times := []time.Time{ time.Unix(0, 0), @@ -307,6 +309,9 @@ func BenchmarkContextFieldType(b *testing.B) { "Strs": func(c Context) Context { return c.Strs("k", strings) }, + "Stringer": func(c Context) Context { + return c.Stringer("k", stringer) + }, "Err": func(c Context) Context { return c.Err(errs[0]) }, diff --git a/context.go b/context.go index 27f0d9a1..08c62fdc 100644 --- a/context.go +++ b/context.go @@ -1,6 +1,7 @@ package zerolog import ( + "fmt" "io/ioutil" "math" "net" @@ -81,6 +82,17 @@ func (c Context) Strs(key string, vals []string) Context { return c } +// Stringer adds the field key with val.String() (or null if val is nil) to the logger context. +func (c Context) Stringer(key string, val fmt.Stringer) Context { + if val != nil { + c.l.context = enc.AppendString(enc.AppendKey(c.l.context, key), val.String()) + return c + } + + c.l.context = enc.AppendInterface(enc.AppendKey(c.l.context, key), nil) + return c +} + // Bytes adds the field key with val as a []byte to the logger context. func (c Context) Bytes(key string, val []byte) Context { c.l.context = enc.AppendBytes(enc.AppendKey(c.l.context, key), val) diff --git a/log_test.go b/log_test.go index 4a4740c5..2129bb9d 100644 --- a/log_test.go +++ b/log_test.go @@ -81,6 +81,8 @@ func TestWith(t *testing.T) { out := &bytes.Buffer{} ctx := New(out).With(). Str("string", "foo"). + Stringer("stringer", net.IP{127, 0, 0, 1}). + Stringer("stringer_nil", nil). Bytes("bytes", []byte("bar")). Hex("hex", []byte{0x12, 0xef}). RawJSON("json", []byte(`{"some":"json"}`)). @@ -104,7 +106,7 @@ func TestWith(t *testing.T) { caller := fmt.Sprintf("%s:%d", file, line+3) log := ctx.Caller().Logger() log.Log().Msg("") - if got, want := decodeIfBinaryToString(out.Bytes()), `{"string":"foo","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 { + 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 { t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want) } @@ -118,7 +120,7 @@ func TestWith(t *testing.T) { }() // The above line is a little contrived, but the line above should be the line due // to the extra frame skip. - if got, want := decodeIfBinaryToString(out.Bytes()), `{"string":"foo","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 { + 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 { t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want) } }