diff --git a/context.go b/context.go index 48c1d5d3..0e4f44bb 100644 --- a/context.go +++ b/context.go @@ -163,6 +163,22 @@ func (c Context) Errs(key string, errs []error) Context { // Err adds the field "error" with serialized err to the logger context. func (c Context) Err(err error) Context { + if c.l.stack && ErrorStackMarshaler != nil { + switch m := ErrorStackMarshaler(err).(type) { + case nil: + case LogObjectMarshaler: + c = c.Object(ErrorStackFieldName, m) + case error: + if m != nil && !isNilValue(m) { + c = c.Str(ErrorStackFieldName, m.Error()) + } + case string: + c = c.Str(ErrorStackFieldName, m) + default: + c = c.Interface(ErrorStackFieldName, m) + } + } + return c.AnErr(ErrorFieldName, err) } diff --git a/diode/diode_test.go b/diode/diode_test.go index 87f62bcd..29b3f867 100644 --- a/diode/diode_test.go +++ b/diode/diode_test.go @@ -3,6 +3,7 @@ package diode_test import ( "bytes" "fmt" + "io" "log" "os" "testing" diff --git a/hlog/hlog_test.go b/hlog/hlog_test.go index 0d6b31ea..445d6b6f 100644 --- a/hlog/hlog_test.go +++ b/hlog/hlog_test.go @@ -7,6 +7,7 @@ import ( "bytes" "context" "fmt" + "io" "net/http" "net/http/httptest" "net/url" diff --git a/pkgerrors/stacktrace_test.go b/pkgerrors/stacktrace_test.go index a09b986f..787a0961 100644 --- a/pkgerrors/stacktrace_test.go +++ b/pkgerrors/stacktrace_test.go @@ -60,6 +60,22 @@ func TestLogStackFromContext(t *testing.T) { } } +func TestLogStackFromContextWith(t *testing.T) { + zerolog.ErrorStackMarshaler = MarshalStack + + err := fmt.Errorf("from error: %w", errors.New("error message")) + out := &bytes.Buffer{} + log := zerolog.New(out).With().Stack().Err(err).Logger() // calling Stack() on log context instead of event + + log.Error().Msg("") + + got := out.String() + want := `\{"level":"error","stack":\[\{"func":"TestLogStackFromContextWith","line":"66","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) + } +} + func BenchmarkLogStack(b *testing.B) { zerolog.ErrorStackMarshaler = MarshalStack out := &bytes.Buffer{}