diff --git a/context.go b/context.go index 08c62fd..7cdd8cc 100644 --- a/context.go +++ b/context.go @@ -406,17 +406,9 @@ func (c Context) CallerWithSkipFrameCount(skipFrameCount int) Context { return c } -type stackTraceHook struct{} - -func (sh stackTraceHook) Run(e *Event, level Level, msg string) { - e.Stack() -} - -var sh = stackTraceHook{} - // Stack enables stack trace printing for the error passed to Err(). func (c Context) Stack() Context { - c.l = c.l.Hook(sh) + c.l.stack = true return c } diff --git a/log.go b/log.go index d02b15e..7927b2a 100644 --- a/log.go +++ b/log.go @@ -188,6 +188,7 @@ type Logger struct { sampler Sampler context []byte hooks []Hook + stack bool } // New creates a root logger with given output writer. If the output writer implements @@ -425,6 +426,9 @@ func (l *Logger) newEvent(level Level, done func(string)) *Event { if l.context != nil && len(l.context) > 1 { e.buf = enc.AppendObjectData(e.buf, l.context) } + if l.stack { + e.Stack() + } return e } diff --git a/pkgerrors/stacktrace_test.go b/pkgerrors/stacktrace_test.go index e771317..4f9838c 100644 --- a/pkgerrors/stacktrace_test.go +++ b/pkgerrors/stacktrace_test.go @@ -27,6 +27,22 @@ func TestLogStack(t *testing.T) { } } +func TestLogStackFromContext(t *testing.T) { + zerolog.ErrorStackMarshaler = MarshalStack + + out := &bytes.Buffer{} + log := zerolog.New(out).With().Stack().Logger() // calling Stack() on log context instead of event + + err := errors.Wrap(errors.New("error message"), "from error") + log.Log().Err(err).Msg("") // not explicitly calling Stack() + + got := out.String() + want := `\{"stack":\[\{"func":"TestLogStackFromContext","line":"36","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{}