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

Allow configurable stacktrace encoding #1371

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

arwineap
Copy link

@arwineap arwineap commented Oct 9, 2023

This PR adds a StacktraceEncoder type to the EncoderConfig struct

Users can override the EncodeStacktrace field to configure how stacktraces are outputed This PR aims to resolve #514 by mirroring the behavior of the EncodeCaller field

The EncodeStacktrace field has been inserted as a required field, and has been added to NewDevelopmentConfig and NewProductionConfig as sane defaults however, as a required field it can cause a panic if a user is manually building their config without these helpers.

This PR adds a `StacktraceEncoder` type to the `EncoderConfig` struct

Users can override the `EncodeStacktrace` field to configure how stacktraces are outputed
This PR aims to resolve uber-go#514 by mirroring the behavior of the `EncodeCaller` field

The `EncodeStacktrace` field has been inserted as a required field, and has been added to `NewDevelopmentConfig` and `NewProductionConfig`
as sane defaults however, it is currently a required field and can cause a panic if a user is manually building their config without these helpers.
@CLAassistant
Copy link

CLAassistant commented Oct 9, 2023

CLA assistant check
All committers have signed the CLA.

@codecov
Copy link

codecov bot commented Oct 10, 2023

Codecov Report

Merging #1371 (cad62a8) into master (87577d8) will decrease coverage by 0.13%.
The diff coverage is 84.12%.

❗ Current head cad62a8 differs from pull request most recent head d45920a. Consider uploading reports for the commit d45920a to get more accurate results

@@            Coverage Diff             @@
##           master    #1371      +/-   ##
==========================================
- Coverage   98.28%   98.15%   -0.13%     
==========================================
  Files          53       53              
  Lines        3493     3527      +34     
==========================================
+ Hits         3433     3462      +29     
- Misses         50       55       +5     
  Partials       10       10              
Files Coverage Δ
config.go 100.00% <100.00%> (ø)
zapcore/json_encoder.go 100.00% <100.00%> (ø)
zapcore/console_encoder.go 97.05% <78.57%> (-2.95%) ⬇️
zapcore/encoder.go 83.45% <22.22%> (-4.24%) ⬇️

... and 1 file with indirect coverage changes

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

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 the PR, @arwineap! This change looks largely in the right direction.
However:

The EncodeStacktrace field has been inserted as a required field [..] it can cause a panic if a user is manually building their config without these helpers

That's a breaking change and we can't merge that. The new field must be optional.
The console and JSON encoders already have handling for optional overrides like this one; this should be another such optional field. For example:

zap/zapcore/json_encoder.go

Lines 381 to 387 in 87577d8

nameEncoder := final.EncodeName
// if no name encoder provided, fall back to FullNameEncoder for backwards
// compatibility
if nameEncoder == nil {
nameEncoder = FullNameEncoder
}

zapcore/encoder.go Outdated Show resolved Hide resolved
zapcore/encoder.go Show resolved Hide resolved
@arwineap
Copy link
Author

Thank you for the clarification, I'm unsure how I missed the default catch for the nil cases. This has been added.

One other concern I had was with the console encoder; I'm not sure I can avoid calling getSliceEncoder() a second time because of the split in output between structured fields and unstructured panic data. This felt ineffecient, but the code seems cleaner than the alternative

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.

This is great, thanks. I've left some minor comments.

I have a couple open questions that I maybe need input from other maintainers on.

  • Should the encoder be primitives-based like the other encoder overrides or a full one capable of posting objects -- e.g. if someone parses the stack trace?
  • Should the fallback behavior be to encode the full stack trace, or should we take that as an indication that they don't want to encode the stack trace?

CC @prashantv @sywhang @mway

zapcore/encoder.go Outdated Show resolved Hide resolved
zapcore/encoder.go Outdated Show resolved Hide resolved
if cur == final.buf.Len() {
// User-supplied EncodeStacktrace was a no-op. Fall back to strings to
// keep output JSON valid.
final.AppendString("")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Did you mean to pass ent.Stack here?

Suggested change
final.AppendString("")
final.AppendString(ent.Stack)

Copy link
Author

Choose a reason for hiding this comment

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

Good catch, this was actually intentional.

The idea being that a user can disable stacktrace key / values in json output by configuring StacktraceKey to be blank

However, if the user created the custom encoder which emptied out the stack trace, it seems like we should respect their key / value, and append their StacktraceKey with an empty string

The issue is that at this part of the code the StacktraceKey has already been added to the json output, so we need a string value to make the json valid, so an empty string makes sense. Perfectly reasonable to only add the Key if a value exists, just need some rearranging

It's a matter of design, and it's more important that it's consistent across all of the options, so I will defer to the zap team here 👍

Comment on lines +133 to +138
for i := range arr.elems {
if i > 0 {
line.AppendString(c.ConsoleSeparator)
}
fmt.Fprint(line, arr.elems[i])
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

The contract for stacktraceEncoder is that it makes at most one Append* call.
So we don't need the full arr.elems handling here. It can just be:

Suggested change
for i := range arr.elems {
if i > 0 {
line.AppendString(c.ConsoleSeparator)
}
fmt.Fprint(line, arr.elems[i])
}
if len(arr.elems) > 0 {
fmt.Fprint(line, arr.elems[0])
} else {
// User-provided encoder was a no-op.
// Fall back to full encoder.
line.AppendString(ent.Stack)
}

Copy link
Author

Choose a reason for hiding this comment

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

The first AppendString in this call is actually a way to add the ConsoleSeparator between each line; it could probably be integrated into the Fprint to reduce branching here

@abhinav
Copy link
Collaborator

abhinav commented Oct 11, 2023

Related: We'll want to make a decision on #1373 before we release this because choices there affect the design for this.

arwineap and others added 2 commits October 11, 2023 08:39
Co-authored-by: Abhinav Gupta <mail@abhinavg.net>
Co-authored-by: Abhinav Gupta <mail@abhinavg.net>
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.

Add an option to override stacktrace collection logic
3 participants