-
Notifications
You must be signed in to change notification settings - Fork 698
Why call callers() on every wrap? #75
Comments
I agree with @cep21 in general. The only scenario where multiple stack traces might be useful is when an error is passed between goroutines (and thus jumps stacks) before getting handled. |
You only need to call Wrap when you have extra context to return. I'm not concerned about the cost of calling Wrap in the error path. Please see this blog post. On Thu, 28 Jul 2016, 05:21 Chris Hines notifications@github.com wrote:
|
The way the code is now, all the stack traces of wraps get put into the output. Isn't that excessive?
If I encourage myself and coworkers to use the errors package, their returns would already include stack traces. Maybe. It's a bit too much for me to know which libraries I'm using have stacks in their errors and which don't. That goes away from "errors are opaque" territory. I can't see much practical use from stack traces of errors wrapped in the middle of the chain. |
I agree that the behaviour is not the expected one. If I do If you use Please consider changing it. |
We should have control over this once #76 gets merged. |
Why not ? I can equally see a need too add a strack trace for each wrap. For example err := <- ch
if err != nil {
return errors.Wrap(err, "async request failed")
}
... That is, the request failed in another goroutine and the error was handled back to the goroutine doing the merge/fan in, and the error is propagated from that point. I'm not saying you're wrong, just that people can (and have) made the argument either way. After strong push back from the Go team at GopherCon this year, #76 is probably going to be how we destructure Wrap into the component pieces of adding a stack trace and/or adding a message depending on requirements. |
Good to hear about #76, eagerly awaiting the results :) Thanks for the good work. Looks like that should solve it. Yes, I see the use case of adding the trace when goroutines are involved (a couple of other stacktrace-error libraries do it the same way for the same reason). At least to me, that is a very rare case compared to the normal case where errors are not passed between goroutines, and I dislike having every error have an enormous stacktrace with almost all of it being duplication. I think it's not possible to identify goroutines in Go code, which would have been very useful here (automatically add a stacktrace when the error crossed goroutines). |
So don't call
I won't be adding a goroutine id. |
Don't you agree that's strongly overstated? Yes, the two situations exist, but to claim they are equal is a strong overstatement. If I were to look over the Go stdlib or any large code I've written, the situation you describe is the 1% of the 99% that is a normal error return. Maybe even the .1% of the 99.9% The 99% case is wanting to "add a stack trace, if one does not exist. Otherwise don't". I think the default behavior should conform to this 99% case with special functions for wanting to do the 1% case. That's what I did in my forked version. But it's my understanding you want this to be in the standard library as well? If that's the case, I would appreciate being part of that conversation when it happens to make sure all sides are considered :) Not to distract!!! I'm super pleased with how the library is implemented and written! |
Nope. I've had people on both sides of the aisle bending my ear. |
I do want to add more context info about the error though, just not another stack.
#76 seems to tackle this problem and make both camps happy, so after that, there should be no problem. I agree with @cep21's sentiment, but I do not care particularly about the API details:
|
#76 has merged, and I think it solves the issue in most cases -- basically, call I think it would be nice/useful if there was an implementation of If there was a I realize that the added complexity has downsides, but in my view it would simplify the manner in which the code is used/consumed. Does this make sense, or is there something that I'm missing/some other way to approach this? |
I see what you are asking for, the logic for "always capture a stack trace On Thu, 29 Sep 2016, 16:55 Nick Miyake notifications@github.com wrote:
|
I played around with doing this locally, and agree with your assessment. I also realized that implementing such functionality out-of-the-box still wouldn't give me the desired error output since all of the I was able to get pretty much everything I wanted by using the default
Both functions fall back on the default For those interested, the implementation for this is at https://github.com/nmiyake/errors/blob/addPrinter/printer/printer.go. This implementation implements the functionality externally from The implementation could be simplified if it were part of the Do you see any way in which this kind of output functionality could be cleanly included in this package (or as a sub-package)? I know you want to keep the footprint down, but seems like there's demand for a mechanism like this that would handle printing stacks wrapped at multiple locations in a consumer-friendly manner, so might be interesting to think about whether something like this could be supported elegantly. |
This only happens with |
Yes in all of my comments on this issue I'm referring specifically to the behavior when using |
I agree with that, ideas of this error package are great but why not implement it more elegantly? |
@davecheney I'm running into the same issue that @nmiyake was having. I can deal with it in the same way that he did, with a different error printer, but I find a lot of value in being able to use this package for both. I'm curious to know your thoughts on best practices in this situation.
As things are now, using WithMessage, I end up with a log that looks something like this:
The context I added with WithMessage is intended to further clarify the error that will be logged. As it is now, I have to scroll past the long stack trace to get the rest of the context. It seems like it would be more valuable to have WithMessage amend in the traditional form, even in the %+v case, so you would get something like:
What's the reasoning behind separating out the message at the bottom? What do you consider the right way to do this? |
This looks like a bug, @noonat please open a new issue (this one is too long and confusing). |
I see there is a number of ways to go, here:
@davecheney , what do you think? You probably understand the different use cases best, by now. Would that make sense at all, or do you think such global config option is a crime? |
TL;dr - yes, that's not a thing I want to add.
The goal of this package is simplicity. That comes via having the fewest
ways to do things, which itself has been a battle. Adding with stack and
with message were only after significant petitioning from many users last
year at gophercon. I don't see adding another option, let alone a global
flag, to alter their preference because this would at least begat an option
to check the preference.
I think you're looking at this the wrong way. Choosing to add a stack trace
or a message is the property of the user of the errors package.
Choosing to print or not print a stack trace is a different property
controlled by the formatting verb you pass to printf.
…On Thu, 23 Feb 2017, 03:41 feliksik ***@***.***> wrote:
I see there is a number of ways to go, here:
1.
always capture a stack trace: Wrap(err,msg) (and WithStack(msg) )
2.
never capture a stack trace: WithMessage(err,msg)
3.
always capture a stack trace, unless one already exists at the origin.
As we're dealing with a linked list of errors, you'd probably have to do a
type assertion on the error to wrap, and (if you don't store a stack trace)
store in the wrapped-error a placeholder value that signals whether a stack
trace is stored, so the next wrapper does not need to traverse the entire
stack. Let's call this OriginStack(err,msg) for lack of a better term now.
4.
a method that chooses whether to use 1, 2 or 3, based on a global
configuration of the library. I'll call it SWrap(msg, err) for now, for
lack of a better term. Then you can configure the 'strategy' with
errors.SetStackStrategy(errors.strategy_1) . This would take away the need
to be concerned with what to use where, and you can tweak the parameter as
you go. Disadvantages would be that if you default to using SWrap()
everywhere, defaulting to strategy 2, and you want to see information you
would have to 1) restart your application and set strategy_1 for example,
and 2) you'll now log it *everywhere*. So great for debugging, not
sure about production. But the point is, you probably don't know beforehand
where you want more and where less detailed info.
@davecheney <https://github.com/davecheney> , what do you think? You
probably understand the different use cases best, by now. Would that make
sense at all, or do you think such global config option is a crime?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#75 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAAcAw0Wu1-_Cr2n0-6UB5Uzhv0hh069ks5rfGVDgaJpZM4JWg8U>
.
|
@davecheney ok thanks for you response! |
Came to this thread with the same issue everyone else is having. This is how I solved it without forking this package or requiring additional dependencies. https://github.com/abraithwaite/go-examples/blob/master/errdive.go#L9-L30 You don't get the extra messages, but if you have the stack do you really need those? |
Currently the primary expectation when using
The fact that one has to be aware of how the underlying implementation handles error wrapping makes using it quite uncomfortable. I can accept overwriting stack trace as a valid use case, but it doesn't seem to be the more common one and should be a conscious decision (eg. use Currently I use my own Wrap function which is based on the code in #122 to avoid annotating an error with multiple stack traces. As far as I can see this is rather a UX/DX issue than a technical one. My two cents. |
Currently github.com/pkg/errors.Wrap/Wrapf functions overwrite already attached stack trace. From a UX/DX point of view one would like to add stack trace to an error if none is attached yet. There are several open issues discussing the problem in the original repo: pkg/errors#75 pkg/errors#144 pkg/errors#158 At the moment there is no solution provided, but it looks like the author is willing to make some changes. Until then this commit adds custom Wrap/Wrapf functions which implement this desired behaviour. Other than that, they behave the same way. There is also a pending PR in the original repo: pkg/errors#122 It worths mentioning that there are alternative solutions, like merging stack traces: srvc/fail#13 After examining the solution it seems that it's probably too complicated and unnecessary for most cases. It's also unlikely that the original errors package will implement this behaviour, so for now we stick to the most expected behaviour.
Based on @abraithwaite's great idea, I came up with the following snippet:
The |
I feel like this proposed function would only serve to produce more confusion about how to properly use this library. |
@puellanivis No, I am not proposing to merge this function into the library, I am just showing an approach for those who have the same "generate only one stack trace" problem like me that how to deal with it and don't bother to care about when to use
|
Every time an error is wrapped, callers() is called. This seems wasteful to me. I think the root error's stack trace is the most important and almost always what I want.
I think if the error that is being wrapped implements
stackTrace interface
, that error's stack trace should be used instead, and the call to callers() can be skipped. For sure, any stack traces in errors between the top and bottom of the error stack are ignored.I think my optimal format message would include the wrapped msg's all down the various error wraps with a stack trace at the bottom.
The text was updated successfully, but these errors were encountered: