Add support for custom object marshaling

This commit is contained in:
Olivier Poitrey 2017-07-25 18:41:05 -07:00
parent f220d89e1f
commit fdbdb09630
4 changed files with 88 additions and 6 deletions

View File

@ -72,12 +72,19 @@ func BenchmarkLogFields(b *testing.B) {
})
}
type obj struct {
Pub string
Tag string `json:"tag"`
priv int
}
func (o obj) MarshalZerologObject(e *Event) {
e.Str("Pub", o.Pub).
Str("Tag", o.Tag).
Int("priv", o.priv)
}
func BenchmarkLogFieldType(b *testing.B) {
type obj struct {
Pub string
Tag string `json:"tag"`
priv int
}
bools := []bool{true, false, true, false, true, false, true, false, true, false}
ints := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
floats := []float64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
@ -143,6 +150,9 @@ func BenchmarkLogFieldType(b *testing.B) {
"Interface": func(e *Event) *Event {
return e.Interface("k", o)
},
"Object": func(e *Event) *Event {
return e.Object("k", o)
},
}
logger := New(ioutil.Discard)
b.ResetTimer()

View File

@ -1,6 +1,9 @@
package zerolog
import "time"
import (
"io/ioutil"
"time"
)
// Context configures a new sub-logger with contextual fields.
type Context struct {
@ -26,6 +29,16 @@ func (c Context) Dict(key string, dict *Event) Context {
return c
}
// Object marshals an object that implement the LogObjectMarshaler interface.
func (c Context) Object(key string, obj LogObjectMarshaler) Context {
e := newEvent(levelWriterAdapter{ioutil.Discard}, 0, true)
e.Object(key, obj)
e.buf[0] = ',' // A new event starts as an object, we want to embed it.
c.l.context = append(c.l.context, e.buf...)
eventPool.Put(e)
return c
}
// Str adds the field key with val as a string to the logger context.
func (c Context) Str(key, val string) Context {
c.l.context = appendString(c.l.context, key, val)

View File

@ -26,6 +26,10 @@ type Event struct {
done func(msg string)
}
type LogObjectMarshaler interface {
MarshalZerologObject(e *Event)
}
func newEvent(w LevelWriter, level Level, enabled bool) *Event {
if !enabled {
return &Event{}
@ -121,6 +125,23 @@ func Dict() *Event {
return newEvent(levelWriterAdapter{ioutil.Discard}, 0, true)
}
// Object marshals an object that implement the LogObjectMarshaler interface.
func (e *Event) Object(key string, obj LogObjectMarshaler) *Event {
e.buf = appendKey(e.buf, key)
pos := len(e.buf)
obj.MarshalZerologObject(e)
if pos < len(e.buf) {
// As MarshalZerologObject will use event API, the first field will be
// preceded by a coma. If at least one field has been added (buf grew),
// we replace this coma by the opening bracket.
e.buf[pos] = '{'
} else {
e.buf = append(e.buf, '{')
}
e.buf = append(e.buf, '}')
return e
}
// Str adds the field key with val as a string to the *Event context.
func (e *Event) Str(key, val string) *Event {
if !e.enabled {

View File

@ -138,6 +138,31 @@ func ExampleEvent_Dict() {
// Output: {"foo":"bar","dict":{"bar":"baz","n":1},"message":"hello world"}
}
type User struct {
Name string
Age int
Created time.Time
}
func (u User) MarshalZerologObject(e *zerolog.Event) {
e.Str("name", u.Name).
Int("age", u.Age).
Time("created", u.Created)
}
func ExampleEvent_Object() {
log := zerolog.New(os.Stdout)
u := User{"John", 35, time.Time{}}
log.Log().
Str("foo", "bar").
Object("user", u).
Msg("hello world")
// Output: {"foo":"bar","user":{"name":"John","age":35,"created":"0001-01-01T00:00:00Z"},"message":"hello world"}
}
func ExampleEvent_Interface() {
log := zerolog.New(os.Stdout)
@ -197,6 +222,19 @@ func ExampleContext_Dict() {
// Output: {"foo":"bar","dict":{"bar":"baz","n":1},"message":"hello world"}
}
func ExampleContext_Object() {
u := User{"John", 35, time.Time{}}
log := zerolog.New(os.Stdout).With().
Str("foo", "bar").
Object("user", u).
Logger()
log.Log().Msg("hello world")
// Output: {"foo":"bar","user":{"name":"John","age":35,"created":"0001-01-01T00:00:00Z"},"message":"hello world"}
}
func ExampleContext_Interface() {
obj := struct {
Name string `json:"name"`