Skip to content

Commit

Permalink
Add utility functions WithLevel and Fields
Browse files Browse the repository at this point in the history
Add some utility functions to ease migration from other logger API.
  • Loading branch information
rs committed Jul 10, 2017
1 parent c964fc4 commit 7af6538
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 19 deletions.
6 changes: 6 additions & 0 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ func (c Context) Logger() Logger {
return c.l
}

// Fields is a helper function to use a map to set fields using type assertion.
func (c Context) Fields(fields map[string]interface{}) Context {
c.l.context = appendFields(c.l.context, fields)
return c
}

// Dict adds the field key with the dict to the logger context.
func (c Context) Dict(key string, dict *Event) Context {
dict.buf = append(dict.buf, '}')
Expand Down
9 changes: 9 additions & 0 deletions event.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,15 @@ func (e *Event) Msgf(format string, v ...interface{}) {
}
}

// Fields is a helper function to use a map to set fields using type assertion.
func (e *Event) Fields(fields map[string]interface{}) *Event {
if !e.enabled {
return e
}
e.buf = appendFields(e.buf, fields)
return e
}

// Dict adds the field key with a dict to the event context.
// Use zerolog.Dict() to create the dictionary.
func (e *Event) Dict(key string, dict *Event) *Event {
Expand Down
54 changes: 54 additions & 0 deletions field.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,64 @@ package zerolog
import (
"encoding/json"
"fmt"
"sort"
"strconv"
"time"
)

func appendFields(dst []byte, fields map[string]interface{}) []byte {
keys := make([]string, 0, len(fields))
for key, _ := range fields {
keys = append(keys, key)
}
sort.Strings(keys)
for _, key := range keys {
switch val := fields[key].(type) {
case string:
dst = appendString(dst, key, val)
case []byte:
dst = appendBytes(dst, key, val)
case error:
dst = appendErrorKey(dst, key, val)
case bool:
dst = appendBool(dst, key, val)
case int:
dst = appendInt(dst, key, val)
case int8:
dst = appendInt8(dst, key, val)
case int16:
dst = appendInt16(dst, key, val)
case int32:
dst = appendInt32(dst, key, val)
case int64:
dst = appendInt64(dst, key, val)
case uint:
dst = appendUint(dst, key, val)
case uint8:
dst = appendUint8(dst, key, val)
case uint16:
dst = appendUint16(dst, key, val)
case uint32:
dst = appendUint32(dst, key, val)
case uint64:
dst = appendUint64(dst, key, val)
case float32:
dst = appendFloat32(dst, key, val)
case float64:
dst = appendFloat64(dst, key, val)
case time.Time:
dst = appendTime(dst, key, val)
case time.Duration:
dst = appendDuration(dst, key, val)
case nil:
dst = append(appendKey(dst, key), "null"...)
default:
dst = appendInterface(dst, key, val)
}
}
return dst
}

func appendKey(dst []byte, key string) []byte {
if len(dst) > 1 {
dst = append(dst, ',')
Expand Down
25 changes: 25 additions & 0 deletions log.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ import (
"io"
"io/ioutil"
"os"
"strconv"
"sync/atomic"
)

Expand Down Expand Up @@ -246,6 +247,30 @@ func (l Logger) Panic() *Event {
return l.newEvent(PanicLevel, true, func(msg string) { panic(msg) })
}

// WithLevel starts a new message with level.
//
// You must call Msg on the returned event in order to send the event.
func (l Logger) WithLevel(level Level) *Event {
switch level {
case DebugLevel:
return l.Debug()
case InfoLevel:
return l.Info()
case WarnLevel:
return l.Warn()
case ErrorLevel:
return l.Error()
case FatalLevel:
return l.Fatal()
case PanicLevel:
return l.Panic()
case Disabled:
return disabledEvent
default:
panic("zerolog: WithLevel(): invalid level: " + strconv.Itoa(int(level)))
}
}

// Log starts a new message with no level. Setting GlobalLevel to Disabled
// will still disable events produced by this method.
//
Expand Down
9 changes: 9 additions & 0 deletions log_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,15 @@ func ExampleLogger_Error() {
// Output: {"level":"error","error":"some error","message":"error doing something"}
}

func ExampleLogger_WithLevel() {
log := zerolog.New(os.Stdout)

log.WithLevel(zerolog.InfoLevel).
Msg("hello world")

// Output: {"level":"info","message":"hello world"}
}

func ExampleLogger_Write() {
log := zerolog.New(os.Stdout).With().
Str("foo", "bar").
Expand Down
78 changes: 59 additions & 19 deletions log_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func TestLog(t *testing.T) {
log := New(out)
log.Log().Msg("")
if got, want := out.String(), "{}\n"; got != want {
t.Errorf("invalid log output: got %q, want %q", got, want)
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
})

Expand All @@ -23,7 +23,7 @@ func TestLog(t *testing.T) {
log := New(out)
log.Log().Str("foo", "bar").Msg("")
if got, want := out.String(), `{"foo":"bar"}`+"\n"; got != want {
t.Errorf("invalid log output: got %q, want %q", got, want)
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
})

Expand All @@ -35,7 +35,7 @@ func TestLog(t *testing.T) {
Int("n", 123).
Msg("")
if got, want := out.String(), `{"foo":"bar","n":123}`+"\n"; got != want {
t.Errorf("invalid log output: got %q, want %q", got, want)
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
})
}
Expand All @@ -46,7 +46,7 @@ func TestInfo(t *testing.T) {
log := New(out)
log.Info().Msg("")
if got, want := out.String(), `{"level":"info"}`+"\n"; got != want {
t.Errorf("invalid log output: got %q, want %q", got, want)
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
})

Expand All @@ -55,7 +55,7 @@ func TestInfo(t *testing.T) {
log := New(out)
log.Info().Str("foo", "bar").Msg("")
if got, want := out.String(), `{"level":"info","foo":"bar"}`+"\n"; got != want {
t.Errorf("invalid log output: got %q, want %q", got, want)
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
})

Expand All @@ -67,7 +67,7 @@ func TestInfo(t *testing.T) {
Int("n", 123).
Msg("")
if got, want := out.String(), `{"level":"info","foo":"bar","n":123}`+"\n"; got != want {
t.Errorf("invalid log output: got %q, want %q", got, want)
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
})
}
Expand Down Expand Up @@ -95,7 +95,36 @@ func TestWith(t *testing.T) {
Logger()
log.Log().Msg("")
if got, want := out.String(), `{"foo":"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,"time":"0001-01-01T00:00:00Z"}`+"\n"; got != want {
t.Errorf("invalid log output: got %q, want %q", got, want)
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
}

func TestFieldsMap(t *testing.T) {
out := &bytes.Buffer{}
log := New(out)
log.Log().Fields(map[string]interface{}{
"nil": nil,
"string": "foo",
"bytes": []byte("bar"),
"error": errors.New("some error"),
"bool": true,
"int": int(1),
"int8": int8(2),
"int16": int16(3),
"int32": int32(4),
"int64": int64(5),
"uint": uint(6),
"uint8": uint8(7),
"uint16": uint16(8),
"uint32": uint32(9),
"uint64": uint64(10),
"float32": float32(11),
"float64": float64(12),
"dur": 1 * time.Second,
"time": time.Time{},
}).Msg("")
if got, want := out.String(), `{"bool":true,"bytes":"bar","dur":1000,"error":"some error","float32":11,"float64":12,"int":1,"int16":3,"int32":4,"int64":5,"int8":2,"nil":null,"string":"foo","time":"0001-01-01T00:00:00Z","uint":6,"uint16":8,"uint32":9,"uint64":10,"uint8":7}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
}

Expand All @@ -104,7 +133,8 @@ func TestFields(t *testing.T) {
log := New(out)
now := time.Now()
log.Log().
Str("foo", "bar").
Str("string", "foo").
Bytes("bytes", []byte("bar")).
AnErr("some_err", nil).
Err(errors.New("some error")).
Bool("bool", true).
Expand All @@ -124,8 +154,8 @@ func TestFields(t *testing.T) {
Time("time", time.Time{}).
TimeDiff("diff", now, now.Add(-10*time.Second)).
Msg("")
if got, want := out.String(), `{"foo":"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,"dur":1000,"time":"0001-01-01T00:00:00Z","diff":10000}`+"\n"; got != want {
t.Errorf("invalid log output: got %q, want %q", got, want)
if got, want := out.String(), `{"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,"dur":1000,"time":"0001-01-01T00:00:00Z","diff":10000}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
}

Expand All @@ -134,7 +164,8 @@ func TestFieldsDisabled(t *testing.T) {
log := New(out).Level(InfoLevel)
now := time.Now()
log.Debug().
Str("foo", "bar").
Str("string", "foo").
Bytes("bytes", []byte("bar")).
AnErr("some_err", nil).
Err(errors.New("some error")).
Bool("bool", true).
Expand All @@ -155,15 +186,15 @@ func TestFieldsDisabled(t *testing.T) {
TimeDiff("diff", now, now.Add(-10*time.Second)).
Msg("")
if got, want := out.String(), ""; got != want {
t.Errorf("invalid log output: got %q, want %q", got, want)
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
}

func TestMsgf(t *testing.T) {
out := &bytes.Buffer{}
New(out).Log().Msgf("one %s %.1f %d %v", "two", 3.4, 5, errors.New("six"))
if got, want := out.String(), `{"message":"one two 3.4 5 six"}`+"\n"; got != want {
t.Errorf("invalid log output: got %q, want %q", got, want)
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
}

Expand All @@ -172,7 +203,7 @@ func TestWithAndFieldsCombined(t *testing.T) {
log := New(out).With().Str("f1", "val").Str("f2", "val").Logger()
log.Log().Str("f3", "val").Msg("")
if got, want := out.String(), `{"f1":"val","f2":"val","f3":"val"}`+"\n"; got != want {
t.Errorf("invalid log output: got %q, want %q", got, want)
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
}

Expand All @@ -182,7 +213,7 @@ func TestLevel(t *testing.T) {
log := New(out).Level(Disabled)
log.Info().Msg("test")
if got, want := out.String(), ""; got != want {
t.Errorf("invalid log output: got %q, want %q", got, want)
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
})

Expand All @@ -191,7 +222,7 @@ func TestLevel(t *testing.T) {
log := New(out).Level(InfoLevel)
log.Info().Msg("test")
if got, want := out.String(), `{"level":"info","message":"test"}`+"\n"; got != want {
t.Errorf("invalid log output: got %q, want %q", got, want)
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
})
}
Expand All @@ -204,7 +235,7 @@ func TestSampling(t *testing.T) {
log.Log().Int("i", 3).Msg("")
log.Log().Int("i", 4).Msg("")
if got, want := out.String(), "{\"sample\":2,\"i\":2}\n{\"sample\":2,\"i\":4}\n"; got != want {
t.Errorf("invalid log output: got %q, want %q", got, want)
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
}

Expand Down Expand Up @@ -239,6 +270,11 @@ func TestLevelWriter(t *testing.T) {
log.Info().Msg("2")
log.Warn().Msg("3")
log.Error().Msg("4")
log.WithLevel(DebugLevel).Msg("5")
log.WithLevel(InfoLevel).Msg("6")
log.WithLevel(WarnLevel).Msg("7")
log.WithLevel(ErrorLevel).Msg("8")

want := []struct {
l Level
p string
Expand All @@ -247,6 +283,10 @@ func TestLevelWriter(t *testing.T) {
{InfoLevel, `{"level":"info","message":"2"}` + "\n"},
{WarnLevel, `{"level":"warn","message":"3"}` + "\n"},
{ErrorLevel, `{"level":"error","message":"4"}` + "\n"},
{DebugLevel, `{"level":"debug","message":"5"}` + "\n"},
{InfoLevel, `{"level":"info","message":"6"}` + "\n"},
{WarnLevel, `{"level":"warn","message":"7"}` + "\n"},
{ErrorLevel, `{"level":"error","message":"8"}` + "\n"},
}
if got := lw.ops; !reflect.DeepEqual(got, want) {
t.Errorf("invalid ops:\ngot:\n%v\nwant:\n%v", got, want)
Expand All @@ -265,7 +305,7 @@ func TestContextTimestamp(t *testing.T) {
log.Log().Msg("hello world")

if got, want := out.String(), `{"time":"2001-02-03T04:05:06Z","foo":"bar","message":"hello world"}`+"\n"; got != want {
t.Errorf("invalid log output: got %q, want %q", got, want)
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
}

Expand All @@ -281,6 +321,6 @@ func TestEventTimestamp(t *testing.T) {
log.Log().Timestamp().Msg("hello world")

if got, want := out.String(), `{"foo":"bar","time":"2001-02-03T04:05:06Z","message":"hello world"}`+"\n"; got != want {
t.Errorf("invalid log output: got %q, want %q", got, want)
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
}

0 comments on commit 7af6538

Please sign in to comment.