Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(zapslog): implement stack trace handling #1339

Merged
merged 18 commits into from
Sep 1, 2023

Conversation

zekth
Copy link
Contributor

@zekth zekth commented Aug 23, 2023

fix: #1329

As discussed in the issue, replacing the HandlersOptions with functional options, i also renamed addSource to addCaller to properly match the zap semantic.

@CLAassistant
Copy link

CLAassistant commented Aug 23, 2023

CLA assistant check
All committers have signed the CLA.

stacktrace.go Outdated
@@ -125,6 +125,12 @@ func (st *stacktrace) Next() (_ runtime.Frame, more bool) {
return st.frames.Next()
}

// TakeStacktrace returns the stack trace,
// and skips the provided number of frames.
func TakeStacktrace(skip int) string {
Copy link
Contributor Author

@zekth zekth Aug 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we deprecate this and add a comment that it's just a temporary export? Although we might want to implement this first because /exp/slog relies on zap 1.24.0 :

go.uber.org/zap v1.24.0

to make it work i need to modify the go.mod:

module go.uber.org/zap/exp

go 1.19

require (
	github.com/stretchr/testify v1.8.1
	go.uber.org/zap v1.24.0
	golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb
)

require (
	github.com/davecgh/go-spew v1.1.1 // indirect
	github.com/pmezard/go-difflib v1.0.0 // indirect
	go.uber.org/atomic v1.10.0 // indirect
	go.uber.org/multierr v1.10.0 // indirect
	gopkg.in/yaml.v3 v3.0.1 // indirect
)

replace go.uber.org/zap => ../

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the idea of exporting this functionality from the main Zap package even as a temporary unsupported thing.
Instead, I've moved the relevant bits into an internal package in #1341.

That makes it easy to use them here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this i agree on this approach too

Time: record.Time,
Message: record.Message,
LoggerName: h.name,
// TODO: do we need to set the following fields?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stack was not required for the implementation

@zekth zekth force-pushed the feat/slog-stacktrace branch 3 times, most recently from 3b30b92 to 964a1cc Compare August 23, 2023 17:15
abhinav added a commit that referenced this pull request Aug 25, 2023
Moves the functionality to capture and format stack traces
into an internal stacktrace package
and exports the relevant bits out for the logger and field.go to use.

This will be used by zapslog.Handler to capture stack traces
so it needs to be in a shared location.

Refs #1329, #1339
Copy link
Collaborator

@abhinav abhinav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for doing this, and thanks for waiting for the review. It's a bit busy these days.

I'll try to get #1341 landed soon to capture the stack traces without exporting them from the main Zap package.

And yeah, exp/ will need a replace directive. We'll have to be careful about updating exp/ to the latest Zap release when we tag it.

@@ -157,6 +144,10 @@ func (h *Handler) Handle(ctx context.Context, record slog.Record) error {
}
}

if h.addStack.Enabled(zapLevel) {
ce.Stack = zap.TakeStacktrace(4 + h.callerSkip)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add a comment here for each of the 4 skips we're adding, e.g. skip Handle, slog.LogAttr, [..], etc.
I suspect this might not be as straightforward.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure I'll add revelant comments

stacktrace.go Outdated
@@ -125,6 +125,12 @@ func (st *stacktrace) Next() (_ runtime.Frame, more bool) {
return st.frames.Next()
}

// TakeStacktrace returns the stack trace,
// and skips the provided number of frames.
func TakeStacktrace(skip int) string {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the idea of exporting this functionality from the main Zap package even as a temporary unsupported thing.
Instead, I've moved the relevant bits into an internal package in #1341.

That makes it easy to use them here.

@abhinav
Copy link
Collaborator

abhinav commented Aug 25, 2023

I've pushed some minor fixups to your branch. Please be sure not to lose them if you git push -f.

abhinav added a commit that referenced this pull request Aug 25, 2023
Moves the functionality to capture and format stack traces
into an internal stacktrace package
and exports the relevant bits out for the logger and field.go to use.

This will be used by zapslog.Handler to capture stack traces
so it needs to be in a shared location.

Refs #1329, #1339
@zekth zekth force-pushed the feat/slog-stacktrace branch from c639ac6 to 3be64f5 Compare August 25, 2023 16:16
@zekth zekth force-pushed the feat/slog-stacktrace branch from 3be64f5 to b66a3d3 Compare August 25, 2023 16:19
@zekth
Copy link
Contributor Author

zekth commented Aug 25, 2023

@abhinav I rebased and applied all the comments

@codecov
Copy link

codecov bot commented Aug 25, 2023

Codecov Report

Merging #1339 (573bc29) into master (e9f4bda) will decrease coverage by 0.23%.
The diff coverage is 75.75%.

@@            Coverage Diff             @@
##           master    #1339      +/-   ##
==========================================
- Coverage   97.95%   97.72%   -0.23%     
==========================================
  Files          51       52       +1     
  Lines        3369     3392      +23     
==========================================
+ Hits         3300     3315      +15     
- Misses         59       67       +8     
  Partials       10       10              
Files Changed Coverage Δ
exp/zapslog/options.go 55.55% <55.55%> (ø)
exp/zapslog/handler.go 93.33% <100.00%> (+0.33%) ⬆️

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@zekth
Copy link
Contributor Author

zekth commented Aug 26, 2023

@abhinav should i add tests for the options or we add them in another PR? I'm happy to write a follow up one if needed

Copy link
Collaborator

@abhinav abhinav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @zekth, apologies; I haven't forgotten about this, but I've had (and continue to have) a busy few days. I've taken a pass; this mostly looks good to go with minor comments. I'll address a few myself in a few minutes.

Tagging other Zap maintainers as well. CC @sywhang @mway @prashantv
(Context: This PR turns HandlerOptions into functional options per prior discussion, and adds support for stack traces. Stack traces are captured for Error and above -- same as Zap's production logger.)

RE: tests: There's no need to backfill tests for existing options at this time--tests for the new option you're adding for stack traces should be sufficient. We do intend to fill in the rest of the tests before moving this to the main Zap package, though, but that's out of scope for this PR.

exp/go.mod Outdated Show resolved Hide resolved
Comment on lines +149 to +153
// Skipping 3:
// zapslog/handler log/slog.(*Logger).log
// slog/logger log/slog.(*Logger).log
// slog/logger log/slog.(*Logger).<level>
ce.Stack = stacktrace.Take(3 + h.callerSkip)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding this. Much more obvious what's going on now.

exp/zapslog/options.go Outdated Show resolved Hide resolved
Comment on lines 65 to 67
// AddStacktrace configures the Logger to record a stack trace for all messages at
// or above a given level.
func AddStacktrace(lvl zapcore.LevelEnabler) Option {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just thinking out loud (would love your opinion on this, @zekth):
I wonder if this should be a slog Level instead. Or a new zapslog.LevelEnabler interface based on slog.Level.

type LevelEnabler interface{ Enabled(context.Context, Level) bool }

The reasoning is this: the result of zapslog.NewHandler is a slog Handler. It talks in the language of slog.

And update documentation.
Changes AddStacktrace to use a slog.Level instead of a Zap Level,
and renames it to AddStacktraceAt.
This leaves room for a LevelEnabler (as suggested in the PR)
to be specified with an AddStacktrace in the future.
@abhinav
Copy link
Collaborator

abhinav commented Aug 27, 2023

On LevelEnabler and whether this should use a Zap level or slog level.
The more I think about it, the slog level makes sense.
The slog level has more information; conversion from slog to Zap level is a lossy operation.
I've renamed the option to AddStacktraceAt.
That way, if we want to add a LevelEnabler in the future, we can still use an AddStacktrace(LevelEnabler) option.
(The proposed LevelEnabler's Enabled signature matches slog.Handler.Enabled, so such a user-provided function
would have all the important information about the record to determine whether it should capture a stacktrace.)

We avoid use of assert.New and require.New in our tests.
Now that zaplevel isn't used to determine if we need to capture the
stack trace, it can be inlined back into the entry construction.
Copy link
Collaborator

@abhinav abhinav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@mway @sywhang would appreciate a second look.
FYI, the coverage drop is because some of the existing functionality is untested; we will want to fix that before considering this stable anyway.

Copy link
Contributor

@sywhang sywhang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@sywhang sywhang merged commit b900128 into uber-go:master Sep 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

zapslog.Handler: Add stack traces
4 participants