mirror of
https://github.com/rs/zerolog
synced 2026-06-08 17:13:30 +00:00
Fix missing context.Context in Object/EmbedObject (#737)
Copies over event settings for ctx, hooks, and stack
- Fix missing context for Event.appendObjects passes event's stack, ctx, and hooks (ch).
- Add Array.Errs support.
- Context.Errs, Event.Errs, use new Array.Errs()
- Array.Err handles nil correctly.
- Fix Event.Err code ignoring modified event in ErrorStackMarshaler handling.
- Fix Fields.appendFieldList when ErrorMarshalFunc returns a nil.
- Fields.appendFieldList does no longer adds the ErrorStackFieldName field when ErrorStackMarshaler returns nil.
- Don't call the ErrorMarshalFunc on nil errors.
- Removed unreachable code NOP in Context.Array
- Rewrite ErrorMarshalFunc testing.
- Made diode tests more stable.
- Log copy error in test.
- Address review comments
- Added CreateArray() and CreateDict() for both Context and Event and deprecate the Arr() and Dict().
Array now carries then stack/context/hooks so they are available to LogObjectMarshal of Array elements.
Added unit tests for error marshal that returns an interface{}
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package zerolog
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -17,7 +18,10 @@ var arrayPool = &sync.Pool{
|
||||
// Array is used to prepopulate an array of items
|
||||
// which can be re-used to add to log messages.
|
||||
type Array struct {
|
||||
buf []byte
|
||||
buf []byte
|
||||
stack bool // enable error stack trace
|
||||
ctx context.Context // Optional Go context
|
||||
ch []Hook // hooks
|
||||
}
|
||||
|
||||
func putArray(a *Array) {
|
||||
@@ -31,13 +35,22 @@ func putArray(a *Array) {
|
||||
if cap(a.buf) > maxSize {
|
||||
return
|
||||
}
|
||||
a.stack = false
|
||||
a.ctx = nil
|
||||
a.ch = nil
|
||||
arrayPool.Put(a)
|
||||
}
|
||||
|
||||
// Arr creates an array to be added to an Event or Context.
|
||||
// WARNING: This function is deprecated because it does not preserve
|
||||
// the stack, hooks, and context from the parent event.
|
||||
// Deprecated: Use Event.CreateArray or Context.CreateArray instead.
|
||||
func Arr() *Array {
|
||||
a := arrayPool.Get().(*Array)
|
||||
a.buf = a.buf[:0]
|
||||
a.stack = false
|
||||
a.ctx = nil
|
||||
a.ch = nil
|
||||
return a
|
||||
}
|
||||
|
||||
@@ -59,7 +72,7 @@ func (a *Array) write(dst []byte) []byte {
|
||||
// Object marshals an object that implement the LogObjectMarshaler
|
||||
// interface and appends it to the array.
|
||||
func (a *Array) Object(obj LogObjectMarshaler) *Array {
|
||||
a.buf = appendObject(enc.AppendArrayDelim(a.buf), obj)
|
||||
a.buf = appendObject(enc.AppendArrayDelim(a.buf), obj, a.stack, a.ctx, a.ch)
|
||||
return a
|
||||
}
|
||||
|
||||
@@ -90,12 +103,12 @@ func (a *Array) RawJSON(val []byte) *Array {
|
||||
// Err serializes and appends the err to the array.
|
||||
func (a *Array) Err(err error) *Array {
|
||||
switch m := ErrorMarshalFunc(err).(type) {
|
||||
case nil:
|
||||
a.buf = enc.AppendNil(enc.AppendArrayDelim(a.buf))
|
||||
case LogObjectMarshaler:
|
||||
a = a.Object(m)
|
||||
case error:
|
||||
if m == nil || isNilValue(m) {
|
||||
a.buf = enc.AppendNil(enc.AppendArrayDelim(a.buf))
|
||||
} else {
|
||||
if !isNilValue(m) {
|
||||
a.buf = enc.AppendString(enc.AppendArrayDelim(a.buf), m.Error())
|
||||
}
|
||||
case string:
|
||||
@@ -107,6 +120,27 @@ func (a *Array) Err(err error) *Array {
|
||||
return a
|
||||
}
|
||||
|
||||
// Errs serializes and appends errors to the array.
|
||||
func (a *Array) Errs(errs []error) *Array {
|
||||
for _, err := range errs {
|
||||
switch m := ErrorMarshalFunc(err).(type) {
|
||||
case nil:
|
||||
a = a.Interface(nil)
|
||||
case LogObjectMarshaler:
|
||||
a = a.Object(m)
|
||||
case error:
|
||||
if !isNilValue(m) {
|
||||
a = a.Str(m.Error())
|
||||
}
|
||||
case string:
|
||||
a = a.Str(m)
|
||||
default:
|
||||
a = a.Interface(m)
|
||||
}
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// Bool appends the val as a bool to the array.
|
||||
func (a *Array) Bool(b bool) *Array {
|
||||
a.buf = enc.AppendBool(enc.AppendArrayDelim(a.buf), b)
|
||||
|
||||
+2
-2
@@ -47,14 +47,14 @@ func TestArray(t *testing.T) {
|
||||
).
|
||||
Err(nil).
|
||||
Err(fmt.Errorf("failure")).
|
||||
Err(errorObjectMarshalerImpl{fmt.Errorf("oops")}).
|
||||
Err(loggableError{fmt.Errorf("oops")}).
|
||||
Object(logObjectMarshalerImpl{
|
||||
name: "ZIT",
|
||||
age: 22,
|
||||
}).
|
||||
Type(3.14)
|
||||
|
||||
want := `[true,1,2,3,4,5,6,7,8,9,10,11.98122,12.987654321,"a","b","1f",{"some":"json"},{"longer":[1111,2222,3333,4444,5555]},"0001-01-01T00:00:00Z","192.168.0.10","127.0.0.0/24","01:23:45:67:89:ab",{"Pub":"A","tag":"j"},{"name":"zot","age":-35},0,{"bar":"baz","n":1},null,"failure",{"error":"OOPS"},{"name":"zit","age":-22},"float64"]`
|
||||
want := `[true,1,2,3,4,5,6,7,8,9,10,11.98122,12.987654321,"a","b","1f",{"some":"json"},{"longer":[1111,2222,3333,4444,5555]},"0001-01-01T00:00:00Z","192.168.0.10","127.0.0.0/24","01:23:45:67:89:ab",{"Pub":"A","tag":"j"},{"name":"zot","age":-35},0,{"bar":"baz","n":1},null,"failure",{"l":"OOPS"},{"name":"zit","age":-22},"float64"]`
|
||||
if got := decodeObjectToStr(a.write([]byte{})); got != want {
|
||||
t.Errorf("Array.write()\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
|
||||
+30
-26
@@ -206,12 +206,13 @@ func ExampleEvent_Dict() {
|
||||
dst := bytes.Buffer{}
|
||||
log := New(&dst)
|
||||
|
||||
log.Log().
|
||||
Str("foo", "bar").
|
||||
Dict("dict", Dict().
|
||||
Str("bar", "baz").
|
||||
Int("n", 1),
|
||||
).
|
||||
e := log.Log().
|
||||
Str("foo", "bar")
|
||||
|
||||
e.Dict("dict", e.CreateDict().
|
||||
Str("bar", "baz").
|
||||
Int("n", 1),
|
||||
).
|
||||
Msg("hello world")
|
||||
|
||||
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
|
||||
@@ -243,12 +244,13 @@ func ExampleEvent_Array() {
|
||||
dst := bytes.Buffer{}
|
||||
log := New(&dst)
|
||||
|
||||
log.Log().
|
||||
Str("foo", "bar").
|
||||
Array("array", Arr().
|
||||
Str("baz").
|
||||
Int(1),
|
||||
).
|
||||
e := log.Log().
|
||||
Str("foo", "bar")
|
||||
|
||||
e.Array("array", e.CreateArray().
|
||||
Str("baz").
|
||||
Int(1),
|
||||
).
|
||||
Msg("hello world")
|
||||
|
||||
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
|
||||
@@ -414,14 +416,15 @@ func ExampleEvent_Fields_slice() {
|
||||
|
||||
func ExampleContext_Dict() {
|
||||
dst := bytes.Buffer{}
|
||||
log := New(&dst).With().
|
||||
Str("foo", "bar").
|
||||
Dict("dict", Dict().
|
||||
Str("bar", "baz").
|
||||
Int("n", 1),
|
||||
).Logger()
|
||||
ctx := New(&dst).With().
|
||||
Str("foo", "bar")
|
||||
|
||||
log.Log().Msg("hello world")
|
||||
logger := ctx.Dict("dict", ctx.CreateDict().
|
||||
Str("bar", "baz").
|
||||
Int("n", 1),
|
||||
).Logger()
|
||||
|
||||
logger.Log().Msg("hello world")
|
||||
|
||||
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
|
||||
// Output: {"foo":"bar","dict":{"bar":"baz","n":1},"message":"hello world"}
|
||||
@@ -429,14 +432,15 @@ func ExampleContext_Dict() {
|
||||
|
||||
func ExampleContext_Array() {
|
||||
dst := bytes.Buffer{}
|
||||
log := New(&dst).With().
|
||||
Str("foo", "bar").
|
||||
Array("array", Arr().
|
||||
Str("baz").
|
||||
Int(1),
|
||||
).Logger()
|
||||
ctx := New(&dst).With().
|
||||
Str("foo", "bar")
|
||||
|
||||
log.Log().Msg("hello world")
|
||||
logger := ctx.Array("array", ctx.CreateArray().
|
||||
Str("baz").
|
||||
Int(1),
|
||||
).Logger()
|
||||
|
||||
logger.Log().Msg("hello world")
|
||||
|
||||
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
|
||||
// Output: {"foo":"bar","array":["baz",1],"message":"hello world"}
|
||||
|
||||
+33
-37
@@ -3,7 +3,6 @@ package zerolog
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"time"
|
||||
@@ -23,7 +22,7 @@ func (c Context) Logger() Logger {
|
||||
// Only map[string]interface{} and []interface{} are accepted. []interface{} must
|
||||
// alternate string keys and arbitrary values, and extraneous ones are ignored.
|
||||
func (c Context) Fields(fields interface{}) Context {
|
||||
c.l.context = appendFields(c.l.context, fields, c.l.stack)
|
||||
c.l.context = appendFields(c.l.context, fields, c.l.stack, c.l.ctx, c.l.hooks)
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -35,8 +34,28 @@ func (c Context) Dict(key string, dict *Event) Context {
|
||||
return c
|
||||
}
|
||||
|
||||
// CreateDict creates an Event to be used with the Context.Dict method.
|
||||
// It preserves the stack, hooks, and context from the logger.
|
||||
// Call usual field methods like Str, Int etc to add fields to this
|
||||
// event and give it as argument the Context.Dict method.
|
||||
func (c Context) CreateDict() *Event {
|
||||
return newEvent(nil, DebugLevel, c.l.stack, c.l.ctx, c.l.hooks)
|
||||
}
|
||||
|
||||
// CreateArray creates an Array to be used with the Context.Array method.
|
||||
// It preserves the stack, hooks, and context from the logger.
|
||||
// Call usual field methods like Str, Int etc to add elements to this
|
||||
// array and give it as argument the Context.Array method.
|
||||
func (c Context) CreateArray() *Array {
|
||||
a := Arr()
|
||||
a.stack = c.l.stack
|
||||
a.ctx = c.l.ctx
|
||||
a.ch = c.l.hooks
|
||||
return a
|
||||
}
|
||||
|
||||
// Array adds the field key with an array to the event context.
|
||||
// Use zerolog.Arr() to create the array or pass a type that
|
||||
// Use c.CreateArray() to create the array or pass a type that
|
||||
// implement the LogArrayMarshaler interface.
|
||||
func (c Context) Array(key string, arr LogArrayMarshaler) Context {
|
||||
c.l.context = enc.AppendKey(c.l.context, key)
|
||||
@@ -44,20 +63,15 @@ func (c Context) Array(key string, arr LogArrayMarshaler) Context {
|
||||
c.l.context = arr.write(c.l.context)
|
||||
return c
|
||||
}
|
||||
var a *Array
|
||||
if aa, ok := arr.(*Array); ok {
|
||||
a = aa
|
||||
} else {
|
||||
a = Arr()
|
||||
arr.MarshalZerologArray(a)
|
||||
}
|
||||
a := c.CreateArray()
|
||||
arr.MarshalZerologArray(a)
|
||||
c.l.context = a.write(c.l.context)
|
||||
return c
|
||||
}
|
||||
|
||||
// Object marshals an object that implement the LogObjectMarshaler interface.
|
||||
func (c Context) Object(key string, obj LogObjectMarshaler) Context {
|
||||
e := newEvent(LevelWriterAdapter{io.Discard}, 0)
|
||||
e := c.l.scratchEvent()
|
||||
e.Object(key, obj)
|
||||
c.l.context = enc.AppendObjectData(c.l.context, e.buf)
|
||||
putEvent(e)
|
||||
@@ -66,7 +80,7 @@ func (c Context) Object(key string, obj LogObjectMarshaler) Context {
|
||||
|
||||
// Object marshals an object that implement the LogObjectMarshaler interface.
|
||||
func (c Context) Objects(key string, objs []LogObjectMarshaler) Context {
|
||||
e := newEvent(LevelWriterAdapter{io.Discard}, 0)
|
||||
e := c.l.scratchEvent()
|
||||
e.Objects(key, objs)
|
||||
c.l.context = enc.AppendObjectData(c.l.context, e.buf)
|
||||
putEvent(e)
|
||||
@@ -75,7 +89,7 @@ func (c Context) Objects(key string, objs []LogObjectMarshaler) Context {
|
||||
|
||||
// EmbedObject marshals and Embeds an object that implement the LogObjectMarshaler interface.
|
||||
func (c Context) EmbedObject(obj LogObjectMarshaler) Context {
|
||||
e := newEvent(LevelWriterAdapter{io.Discard}, 0)
|
||||
e := c.l.scratchEvent()
|
||||
e.EmbedObject(obj)
|
||||
c.l.context = enc.AppendObjectData(c.l.context, e.buf)
|
||||
putEvent(e)
|
||||
@@ -139,6 +153,7 @@ func (c Context) RawJSON(key string, b []byte) Context {
|
||||
}
|
||||
|
||||
// AnErr adds the field key with serialized err to the logger context.
|
||||
// If err is nil, no field is added.
|
||||
func (c Context) AnErr(key string, err error) Context {
|
||||
switch m := ErrorMarshalFunc(err).(type) {
|
||||
case nil:
|
||||
@@ -146,11 +161,10 @@ func (c Context) AnErr(key string, err error) Context {
|
||||
case LogObjectMarshaler:
|
||||
return c.Object(key, m)
|
||||
case error:
|
||||
if m == nil || isNilValue(m) {
|
||||
if isNilValue(m) {
|
||||
return c
|
||||
} else {
|
||||
return c.Str(key, m.Error())
|
||||
}
|
||||
return c.Str(key, m.Error())
|
||||
case string:
|
||||
return c.Str(key, m)
|
||||
default:
|
||||
@@ -161,24 +175,7 @@ func (c Context) AnErr(key string, err error) Context {
|
||||
// Errs adds the field key with errs as an array of serialized errors to the
|
||||
// logger context.
|
||||
func (c Context) Errs(key string, errs []error) Context {
|
||||
arr := Arr()
|
||||
for _, err := range errs {
|
||||
switch m := ErrorMarshalFunc(err).(type) {
|
||||
case LogObjectMarshaler:
|
||||
arr = arr.Object(m)
|
||||
case error:
|
||||
if m == nil || isNilValue(m) {
|
||||
arr = arr.Interface(nil)
|
||||
} else {
|
||||
arr = arr.Str(m.Error())
|
||||
}
|
||||
case string:
|
||||
arr = arr.Str(m)
|
||||
default:
|
||||
arr = arr.Interface(m)
|
||||
}
|
||||
}
|
||||
|
||||
arr := c.CreateArray().Errs(errs)
|
||||
return c.Array(key, arr)
|
||||
}
|
||||
|
||||
@@ -187,12 +184,11 @@ func (c Context) Err(err error) Context {
|
||||
if c.l.stack && ErrorStackMarshaler != nil {
|
||||
switch m := ErrorStackMarshaler(err).(type) {
|
||||
case nil:
|
||||
// do nothing
|
||||
case LogObjectMarshaler:
|
||||
c = c.Object(ErrorStackFieldName, m)
|
||||
case error:
|
||||
if m != nil && !isNilValue(m) {
|
||||
c = c.Str(ErrorStackFieldName, m.Error())
|
||||
}
|
||||
c = c.Str(ErrorStackFieldName, m.Error())
|
||||
case string:
|
||||
c = c.Str(ErrorStackFieldName, m)
|
||||
default:
|
||||
|
||||
@@ -82,14 +82,6 @@ func (t logObjectMarshalerImpl) MarshalZerologObject(e *Event) {
|
||||
e.Str("name", strings.ToLower(t.name)).Int("age", -t.age)
|
||||
}
|
||||
|
||||
type errorObjectMarshalerImpl struct {
|
||||
error
|
||||
}
|
||||
|
||||
func (t errorObjectMarshalerImpl) MarshalZerologObject(e *Event) {
|
||||
e.Str("error", strings.ToUpper(t.error.Error()))
|
||||
}
|
||||
|
||||
func Test_InterfaceLogObjectMarshaler(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
log := New(&buf)
|
||||
|
||||
+27
-8
@@ -7,6 +7,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -60,15 +61,25 @@ func TestFatal(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
slurp, err := io.ReadAll(stderr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var stderrBuf bytes.Buffer
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if _, err := io.Copy(&stderrBuf, stderr); err != nil {
|
||||
t.Errorf("failed to copy stderr: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = cmd.Wait()
|
||||
if err == nil {
|
||||
t.Error("Expected log.Fatal to exit with non-zero status")
|
||||
}
|
||||
|
||||
wg.Wait() // Wait for the goroutine to finish copying
|
||||
slurp := stderrBuf.Bytes()
|
||||
|
||||
want := "{\"level\":\"fatal\",\"message\":\"test\"}\n"
|
||||
got := cbor.DecodeIfBinaryToString(slurp)
|
||||
if got != want {
|
||||
@@ -112,15 +123,23 @@ func TestFatalWithFilteredLevelWriter(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
slurp, err := io.ReadAll(stdout)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var stdoutBuf bytes.Buffer
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
_, _ = io.Copy(&stdoutBuf, stdout)
|
||||
}()
|
||||
|
||||
err = cmd.Wait()
|
||||
if err == nil {
|
||||
t.Error("Expected log.Fatal to exit with non-zero status")
|
||||
}
|
||||
|
||||
wg.Wait() // Wait for the goroutine to finish copying
|
||||
slurp := stdoutBuf.Bytes()
|
||||
|
||||
got := cbor.DecodeIfBinaryToString(slurp)
|
||||
want := "{\"level\":\"fatal\",\"message\":\"test\"}\n"
|
||||
if got != want {
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
package zerolog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type loggableError struct {
|
||||
error
|
||||
}
|
||||
|
||||
func (l loggableError) MarshalZerologObject(e *Event) {
|
||||
if l.error == nil {
|
||||
return
|
||||
}
|
||||
e.Str("l", strings.ToUpper(l.error.Error()))
|
||||
}
|
||||
|
||||
type nonLoggableError struct {
|
||||
error
|
||||
line int
|
||||
}
|
||||
|
||||
type wrappedError struct {
|
||||
error
|
||||
msg string
|
||||
}
|
||||
|
||||
func (w wrappedError) Error() string {
|
||||
if w.error == nil {
|
||||
return w.msg
|
||||
}
|
||||
return w.error.Error() + ": " + w.msg
|
||||
}
|
||||
|
||||
type interfaceError struct {
|
||||
val string
|
||||
}
|
||||
|
||||
func TestArrayErrorMarshalFunc(t *testing.T) {
|
||||
prefixed := func(s, prefix string) string {
|
||||
if s == "null" {
|
||||
return ""
|
||||
}
|
||||
return prefix + s + `,`
|
||||
}
|
||||
errs := []error{
|
||||
nil,
|
||||
fmt.Errorf("failure"),
|
||||
loggableError{fmt.Errorf("whoops")},
|
||||
nonLoggableError{fmt.Errorf("oops"), 402},
|
||||
}
|
||||
type testCase struct {
|
||||
name string
|
||||
marshal func(err error) interface{}
|
||||
want []string
|
||||
}
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "default",
|
||||
marshal: nil,
|
||||
want: []string{`null`, `"failure"`, `{"l":"WHOOPS"}`, `"oops"`},
|
||||
},
|
||||
{
|
||||
name: "string",
|
||||
marshal: func(err error) interface{} {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return err.Error()
|
||||
},
|
||||
want: []string{`null`, `"failure"`, `"whoops"`, `"oops"`},
|
||||
},
|
||||
{
|
||||
name: "loggable",
|
||||
marshal: func(err error) interface{} {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return loggableError{err}
|
||||
},
|
||||
want: []string{`null`, `{"l":"FAILURE"}`, `{"l":"WHOOPS"}`, `{"l":"OOPS"}`},
|
||||
},
|
||||
{
|
||||
name: "non-loggable",
|
||||
marshal: func(err error) interface{} {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return nonLoggableError{err, 404}
|
||||
},
|
||||
want: []string{`null`, `"failure"`, `"whoops"`, `"oops"`},
|
||||
},
|
||||
{
|
||||
name: "interface",
|
||||
marshal: func(err error) interface{} {
|
||||
var some interfaceError
|
||||
if err != nil {
|
||||
some.val = err.Error()
|
||||
}
|
||||
var interfaceErr interface{} = some
|
||||
return interfaceErr
|
||||
},
|
||||
want: []string{`{}`, `{}`, `{}`, `{}`},
|
||||
},
|
||||
{
|
||||
name: "nilError",
|
||||
marshal: func(err error) interface{} {
|
||||
var errNil error = nil
|
||||
return errNil
|
||||
},
|
||||
want: []string{`null`, `null`, `null`, `null`},
|
||||
},
|
||||
{
|
||||
name: "wrapped error",
|
||||
marshal: func(err error) interface{} {
|
||||
if err == nil {
|
||||
return nil
|
||||
} else if we, ok := err.(wrappedError); ok {
|
||||
return we
|
||||
} else {
|
||||
return wrappedError{err, "addendum"}
|
||||
}
|
||||
},
|
||||
want: []string{`null`, `"failure: addendum"`, `"whoops: addendum"`, `"oops: addendum"`},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
originalErrorMarshalFunc := ErrorMarshalFunc
|
||||
defer func() {
|
||||
ErrorMarshalFunc = originalErrorMarshalFunc
|
||||
}()
|
||||
|
||||
if tc.marshal != nil {
|
||||
ErrorMarshalFunc = tc.marshal
|
||||
}
|
||||
|
||||
t.Run("Err", func(t *testing.T) {
|
||||
for i, err := range errs {
|
||||
want := tc.want[i]
|
||||
t.Run("Arr", func(t *testing.T) {
|
||||
wants := `[` + want + `]`
|
||||
a := Arr().Err(err)
|
||||
if got := decodeObjectToStr(a.write([]byte{})); got != wants {
|
||||
t.Errorf("%s %d Array.Err(%v)\ngot: %s\nwant: %s", tc.name, i, err, got, wants)
|
||||
}
|
||||
})
|
||||
t.Run("Ctx", func(t *testing.T) {
|
||||
wants := `{` + prefixed(want, `"error":`) + `"message":"msg"}` + "\n"
|
||||
out := &bytes.Buffer{}
|
||||
logger := New(out).With().Err(err).Logger()
|
||||
logger.Log().Msg("msg")
|
||||
if got := decodeIfBinaryToString(out.Bytes()); got != wants {
|
||||
t.Errorf("%s %d Ctx.Err(%v)\ngot: %v\nwant: %v", tc.name, i, err, got, wants)
|
||||
}
|
||||
})
|
||||
t.Run("Event", func(t *testing.T) {
|
||||
wants := `{` + prefixed(want, `"error":`) + `"message":"msg"}` + "\n"
|
||||
out := &bytes.Buffer{}
|
||||
logger := New(out)
|
||||
logger.Log().Err(err).Msg("msg")
|
||||
if got := decodeIfBinaryToString(out.Bytes()); got != wants {
|
||||
t.Errorf("%s %d Event.Err(%v)\ngot: %v\nwant: %v", tc.name, i, err, got, wants)
|
||||
}
|
||||
})
|
||||
t.Run("Fields", func(t *testing.T) {
|
||||
if i == 0 && tc.want[i] == "{}" {
|
||||
want = `null`
|
||||
}
|
||||
wants := `{"err":` + want + `,"message":"msg"}` + "\n"
|
||||
out := &bytes.Buffer{}
|
||||
logger := New(out)
|
||||
logger.Log().Fields(map[string]interface{}{"err": err}).Msg("msg")
|
||||
if got := decodeIfBinaryToString(out.Bytes()); got != wants {
|
||||
t.Errorf("%s %d Event.Fields(%v)\ngot: %v\nwant: %v", tc.name, i, err, got, wants)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Errs", func(t *testing.T) {
|
||||
want := `[` + strings.Join(tc.want, ",") + `]`
|
||||
t.Run("Arr", func(t *testing.T) {
|
||||
a := Arr().Errs(errs)
|
||||
if got := decodeObjectToStr(a.write([]byte{})); got != want {
|
||||
t.Errorf("%s Array.Errs()\ngot: %s\nwant: %s", tc.name, got, want)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Ctx", func(t *testing.T) {
|
||||
wants := `{"e":` + want + `,"message":"msg"}` + "\n"
|
||||
out := &bytes.Buffer{}
|
||||
logger := New(out).With().Errs("e", errs).Logger()
|
||||
logger.Log().Msg("msg")
|
||||
if got := decodeIfBinaryToString(out.Bytes()); got != wants {
|
||||
t.Errorf("%s Ctx.Errs()\ngot: %v\nwant: %v", tc.name, got, wants)
|
||||
}
|
||||
})
|
||||
t.Run("Event", func(t *testing.T) {
|
||||
wants := `{"e":` + want + `,"message":"msg"}` + "\n"
|
||||
out := &bytes.Buffer{}
|
||||
logger := New(out)
|
||||
logger.Log().Errs("e", errs).Msg("msg")
|
||||
if got := decodeIfBinaryToString(out.Bytes()); got != wants {
|
||||
t.Errorf("%s Ctx.Errs()\ngot: %v\nwant: %v", tc.name, got, wants)
|
||||
}
|
||||
})
|
||||
t.Run("Fields", func(t *testing.T) {
|
||||
wants := `{"e":` + want + `,"message":"msg"}` + "\n"
|
||||
out := &bytes.Buffer{}
|
||||
logger := New(out)
|
||||
logger.Log().Fields(map[string]interface{}{"e": errs}).Msg("msg")
|
||||
if got := decodeIfBinaryToString(out.Bytes()); got != wants {
|
||||
t.Errorf("%s Ctx.Errs()\ngot: %v\nwant: %v", tc.name, got, wants)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -57,14 +57,15 @@ type LogArrayMarshaler interface {
|
||||
MarshalZerologArray(a *Array)
|
||||
}
|
||||
|
||||
func newEvent(w LevelWriter, level Level) *Event {
|
||||
func newEvent(w LevelWriter, level Level, stack bool, ctx context.Context, hooks []Hook) *Event {
|
||||
e := eventPool.Get().(*Event)
|
||||
e.buf = e.buf[:0]
|
||||
e.ch = nil
|
||||
e.stack = stack
|
||||
e.ctx = ctx
|
||||
e.ch = hooks
|
||||
e.buf = enc.AppendBeginMarker(e.buf)
|
||||
e.w = w
|
||||
e.level = level
|
||||
e.stack = false
|
||||
e.skipFrame = 0
|
||||
return e
|
||||
}
|
||||
@@ -164,12 +165,12 @@ func (e *Event) Fields(fields interface{}) *Event {
|
||||
if e == nil {
|
||||
return e
|
||||
}
|
||||
e.buf = appendFields(e.buf, fields, e.stack)
|
||||
e.buf = appendFields(e.buf, fields, e.stack, e.ctx, e.ch)
|
||||
return e
|
||||
}
|
||||
|
||||
// Dict adds the field key with a dict to the event context.
|
||||
// Use zerolog.Dict() to create the dictionary.
|
||||
// Use e.CreateDict() to create the dictionary.
|
||||
func (e *Event) Dict(key string, dict *Event) *Event {
|
||||
if e == nil {
|
||||
return e
|
||||
@@ -180,15 +181,43 @@ func (e *Event) Dict(key string, dict *Event) *Event {
|
||||
return e
|
||||
}
|
||||
|
||||
// CreateDict creates an Event to be used with the *Event.Dict method.
|
||||
// It preserves the stack, hooks, and context from the parent event.
|
||||
// Call usual field methods like Str, Int etc to add fields to this
|
||||
// event and give it as argument the *Event.Dict method.
|
||||
func (e *Event) CreateDict() *Event {
|
||||
if e == nil {
|
||||
return newEvent(nil, DebugLevel, false, nil, nil)
|
||||
}
|
||||
return newEvent(nil, DebugLevel, e.stack, e.ctx, e.ch)
|
||||
}
|
||||
|
||||
// Dict creates an Event to be used with the *Event.Dict method.
|
||||
// Call usual field methods like Str, Int etc to add fields to this
|
||||
// event and give it as argument the *Event.Dict method.
|
||||
// NOTE: This function is deprecated because it does not preserve
|
||||
// the stack, hooks, and context from the parent event.
|
||||
// Deprecated: Use Event.CreateDict instead.
|
||||
func Dict() *Event {
|
||||
return newEvent(nil, 0)
|
||||
return newEvent(nil, DebugLevel, false, nil, nil)
|
||||
}
|
||||
|
||||
// CreateArray creates an Array to be used with the *Event.Array method.
|
||||
// It preserves the stack, hooks, and context from the parent event.
|
||||
// Call usual field methods like Str, Int etc to add elements to this
|
||||
// array and give it as argument the *Event.Array method.
|
||||
func (e *Event) CreateArray() *Array {
|
||||
a := Arr()
|
||||
if e != nil {
|
||||
a.stack = e.stack
|
||||
a.ctx = e.ctx
|
||||
a.ch = e.ch
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// Array adds the field key with an array to the event context.
|
||||
// Use zerolog.Arr() to create the array or pass a type that
|
||||
// Use e.CreateArray() to create the array or pass a type that
|
||||
// implement the LogArrayMarshaler interface.
|
||||
func (e *Event) Array(key string, arr LogArrayMarshaler) *Event {
|
||||
if e == nil {
|
||||
@@ -199,7 +228,7 @@ func (e *Event) Array(key string, arr LogArrayMarshaler) *Event {
|
||||
if aa, ok := arr.(*Array); ok {
|
||||
a = aa
|
||||
} else {
|
||||
a = Arr()
|
||||
a = e.CreateArray()
|
||||
arr.MarshalZerologArray(a)
|
||||
}
|
||||
e.buf = a.write(e.buf)
|
||||
@@ -235,7 +264,7 @@ func (e *Event) Objects(key string, objs []LogObjectMarshaler) *Event {
|
||||
}
|
||||
e.buf = enc.AppendArrayStart(enc.AppendKey(e.buf, key))
|
||||
for i, obj := range objs {
|
||||
e.buf = appendObject(e.buf, obj)
|
||||
e.buf = appendObject(e.buf, obj, e.stack, e.ctx, e.ch)
|
||||
if i < (len(objs) - 1) {
|
||||
e.buf = enc.AppendArrayDelim(e.buf)
|
||||
}
|
||||
@@ -360,11 +389,10 @@ func (e *Event) AnErr(key string, err error) *Event {
|
||||
case LogObjectMarshaler:
|
||||
return e.Object(key, m)
|
||||
case error:
|
||||
if m == nil || isNilValue(m) {
|
||||
if isNilValue(m) {
|
||||
return e
|
||||
} else {
|
||||
return e.Str(key, m.Error())
|
||||
}
|
||||
return e.Str(key, m.Error())
|
||||
case string:
|
||||
return e.Str(key, m)
|
||||
default:
|
||||
@@ -378,20 +406,7 @@ func (e *Event) Errs(key string, errs []error) *Event {
|
||||
if e == nil {
|
||||
return e
|
||||
}
|
||||
arr := Arr()
|
||||
for _, err := range errs {
|
||||
switch m := ErrorMarshalFunc(err).(type) {
|
||||
case LogObjectMarshaler:
|
||||
arr = arr.Object(m)
|
||||
case error:
|
||||
arr = arr.Err(m)
|
||||
case string:
|
||||
arr = arr.Str(m)
|
||||
default:
|
||||
arr = arr.Interface(m)
|
||||
}
|
||||
}
|
||||
|
||||
arr := e.CreateArray().Errs(errs)
|
||||
return e.Array(key, arr)
|
||||
}
|
||||
|
||||
@@ -407,21 +422,22 @@ func (e *Event) Err(err error) *Event {
|
||||
if e == nil {
|
||||
return e
|
||||
}
|
||||
|
||||
if e.stack && ErrorStackMarshaler != nil {
|
||||
switch m := ErrorStackMarshaler(err).(type) {
|
||||
case nil:
|
||||
// do nothing
|
||||
case LogObjectMarshaler:
|
||||
e.Object(ErrorStackFieldName, m)
|
||||
e = e.Object(ErrorStackFieldName, m)
|
||||
case error:
|
||||
if m != nil && !isNilValue(m) {
|
||||
e.Str(ErrorStackFieldName, m.Error())
|
||||
}
|
||||
e = e.Str(ErrorStackFieldName, m.Error())
|
||||
case string:
|
||||
e.Str(ErrorStackFieldName, m)
|
||||
e = e.Str(ErrorStackFieldName, m)
|
||||
default:
|
||||
e.Interface(ErrorStackFieldName, m)
|
||||
e = e.Interface(ErrorStackFieldName, m)
|
||||
}
|
||||
}
|
||||
|
||||
return e.AnErr(ErrorFieldName, err)
|
||||
}
|
||||
|
||||
|
||||
+110
-30
@@ -1,9 +1,11 @@
|
||||
//go:build !binary_log
|
||||
// +build !binary_log
|
||||
|
||||
package zerolog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
@@ -14,7 +16,7 @@ import (
|
||||
type nilError struct{}
|
||||
|
||||
func (nilError) Error() string {
|
||||
return ""
|
||||
return "nope"
|
||||
}
|
||||
|
||||
func TestEvent_AnErr(t *testing.T) {
|
||||
@@ -30,9 +32,13 @@ func TestEvent_AnErr(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
e := newEvent(LevelWriterAdapter{&buf}, DebugLevel)
|
||||
e.AnErr("err", tt.err)
|
||||
_ = e.write()
|
||||
e := newEvent(LevelWriterAdapter{&buf}, DebugLevel, false, nil, nil)
|
||||
e = e.AnErr("err", tt.err)
|
||||
err := e.write()
|
||||
if err != nil {
|
||||
t.Errorf("Event.AnErr() error: %v", err)
|
||||
}
|
||||
|
||||
if got, want := strings.TrimSpace(buf.String()), tt.want; got != want {
|
||||
t.Errorf("Event.AnErr() = %v, want %v", got, want)
|
||||
}
|
||||
@@ -50,30 +56,104 @@ func TestEvent_writeWithNil(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvent_ObjectWithNil(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
e := newEvent(LevelWriterAdapter{&buf}, DebugLevel)
|
||||
_ = e.Object("obj", nil)
|
||||
_ = e.write()
|
||||
|
||||
want := `{"obj":null}`
|
||||
got := strings.TrimSpace(buf.String())
|
||||
if got != want {
|
||||
t.Errorf("Event.Object() = %q, want %q", got, want)
|
||||
}
|
||||
type loggableObject struct {
|
||||
member string
|
||||
}
|
||||
|
||||
func TestEvent_EmbedObjectWithNil(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
e := newEvent(LevelWriterAdapter{&buf}, DebugLevel)
|
||||
_ = e.EmbedObject(nil)
|
||||
_ = e.write()
|
||||
func (o loggableObject) MarshalZerologObject(e *Event) {
|
||||
e.Str("member", o.member)
|
||||
}
|
||||
|
||||
want := "{}"
|
||||
got := strings.TrimSpace(buf.String())
|
||||
if got != want {
|
||||
t.Errorf("Event.EmbedObject() = %q, want %q", got, want)
|
||||
}
|
||||
func TestEvent_Object(t *testing.T) {
|
||||
t.Run("ObjectWithNil", func(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
e := newEvent(LevelWriterAdapter{&buf}, DebugLevel, false, nil, nil)
|
||||
e = e.Object("obj", nil)
|
||||
err := e.write()
|
||||
if err != nil {
|
||||
t.Errorf("Event.Object() error: %v", err)
|
||||
}
|
||||
|
||||
want := `{"obj":null}`
|
||||
got := strings.TrimSpace(buf.String())
|
||||
if got != want {
|
||||
t.Errorf("Event.Object()\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("EmbedObjectWithNil", func(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
e := newEvent(LevelWriterAdapter{&buf}, DebugLevel, false, nil, nil)
|
||||
e = e.EmbedObject(nil)
|
||||
err := e.write()
|
||||
if err != nil {
|
||||
t.Errorf("Event.EmbedObject() error: %v", err)
|
||||
}
|
||||
|
||||
want := "{}"
|
||||
got := strings.TrimSpace(buf.String())
|
||||
if got != want {
|
||||
t.Errorf("Event.EmbedObject()\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
})
|
||||
|
||||
type contextKeyType struct{}
|
||||
var contextKey = contextKeyType{}
|
||||
|
||||
called := false
|
||||
ctxHook := HookFunc(func(e *Event, level Level, message string) {
|
||||
called = true
|
||||
ctx := e.GetCtx()
|
||||
if ctx == nil {
|
||||
t.Errorf("expected context to be set in Event")
|
||||
}
|
||||
val := ctx.Value(contextKey)
|
||||
if val == nil {
|
||||
t.Errorf("expected context value, got %v", val)
|
||||
}
|
||||
e.Str("ctxValue", val.(string))
|
||||
e.Bool("stackValue", e.stack)
|
||||
})
|
||||
|
||||
t.Run("ObjectWithFullContext", func(t *testing.T) {
|
||||
called = false
|
||||
ctx := context.WithValue(context.Background(), contextKey, "ctx-object")
|
||||
|
||||
var buf bytes.Buffer
|
||||
e := newEvent(LevelWriterAdapter{&buf}, DebugLevel, true, ctx, []Hook{ctxHook})
|
||||
e = e.Object("obj", loggableObject{member: "object-value"})
|
||||
e.Msg("hello")
|
||||
|
||||
if !called {
|
||||
t.Errorf("hook was not called")
|
||||
}
|
||||
|
||||
want := `{"obj":{"member":"object-value"},"ctxValue":"ctx-object","stackValue":true,"message":"hello"}`
|
||||
got := strings.TrimSpace(buf.String())
|
||||
if got != want {
|
||||
t.Errorf("Event.EmbedObject()\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("EmbedObjectWithFullContext", func(t *testing.T) {
|
||||
called = false
|
||||
ctx := context.WithValue(context.Background(), contextKey, "ctx-embed")
|
||||
|
||||
var buf bytes.Buffer
|
||||
e := newEvent(LevelWriterAdapter{&buf}, DebugLevel, false, ctx, []Hook{ctxHook})
|
||||
e = e.EmbedObject(loggableObject{member: "embedded-value"})
|
||||
e.Msg("hello")
|
||||
|
||||
if !called {
|
||||
t.Errorf("hook was not called")
|
||||
}
|
||||
|
||||
want := `{"member":"embedded-value","ctxValue":"ctx-embed","stackValue":false,"message":"hello"}`
|
||||
got := strings.TrimSpace(buf.String())
|
||||
if got != want {
|
||||
t.Errorf("Event.EmbedObject()\ngot: %s\nwant: %s", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestEvent_WithNilEvent(t *testing.T) {
|
||||
@@ -83,7 +163,7 @@ func TestEvent_WithNilEvent(t *testing.T) {
|
||||
fixtures := makeFieldFixtures()
|
||||
types := map[string]func() *Event{
|
||||
"Array": func() *Event {
|
||||
arr := Arr()
|
||||
arr := e.CreateArray()
|
||||
return e.Array("k", arr)
|
||||
},
|
||||
"Bool": func() *Event {
|
||||
@@ -198,7 +278,7 @@ func TestEvent_WithNilEvent(t *testing.T) {
|
||||
return e.Times("k", fixtures.Times)
|
||||
},
|
||||
"Dict": func() *Event {
|
||||
d := Dict()
|
||||
d := e.CreateDict()
|
||||
d.Str("greeting", "hello")
|
||||
return e.Dict("k", d)
|
||||
},
|
||||
@@ -289,7 +369,7 @@ func TestEvent_WithNilEvent(t *testing.T) {
|
||||
|
||||
func TestEvent_MsgFunc(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
e := newEvent(LevelWriterAdapter{&buf}, DebugLevel)
|
||||
e := newEvent(LevelWriterAdapter{&buf}, DebugLevel, false, nil, nil)
|
||||
|
||||
called := false
|
||||
e.MsgFunc(func() string {
|
||||
@@ -308,7 +388,7 @@ func TestEvent_MsgFunc(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEvent_DoneHandler(t *testing.T) {
|
||||
e := newEvent(nil, InfoLevel)
|
||||
e := newEvent(nil, InfoLevel, false, nil, nil)
|
||||
|
||||
// Set up a done handler to capture calls
|
||||
var called bool
|
||||
@@ -351,7 +431,7 @@ func TestEvent_Msg_ErrorHandlerNil(t *testing.T) {
|
||||
// Create a LevelWriter that always returns an error
|
||||
mockWriter := &badLevelWriter{err: errors.New("write error")}
|
||||
|
||||
e := newEvent(mockWriter, InfoLevel)
|
||||
e := newEvent(mockWriter, InfoLevel, false, nil, nil)
|
||||
if e == nil {
|
||||
t.Fatal("Event should not be nil")
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package zerolog
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net"
|
||||
"sort"
|
||||
"time"
|
||||
@@ -12,13 +14,13 @@ func isNilValue(i interface{}) bool {
|
||||
return (*[2]uintptr)(unsafe.Pointer(&i))[1] == 0
|
||||
}
|
||||
|
||||
func appendFields(dst []byte, fields interface{}, stack bool) []byte {
|
||||
func appendFields(dst []byte, fields interface{}, stack bool, ctx context.Context, hooks []Hook) []byte {
|
||||
switch fields := fields.(type) {
|
||||
case []interface{}:
|
||||
if n := len(fields); n&0x1 == 1 { // odd number
|
||||
fields = fields[:n-1]
|
||||
}
|
||||
dst = appendFieldList(dst, fields, stack)
|
||||
dst = appendFieldList(dst, fields, stack, ctx, hooks)
|
||||
case map[string]interface{}:
|
||||
keys := make([]string, 0, len(fields))
|
||||
for key := range fields {
|
||||
@@ -28,14 +30,14 @@ func appendFields(dst []byte, fields interface{}, stack bool) []byte {
|
||||
kv := make([]interface{}, 2)
|
||||
for _, key := range keys {
|
||||
kv[0], kv[1] = key, fields[key]
|
||||
dst = appendFieldList(dst, kv, stack)
|
||||
dst = appendFieldList(dst, kv, stack, ctx, hooks)
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendObject(dst []byte, obj LogObjectMarshaler) []byte {
|
||||
e := newEvent(nil, 0)
|
||||
func appendObject(dst []byte, obj LogObjectMarshaler, stack bool, ctx context.Context, hooks []Hook) []byte {
|
||||
e := newEvent(LevelWriterAdapter{io.Discard}, DebugLevel, stack, ctx, hooks)
|
||||
e.buf = e.buf[:0] // discard the beginning marker added by newEvent
|
||||
e.appendObject(obj)
|
||||
dst = append(dst, e.buf...)
|
||||
@@ -43,7 +45,7 @@ func appendObject(dst []byte, obj LogObjectMarshaler) []byte {
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte {
|
||||
func appendFieldList(dst []byte, kvList []interface{}, stack bool, ctx context.Context, hooks []Hook) []byte {
|
||||
for i, n := 0, len(kvList); i < n; i += 2 {
|
||||
key, val := kvList[i], kvList[i+1]
|
||||
if key, ok := key.(string); ok {
|
||||
@@ -51,10 +53,6 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte {
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
if val, ok := val.(LogObjectMarshaler); ok {
|
||||
dst = appendObject(dst, val)
|
||||
continue
|
||||
}
|
||||
switch val := val.(type) {
|
||||
case string:
|
||||
dst = enc.AppendString(dst, val)
|
||||
@@ -62,12 +60,12 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte {
|
||||
dst = enc.AppendBytes(dst, val)
|
||||
case error:
|
||||
switch m := ErrorMarshalFunc(val).(type) {
|
||||
case nil:
|
||||
dst = enc.AppendNil(dst)
|
||||
case LogObjectMarshaler:
|
||||
dst = appendObject(dst, m)
|
||||
dst = appendObject(dst, m, stack, ctx, hooks)
|
||||
case error:
|
||||
if m == nil || isNilValue(m) {
|
||||
dst = enc.AppendNil(dst)
|
||||
} else {
|
||||
if !isNilValue(m) {
|
||||
dst = enc.AppendString(dst, m.Error())
|
||||
}
|
||||
case string:
|
||||
@@ -77,16 +75,20 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte {
|
||||
}
|
||||
|
||||
if stack && ErrorStackMarshaler != nil {
|
||||
dst = enc.AppendKey(dst, ErrorStackFieldName)
|
||||
switch m := ErrorStackMarshaler(val).(type) {
|
||||
case nil:
|
||||
// do nothing
|
||||
case LogObjectMarshaler:
|
||||
dst = enc.AppendKey(dst, ErrorStackFieldName)
|
||||
dst = appendObject(dst, m, stack, ctx, hooks)
|
||||
case error:
|
||||
if m != nil && !isNilValue(m) {
|
||||
dst = enc.AppendString(dst, m.Error())
|
||||
}
|
||||
dst = enc.AppendKey(dst, ErrorStackFieldName)
|
||||
dst = enc.AppendString(dst, m.Error())
|
||||
case string:
|
||||
dst = enc.AppendKey(dst, ErrorStackFieldName)
|
||||
dst = enc.AppendString(dst, m)
|
||||
default:
|
||||
dst = enc.AppendKey(dst, ErrorStackFieldName)
|
||||
dst = enc.AppendInterface(dst, m)
|
||||
}
|
||||
}
|
||||
@@ -94,12 +96,12 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte {
|
||||
dst = enc.AppendArrayStart(dst)
|
||||
for i, err := range val {
|
||||
switch m := ErrorMarshalFunc(err).(type) {
|
||||
case nil:
|
||||
dst = enc.AppendNil(dst)
|
||||
case LogObjectMarshaler:
|
||||
dst = appendObject(dst, m)
|
||||
dst = appendObject(dst, m, stack, ctx, hooks)
|
||||
case error:
|
||||
if m == nil || isNilValue(m) {
|
||||
dst = enc.AppendNil(dst)
|
||||
} else {
|
||||
if !isNilValue(m) {
|
||||
dst = enc.AppendString(dst, m.Error())
|
||||
}
|
||||
case string:
|
||||
@@ -116,7 +118,7 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte {
|
||||
case []LogObjectMarshaler:
|
||||
dst = enc.AppendArrayStart(dst)
|
||||
for i, obj := range val {
|
||||
dst = appendObject(dst, obj)
|
||||
dst = appendObject(dst, obj, stack, ctx, hooks)
|
||||
if i < (len(val) - 1) {
|
||||
dst = enc.AppendArrayDelim(dst)
|
||||
}
|
||||
@@ -294,7 +296,11 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte {
|
||||
case json.RawMessage:
|
||||
dst = appendJSON(dst, val)
|
||||
default:
|
||||
dst = enc.AppendInterface(dst, val)
|
||||
if lom, ok := val.(LogObjectMarshaler); ok {
|
||||
dst = appendObject(dst, lom, stack, ctx, hooks)
|
||||
} else {
|
||||
dst = enc.AppendInterface(dst, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
return dst
|
||||
|
||||
+1
-1
@@ -120,7 +120,7 @@ func makeFieldFixtures() *fieldFixtures {
|
||||
ipPfxV6 := net.IPNet{IP: net.IP{0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x00}, Mask: net.CIDRMask(64, 128)}
|
||||
ipPfxs := []net.IPNet{ipPfxV4, ipPfxV6, ipPfxV4, ipPfxV6, ipPfxV4, ipPfxV6, ipPfxV4, ipPfxV6, ipPfxV4, ipPfxV6}
|
||||
macAddr := net.HardwareAddr{0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E}
|
||||
errs := []error{errors.New("a"), errors.New("b"), errors.New("c"), errors.New("d"), errors.New("e"), nil, errorObjectMarshalerImpl{fmt.Errorf("oops")}}
|
||||
errs := []error{errors.New("a"), errors.New("b"), errors.New("c"), errors.New("d"), errors.New("e"), nil, loggableError{fmt.Errorf("oops")}}
|
||||
ctx := context.Background()
|
||||
stringers := []fmt.Stringer{ipAddrs[0], durations[0]}
|
||||
rawJSONs := [][]byte{[]byte(`{"some":"json"}`), []byte(`{"longer":[1111,2222,3333,4444,5555]}`)}
|
||||
|
||||
@@ -487,22 +487,21 @@ func (l *Logger) newEvent(level Level, done func(string)) *Event {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
e := newEvent(l.w, level)
|
||||
e := newEvent(l.w, level, l.stack, l.ctx, l.hooks)
|
||||
e.done = done
|
||||
e.ch = l.hooks
|
||||
e.ctx = l.ctx
|
||||
if level != NoLevel && LevelFieldName != "" {
|
||||
e.Str(LevelFieldName, LevelFieldMarshalFunc(level))
|
||||
}
|
||||
if len(l.context) > 1 {
|
||||
e.buf = enc.AppendObjectData(e.buf, l.context)
|
||||
}
|
||||
if l.stack {
|
||||
e.Stack()
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func (l *Logger) scratchEvent() *Event {
|
||||
return newEvent(LevelWriterAdapter{io.Discard}, DebugLevel, l.stack, l.ctx, l.hooks)
|
||||
}
|
||||
|
||||
// should returns true if the log event should be logged.
|
||||
func (l *Logger) should(lvl Level) bool {
|
||||
if l.w == nil {
|
||||
|
||||
+34
-30
@@ -192,12 +192,13 @@ func ExampleLogger_Log() {
|
||||
func ExampleEvent_Dict() {
|
||||
log := zerolog.New(os.Stdout)
|
||||
|
||||
log.Log().
|
||||
Str("foo", "bar").
|
||||
Dict("dict", zerolog.Dict().
|
||||
Str("bar", "baz").
|
||||
Int("n", 1),
|
||||
).
|
||||
e := log.Log().
|
||||
Str("foo", "bar")
|
||||
|
||||
e.Dict("dict", e.CreateDict().
|
||||
Str("bar", "baz").
|
||||
Int("n", 1),
|
||||
).
|
||||
Msg("hello world")
|
||||
|
||||
// Output: {"foo":"bar","dict":{"bar":"baz","n":1},"message":"hello world"}
|
||||
@@ -242,16 +243,17 @@ func (uu Users) MarshalZerologArray(a *zerolog.Array) {
|
||||
func ExampleEvent_Array() {
|
||||
log := zerolog.New(os.Stdout)
|
||||
|
||||
log.Log().
|
||||
Str("foo", "bar").
|
||||
Array("array", zerolog.Arr().
|
||||
Str("baz").
|
||||
Int(1).
|
||||
Dict(zerolog.Dict().
|
||||
Str("bar", "baz").
|
||||
Int("n", 1),
|
||||
),
|
||||
).
|
||||
e := log.Log().
|
||||
Str("foo", "bar")
|
||||
|
||||
e.Array("array", e.CreateArray().
|
||||
Str("baz").
|
||||
Int(1).
|
||||
Dict(e.CreateDict().
|
||||
Str("bar", "baz").
|
||||
Int("n", 1),
|
||||
),
|
||||
).
|
||||
Msg("hello world")
|
||||
|
||||
// Output: {"foo":"bar","array":["baz",1,{"bar":"baz","n":1}],"message":"hello world"}
|
||||
@@ -380,27 +382,29 @@ func ExampleEvent_Fields_slice() {
|
||||
}
|
||||
|
||||
func ExampleContext_Dict() {
|
||||
log := zerolog.New(os.Stdout).With().
|
||||
Str("foo", "bar").
|
||||
Dict("dict", zerolog.Dict().
|
||||
Str("bar", "baz").
|
||||
Int("n", 1),
|
||||
).Logger()
|
||||
ctx := zerolog.New(os.Stdout).With().
|
||||
Str("foo", "bar")
|
||||
|
||||
log.Log().Msg("hello world")
|
||||
logger := ctx.Dict("dict", ctx.CreateDict().
|
||||
Str("bar", "baz").
|
||||
Int("n", 1),
|
||||
).Logger()
|
||||
|
||||
logger.Log().Msg("hello world")
|
||||
|
||||
// Output: {"foo":"bar","dict":{"bar":"baz","n":1},"message":"hello world"}
|
||||
}
|
||||
|
||||
func ExampleContext_Array() {
|
||||
log := zerolog.New(os.Stdout).With().
|
||||
Str("foo", "bar").
|
||||
Array("array", zerolog.Arr().
|
||||
Str("baz").
|
||||
Int(1),
|
||||
).Logger()
|
||||
ctx := zerolog.New(os.Stdout).With().
|
||||
Str("foo", "bar")
|
||||
|
||||
log.Log().Msg("hello world")
|
||||
logger := ctx.Array("array", ctx.CreateArray().
|
||||
Str("baz").
|
||||
Int(1),
|
||||
).Logger()
|
||||
|
||||
logger.Log().Msg("hello world")
|
||||
|
||||
// Output: {"foo":"bar","array":["baz",1],"message":"hello world"}
|
||||
}
|
||||
|
||||
+12
-368
@@ -163,7 +163,7 @@ func TestWithPlurals(t *testing.T) {
|
||||
Strs("strings_nil", nil).
|
||||
Stringers("stringers", []fmt.Stringer{net.IP{127, 0, 0, 1}, nil}).
|
||||
Stringers("stringers_nil", nil).
|
||||
Errs("errs", []error{errors.New("some error"), errors.New("some other error"), nil, errorObjectMarshalerImpl{fmt.Errorf("oops")}}).
|
||||
Errs("errs", []error{errors.New("some error"), errors.New("some other error"), nil, loggableError{fmt.Errorf("oops")}, nonLoggableError{fmt.Errorf("whoops"), 401}}).
|
||||
Bools("bool", []bool{true, false}).
|
||||
Ints("int", []int{1, 2}).
|
||||
Ints8("int8", []int8{2, 3}).
|
||||
@@ -182,7 +182,7 @@ func TestWithPlurals(t *testing.T) {
|
||||
log := ctx.Logger()
|
||||
log.Log().Msg("")
|
||||
if got, want := decodeIfBinaryToString(out.Bytes()),
|
||||
`{"strings":["foo","bar"],"strings_nil":[],"stringers":["127.0.0.1",null],"stringers_nil":null,"errs":["some error","some other error",null,{"error":"OOPS"}],"bool":[true,false],"int":[1,2],"int8":[2,3],"int16":[3,4],"int32":[4,5],"int64":[5,6],"uint":[6,7],"uint8":[7,8],"uint16":[8,9],"uint32":[9,10],"uint64":[10,11],"float32":[1.1,2.2],"float64":[2.2,3.3],"time":["0001-02-03T00:00:00Z","0005-06-07T00:00:00Z"],"dur":[1000,2000]}`+"\n"; got != want {
|
||||
`{"strings":["foo","bar"],"strings_nil":[],"stringers":["127.0.0.1",null],"stringers_nil":null,"errs":["some error","some other error",null,{"l":"OOPS"},"whoops"],"bool":[true,false],"int":[1,2],"int8":[2,3],"int16":[3,4],"int32":[4,5],"int64":[5,6],"uint":[6,7],"uint8":[7,8],"uint16":[8,9],"uint32":[9,10],"uint64":[10,11],"float32":[1.1,2.2],"float64":[2.2,3.3],"time":["0001-02-03T00:00:00Z","0005-06-07T00:00:00Z"],"dur":[1000,2000]}`+"\n"; got != want {
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
}
|
||||
@@ -268,7 +268,7 @@ func TestFieldsMap_Arrays(t *testing.T) {
|
||||
"times": []time.Time{{}},
|
||||
"objs": []fixtureObj{{"a", "b", 1}},
|
||||
}).Msg("")
|
||||
// special case: []uint8 is logged as base64 string so we use "," for 44
|
||||
// special case: []uint8 are logged as base64 string so we use "," for 44
|
||||
if got, want := decodeIfBinaryToString(out.Bytes()), `{"bools":[true],"durs":[1000],"errors":["some error"],"floats32":[11],"floats64":[12],"ints":[1],"ints16":[3],"ints32":[4],"ints64":[5],"ints8":[1],"ipnets":["2001:db8:85a3::8a2e:370:7334/64"],"ipv6s":["2001:db8:85a3::8a2e:370:7334"],"macaddrs":["ABorPE1e"],"objs":[{"Pub":"a","tag":"b"}],"strings":["foo"],"times":["0001-01-01T00:00:00Z"],"uint8s":",","uints":[6],"uints16":[8],"uints32":[9],"uints64":[10]}`+"\n"; got != want {
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
@@ -278,13 +278,13 @@ func TestFieldsErr(t *testing.T) {
|
||||
out := &bytes.Buffer{}
|
||||
log := New(out)
|
||||
log.Log().Fields(map[string]interface{}{
|
||||
"nil": nil,
|
||||
"nilerror": err,
|
||||
"error": errors.New("some error"),
|
||||
"loggable": loggableError{errors.New("loggable")},
|
||||
"marshal": errorObjectMarshalerImpl{fmt.Errorf("oops")},
|
||||
"nil": nil,
|
||||
"nilerror": err,
|
||||
"error": errors.New("some error"),
|
||||
"loggable": loggableError{errors.New("loggable")},
|
||||
"non-loggable": nonLoggableError{fmt.Errorf("oops"), 401},
|
||||
}).Msg("")
|
||||
if got, want := decodeIfBinaryToString(out.Bytes()), `{"error":"some error","loggable":{"message":"loggable loggableError"},"marshal":{"error":"OOPS"},"nil":null,"nilerror":null}`+"\n"; got != want {
|
||||
if got, want := decodeIfBinaryToString(out.Bytes()), `{"error":"some error","loggable":{"l":"LOGGABLE"},"nil":null,"nilerror":null,"non-loggable":"oops"}`+"\n"; got != want {
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
}
|
||||
@@ -293,9 +293,9 @@ func TestFieldsErrs(t *testing.T) {
|
||||
out := &bytes.Buffer{}
|
||||
log := New(out)
|
||||
log.Log().Fields(map[string]interface{}{
|
||||
"errors": []error{errors.New("some error"), nil, err, loggableError{errors.New("loggable")}, errorObjectMarshalerImpl{fmt.Errorf("oops")}},
|
||||
"errors": []error{errors.New("some error"), nil, err, loggableError{errors.New("loggable")}, nonLoggableError{fmt.Errorf("oops"), 404}},
|
||||
}).Msg("")
|
||||
if got, want := decodeIfBinaryToString(out.Bytes()), `{"errors":["some error",null,null,{"message":"loggable loggableError"},{"error":"OOPS"}]}`+"\n"; got != want {
|
||||
if got, want := decodeIfBinaryToString(out.Bytes()), `{"errors":["some error",null,null,{"l":"LOGGABLE"},"oops"]}`+"\n"; got != want {
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
}
|
||||
}
|
||||
@@ -606,6 +606,7 @@ func TestFieldsDisabled(t *testing.T) {
|
||||
Ctx(context.Background()).
|
||||
Any("any", struct{ A string }{"test"}).
|
||||
Interface("interface", fixtureObj{"a", "z", 1}).
|
||||
Err(errors.New("some error")).
|
||||
Msg("")
|
||||
if got, want := decodeIfBinaryToString(out.Bytes()), ""; got != want {
|
||||
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
|
||||
@@ -863,363 +864,6 @@ func TestOutputWithTimestamp(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type loggableError struct {
|
||||
error
|
||||
}
|
||||
|
||||
func (l loggableError) MarshalZerologObject(e *Event) {
|
||||
if l.error == nil {
|
||||
return
|
||||
}
|
||||
e.Str("message", l.error.Error()+" loggableError")
|
||||
}
|
||||
|
||||
type nonLoggable struct {
|
||||
where string
|
||||
how int
|
||||
what string
|
||||
}
|
||||
type wrappedError struct {
|
||||
error
|
||||
msg string
|
||||
}
|
||||
|
||||
func (w wrappedError) Error() string {
|
||||
if w.error == nil {
|
||||
return w.msg
|
||||
}
|
||||
return w.error.Error() + ": " + w.msg
|
||||
}
|
||||
|
||||
func TestErrorMarshalFunc_Default(t *testing.T) {
|
||||
// test default behaviour
|
||||
testErrorMarshalFunc(t, nil, "default",
|
||||
"",
|
||||
"null",
|
||||
|
||||
`"zot"`,
|
||||
`"zot"`,
|
||||
|
||||
`{"message":"log loggableError"}`,
|
||||
`{"message":"log loggableError"}`,
|
||||
|
||||
"[]",
|
||||
`"foo","bar"`,
|
||||
)
|
||||
}
|
||||
func TestErrorMarshalFunc_AppendedString(t *testing.T) {
|
||||
// test returning an appended string from ErrorMarshalFunc
|
||||
testErrorMarshalFunc(t, func(err error) interface{} {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return err.Error() + ": marshaled"
|
||||
}, "appended string",
|
||||
"",
|
||||
"null",
|
||||
|
||||
`"zot: marshaled"`,
|
||||
`"zot: marshaled"`,
|
||||
|
||||
`"log: marshaled"`,
|
||||
`{"message":"log loggableError"}`,
|
||||
|
||||
"[]",
|
||||
`"foo: marshaled","bar: marshaled"`,
|
||||
)
|
||||
}
|
||||
func TestErrorMarshalFunc_NilError(t *testing.T) {
|
||||
// test returning an nil error from ErrorMarshalFunc
|
||||
testErrorMarshalFunc(t, func(err error) interface{} {
|
||||
return error(nil)
|
||||
}, "nil error",
|
||||
"",
|
||||
"null",
|
||||
|
||||
"",
|
||||
"null",
|
||||
|
||||
"",
|
||||
`{"message":"log loggableError"}`,
|
||||
|
||||
"[]",
|
||||
"null,null",
|
||||
)
|
||||
}
|
||||
|
||||
func TestErrorMarshalFunc_UntypedNil(t *testing.T) {
|
||||
// test returning an untyped nil from ErrorMarshalFunc
|
||||
testErrorMarshalFunc(t, func(err error) interface{} {
|
||||
return nil
|
||||
}, "untyped nil",
|
||||
"",
|
||||
"null",
|
||||
|
||||
"",
|
||||
"null",
|
||||
|
||||
"",
|
||||
`{"message":"log loggableError"}`,
|
||||
|
||||
"[]",
|
||||
"null,null",
|
||||
)
|
||||
}
|
||||
|
||||
func TestErrorMarshalFunc_WrappedError(t *testing.T) {
|
||||
// test returning an wrapped error from ErrorMarshalFunc
|
||||
testErrorMarshalFunc(t, func(err error) interface{} {
|
||||
if err == nil {
|
||||
return nil
|
||||
} else if we, ok := err.(wrappedError); ok {
|
||||
return we
|
||||
} else {
|
||||
return wrappedError{err, "addendum"}
|
||||
}
|
||||
}, "wrapped error",
|
||||
"",
|
||||
"null",
|
||||
|
||||
`"zot: addendum"`,
|
||||
`"zot: addendum"`,
|
||||
|
||||
`"log: addendum"`,
|
||||
`{"message":"log loggableError"}`,
|
||||
|
||||
"[]",
|
||||
`"foo: addendum","bar: addendum"`,
|
||||
)
|
||||
}
|
||||
|
||||
func TestErrorMarshalFunc_LoggableType(t *testing.T) {
|
||||
// test returning a loggable type from ErrorMarshalFunc
|
||||
testErrorMarshalFunc(t, func(err error) interface{} {
|
||||
return loggableError{err}
|
||||
}, "loggable type",
|
||||
"{}",
|
||||
"null",
|
||||
|
||||
`{"message":"zot loggableError"}`,
|
||||
`{"message":"zot loggableError"}`,
|
||||
|
||||
`{"message":"log loggableError"}`,
|
||||
`{"message":"log loggableError"}`,
|
||||
|
||||
"[]",
|
||||
`{"message":"foo loggableError"},{"message":"bar loggableError"}`,
|
||||
)
|
||||
}
|
||||
func TestErrorMarshalFunc_String(t *testing.T) {
|
||||
// test returning a string type from ErrorMarshalFunc
|
||||
testErrorMarshalFunc(t, func(err error) interface{} {
|
||||
return "i'm an err" // return just a string
|
||||
}, "string type",
|
||||
`"i'm an err"`,
|
||||
"null",
|
||||
|
||||
`"i'm an err"`,
|
||||
`"i'm an err"`,
|
||||
|
||||
`"i'm an err"`,
|
||||
`{"message":"log loggableError"}`,
|
||||
|
||||
"[]",
|
||||
`"i'm an err","i'm an err"`,
|
||||
)
|
||||
}
|
||||
|
||||
func TestErrorMarshalFunc_NonLoggableType(t *testing.T) {
|
||||
// test returning a non-loggable type from ErrorMarshalFunc
|
||||
testErrorMarshalFunc(t, func(err error) interface{} {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return nonLoggable{where: "here", how: 42, what: err.Error()}
|
||||
}, "non-loggable type",
|
||||
"",
|
||||
"null",
|
||||
|
||||
"{}",
|
||||
"{}",
|
||||
|
||||
"{}",
|
||||
`{"message":"log loggableError"}`,
|
||||
|
||||
"[]",
|
||||
"{},{}",
|
||||
)
|
||||
}
|
||||
|
||||
func TestErrorMarshalFunc_NilMarshal(t *testing.T) {
|
||||
// test returning a nil from ErrorMarshalFunc
|
||||
testErrorMarshalFunc(t, func(err error) interface{} {
|
||||
var nilerr error = nil
|
||||
return nilerr
|
||||
}, "nil-marshal",
|
||||
"",
|
||||
"null",
|
||||
|
||||
"",
|
||||
"null",
|
||||
|
||||
"",
|
||||
`{"message":"log loggableError"}`,
|
||||
|
||||
"[]",
|
||||
"null,null",
|
||||
)
|
||||
}
|
||||
|
||||
func testErrorMarshalFunc(t *testing.T,
|
||||
errFunc func(err error) interface{},
|
||||
testcase string,
|
||||
|
||||
whenNil string,
|
||||
whenNilField string,
|
||||
|
||||
hasValue string,
|
||||
hasValueField string,
|
||||
|
||||
whenLoggable string,
|
||||
whenLoggableField string,
|
||||
|
||||
errsNilValue string,
|
||||
errsValue string,
|
||||
) {
|
||||
const suffix = `"message":"msg"}`
|
||||
|
||||
if errFunc != nil {
|
||||
originalErrorMarshalFunc := ErrorMarshalFunc
|
||||
defer func() {
|
||||
ErrorMarshalFunc = originalErrorMarshalFunc
|
||||
}()
|
||||
|
||||
ErrorMarshalFunc = errFunc
|
||||
}
|
||||
|
||||
var err error
|
||||
wantNil := `{`
|
||||
if whenNil != "" {
|
||||
wantNil = wantNil + `"error":` + whenNil + `,`
|
||||
}
|
||||
wantNil = wantNil + suffix
|
||||
|
||||
wantNilField := `{"err":` + whenNilField + `,` + suffix
|
||||
err = nil
|
||||
testContextErrorMarshalFunc(t, testcase+" / context.Err(nil)", wantNil, func(ctx Context) Context {
|
||||
ctx = ctx.Err(err)
|
||||
return ctx
|
||||
})
|
||||
testEventErrorMarshalFunc(t, testcase+" / event.Err(nil)", wantNil, func(e *Event) *Event {
|
||||
e.Err(err)
|
||||
return e
|
||||
})
|
||||
testFieldsErrorMarshalFunc(t, testcase+" / field.Err(nil)", wantNilField, func(e *Event) *Event {
|
||||
e.Fields(map[string]interface{}{"err": err})
|
||||
return e
|
||||
})
|
||||
|
||||
wantErr := `{`
|
||||
if hasValue != "" {
|
||||
wantErr = wantErr + `"error":` + hasValue + `,`
|
||||
}
|
||||
wantErr = wantErr + suffix
|
||||
wantErrField := `{"err":` + hasValueField + `,` + suffix
|
||||
err = errors.New("zot")
|
||||
testContextErrorMarshalFunc(t, testcase+" / context.Err(error)", wantErr, func(ctx Context) Context {
|
||||
ctx = ctx.Err(err)
|
||||
return ctx
|
||||
})
|
||||
testEventErrorMarshalFunc(t, testcase+" / event.Err(error)", wantErr, func(e *Event) *Event {
|
||||
e.Err(err)
|
||||
return e
|
||||
})
|
||||
testFieldsErrorMarshalFunc(t, testcase+" / field.Err(error)", wantErrField, func(e *Event) *Event {
|
||||
e.Fields(map[string]interface{}{"err": err})
|
||||
return e
|
||||
})
|
||||
|
||||
wantLoggable := `{`
|
||||
if whenLoggable != "" {
|
||||
wantLoggable = wantLoggable + `"error":` + whenLoggable + `,`
|
||||
}
|
||||
wantLoggable = wantLoggable + suffix
|
||||
wantLoggableField := `{"err":` + whenLoggableField + `,` + suffix
|
||||
err = loggableError{errors.New("log")}
|
||||
testContextErrorMarshalFunc(t, testcase+" / context.Err(loggable)", wantLoggable, func(ctx Context) Context {
|
||||
ctx = ctx.Err(err)
|
||||
return ctx
|
||||
})
|
||||
testEventErrorMarshalFunc(t, testcase+" / event.Err(loggable)", wantLoggable, func(e *Event) *Event {
|
||||
e.Err(err)
|
||||
return e
|
||||
})
|
||||
testFieldsErrorMarshalFunc(t, testcase+" / field.Err(loggable)", wantLoggableField, func(e *Event) *Event {
|
||||
e.Fields(map[string]interface{}{"err": err})
|
||||
return e
|
||||
})
|
||||
|
||||
wantErrsNil := `{"errs":` + errsNilValue + `,` + suffix
|
||||
var errs []error = nil
|
||||
testContextErrorMarshalFunc(t, testcase+" / context.Errs(nil)", wantErrsNil, func(ctx Context) Context {
|
||||
ctx = ctx.Errs("errs", errs)
|
||||
return ctx
|
||||
})
|
||||
testEventErrorMarshalFunc(t, testcase+" / event.Errs(nil)", wantErrsNil, func(e *Event) *Event {
|
||||
e.Errs("errs", errs)
|
||||
return e
|
||||
})
|
||||
testFieldsErrorMarshalFunc(t, testcase+" / field.Errs(nil)", wantErrsNil, func(e *Event) *Event {
|
||||
e.Fields(map[string]interface{}{"errs": errs})
|
||||
return e
|
||||
})
|
||||
|
||||
wantErrs := `{"errs":[` + errsValue + `],` + suffix
|
||||
errs = []error{errors.New("foo"), errors.New("bar")}
|
||||
testContextErrorMarshalFunc(t, testcase+" / context.Errs([])", wantErrs, func(ctx Context) Context {
|
||||
ctx = ctx.Errs("errs", []error{errors.New("foo"), errors.New("bar")})
|
||||
return ctx
|
||||
})
|
||||
testEventErrorMarshalFunc(t, testcase+" / event.Errs([])", wantErrs, func(e *Event) *Event {
|
||||
e.Errs("errs", errs)
|
||||
return e
|
||||
})
|
||||
testFieldsErrorMarshalFunc(t, testcase+" / field.Errs([])", wantErrs, func(e *Event) *Event {
|
||||
e.Fields(map[string]interface{}{"errs": errs})
|
||||
return e
|
||||
})
|
||||
}
|
||||
|
||||
func testEventErrorMarshalFunc(t *testing.T, testcase string, wants string, test func(e *Event) *Event) {
|
||||
out := &bytes.Buffer{}
|
||||
logger := New(out)
|
||||
test(logger.Log()).Msg("msg")
|
||||
if got, want := decodeIfBinaryToString(out.Bytes()), wants+"\n"; got != want {
|
||||
t.Errorf("%s output:\ngot: %v\nwant: %v", testcase, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func testFieldsErrorMarshalFunc(t *testing.T, testcase string, wants string, test func(e *Event) *Event) {
|
||||
out := &bytes.Buffer{}
|
||||
logger := New(out)
|
||||
test(logger.Log()).Msg("msg")
|
||||
if got, want := decodeIfBinaryToString(out.Bytes()), wants+"\n"; got != want {
|
||||
t.Errorf("%s output:\ngot: %v\nwant: %v", testcase, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func testContextErrorMarshalFunc(t *testing.T, testcase string, wants string, test func(ctx Context) Context) {
|
||||
out := &bytes.Buffer{}
|
||||
ctx := New(out).With()
|
||||
|
||||
ctx = test(ctx)
|
||||
logger := ctx.Logger()
|
||||
logger.Log().Msg("msg")
|
||||
if got, want := decodeIfBinaryToString(out.Bytes()), wants+"\n"; got != want {
|
||||
t.Errorf("%s output:\ngot: %v\nwant: %v", testcase, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCallerMarshalFunc(t *testing.T) {
|
||||
out := &bytes.Buffer{}
|
||||
log := New(out)
|
||||
|
||||
Reference in New Issue
Block a user