-
Notifications
You must be signed in to change notification settings - Fork 575
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
Add support for stack trace extration of error fields #35
Conversation
In the example for have a field name parameter like
The first one makes sense if one wants to add more attributes to an error. While second one allows to keep log processing more simple and prevents from questions what should be inside the |
I see a way to configure root logger with an type ErrorMarshaller func (buf []byte, err error, stack bool) []byte or type ErrorMarshaller func (e *Event, err error, stack bool) *Event or type ErrorMarshaller interface {
func (e *Event) Err(err error) *Event
func (e *Event) ErrStack(err error) *Event
} This would it make possible for a user to decide does he/she needs |
@rs, please, take a look at a commit soulne4ny@863bbc6 |
@soulne4ny: one downside I see with your approach is that we have to pay for the cost of the interface, even for the default (current) mode with no stack support. |
Yes, it is the cost. It could be wrapped with However, this is only On the other hand, this is not just support for error stacks, but for custom wrapped-error types. This requires either tight coupling with the library, or an interface, or a code generation. Passing an error formatter as an interface or a function pointer, implies a cost for every Is there any other way to remove the indirection besides code generation? |
@rs Would you consider true the hypothesis that error messages should be rather infrequent during regular runs? It yes, then does the cost of indirection matter? |
pkgerrors/stacktrace.go
Outdated
StackTrace() errors.StackTrace | ||
} | ||
var st errors.StackTrace | ||
if err, ok := err.(stackTracer); ok { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can remove this else
by inverting the validation logic.
err, ok := err.(stackTracer)
if !ok {
return nil
}
return appendJSONStack(make([]byte, 0, 500), err.StackTrace())
Just a different point of view on this block 😃
We often use |
Solving just stack reporting case, the following notation could be used log.Error().Err(err).Stack(err).Msg("") Then |
Sounds reasonable. |
Any news on this? really looking forward to stacktraces |
@soulne4ny would you consider rebasing your work and implement the last discussed changes? |
As per #9 and to offer a different approach from #11 and #35 this PR introduces custom error serialization with sane defaults without breaking the existing APIs. This is just a first draft and is missing tests. Also, a bit of code duplication which I feel could be reduced but it serves to get the idea across. It provides global error marshalling by exposing a `var ErrorMarshalFunc func(error) interface{}` in zerolog package that by default is a function that returns the passed argument. It should be overriden if you require custom error marshalling. Then in every function that accept error or array of errors `ErrorMarshalFunc` is called on the error and then the result of it is processed like this: - if it implements `LogObjectMarshaler`, serialize it as an object - if it is a string serialize as a string - if it is an error, serialize as a string with the result of `Error()` - else serialize it as an interface The side effect of this change is that the encoders don't need the `AppendError/s` methods anymore, as the errors are serialized directly to other types.
@soulne4ny ping |
1cea9c5
to
8479412
Compare
Looking forward to this feature. Press the merge button already! |
Any chance we can get this merged? The rebase looks fairly easy, I had a go in a closed PR but ran into CI issues. |
context.go
Outdated
e.Stack() | ||
} | ||
|
||
var sh = callerHook{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be var sh = stackTraceHook{}
?
@krak3n: I just tried to rebase, and it's not trivial. The |
Here is a rebase with a change of API for the stack marshaler that work with the new encoding system. Please have a look before I merge. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thank you for chasing this to the end and incorporating this request.
pkgerrors/stacktrace.go
Outdated
out = append(out, map[string]string{ | ||
StackSourceFileName: fmt.Sprintf("%s", frame), | ||
StackSourceLineName: fmt.Sprintf("%d", frame), | ||
StackSourceFunctionName: fmt.Sprintf("%n", frame), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we change this to be something like:
StackSourceFileName: frame.String(),
StackSourceLineName: strconv.FormatInt(frame, 10),
I'm not sure what the %n
verb is for StackSourceFunctionName()
, but finding something that isn't fmt.Sprintf()
would be preferred if there's interest in reducing the overhead of this call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think pkg/errors
is using the fmt.Formatter
interface to expose the different info. I'm not a big fan of this type of magic API, but that's the way it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check the last commit, I removed some allocs by calling the Format
method directly. It's not a huge win though:
name old time/op new time/op delta
LogStack-8 11.0µs ± 3% 8.9µs ± 1% -18.97% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
LogStack-8 4.16kB ± 0% 4.24kB ± 0% +2.12% (p=0.008 n=5+5)
name old allocs/op new allocs/op delta
LogStack-8 89.0 ± 0% 86.0 ± 0% -3.37% (p=0.008 n=5+5)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks guys, looking forward to this getting merged 😄 |
🎉 |
Proposal for #11.
@sean-: what do you think about this implementation?
I'm not super happy of the API. I'm not sure having
Stack
andErr
separated is great design. What would you think about a new set of error-with-stack methods that would package the error message and the stack together.For instance:
would generate: