Skip to content

Commit

Permalink
feat: display error stack when using .Fields() (#560)
Browse files Browse the repository at this point in the history
  • Loading branch information
julienrbrt committed Oct 4, 2023
1 parent 9e34cb4 commit ed609e7
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 7 deletions.
2 changes: 1 addition & 1 deletion context.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,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.context = appendFields(c.l.context, fields, c.l.stack)
return c
}

Expand Down
2 changes: 1 addition & 1 deletion event.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func (e *Event) Fields(fields interface{}) *Event {
if e == nil {
return e
}
e.buf = appendFields(e.buf, fields)
e.buf = appendFields(e.buf, fields, e.stack)
return e
}

Expand Down
23 changes: 19 additions & 4 deletions fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ func isNilValue(i interface{}) bool {
return (*[2]uintptr)(unsafe.Pointer(&i))[1] == 0
}

func appendFields(dst []byte, fields interface{}) []byte {
func appendFields(dst []byte, fields interface{}, stack bool) []byte {
switch fields := fields.(type) {
case []interface{}:
if n := len(fields); n&0x1 == 1 { // odd number
fields = fields[:n-1]
}
dst = appendFieldList(dst, fields)
dst = appendFieldList(dst, fields, stack)
case map[string]interface{}:
keys := make([]string, 0, len(fields))
for key := range fields {
Expand All @@ -28,13 +28,13 @@ func appendFields(dst []byte, fields interface{}) []byte {
kv := make([]interface{}, 2)
for _, key := range keys {
kv[0], kv[1] = key, fields[key]
dst = appendFieldList(dst, kv)
dst = appendFieldList(dst, kv, stack)
}
}
return dst
}

func appendFieldList(dst []byte, kvList []interface{}) []byte {
func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte {
for i, n := 0, len(kvList); i < n; i += 2 {
key, val := kvList[i], kvList[i+1]
if key, ok := key.(string); ok {
Expand Down Expand Up @@ -74,6 +74,21 @@ func appendFieldList(dst []byte, kvList []interface{}) []byte {
default:
dst = enc.AppendInterface(dst, m)
}

if stack && ErrorStackMarshaler != nil {
dst = enc.AppendKey(dst, ErrorStackFieldName)
switch m := ErrorStackMarshaler(val).(type) {
case nil:
case error:
if m != nil && !isNilValue(m) {
dst = enc.AppendString(dst, m.Error())
}
case string:
dst = enc.AppendString(dst, m)
default:
dst = enc.AppendInterface(dst, m)
}
}
case []error:
dst = enc.AppendArrayStart(dst)
for i, err := range val {
Expand Down
18 changes: 17 additions & 1 deletion pkgerrors/stacktrace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@ func TestLogStack(t *testing.T) {
}
}

func TestLogStackFields(t *testing.T) {
zerolog.ErrorStackMarshaler = MarshalStack

out := &bytes.Buffer{}
log := zerolog.New(out)

err := fmt.Errorf("from error: %w", errors.New("error message"))
log.Log().Stack().Fields([]interface{}{"error", err}).Msg("")

got := out.String()
want := `\{"error":"from error: error message","stack":\[\{"func":"TestLogStackFields","line":"37","source":"stacktrace_test.go"\},.*\]\}\n`
if ok, _ := regexp.MatchString(want, got); !ok {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
}

func TestLogStackFromContext(t *testing.T) {
zerolog.ErrorStackMarshaler = MarshalStack

Expand All @@ -38,7 +54,7 @@ func TestLogStackFromContext(t *testing.T) {
log.Log().Err(err).Msg("") // not explicitly calling Stack()

got := out.String()
want := `\{"stack":\[\{"func":"TestLogStackFromContext","line":"37","source":"stacktrace_test.go"\},.*\],"error":"from error: error message"\}\n`
want := `\{"stack":\[\{"func":"TestLogStackFromContext","line":"53","source":"stacktrace_test.go"\},.*\],"error":"from error: error message"\}\n`
if ok, _ := regexp.MatchString(want, got); !ok {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
Expand Down

0 comments on commit ed609e7

Please sign in to comment.