-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Fix the Error trait #2504
Fix the Error trait #2504
Conversation
Alternative to
|
Or
|
Has |
I'm gonna be extremely sad if we end up with an awkward synonym for |
I don’t want to chime in too much on the bikeshedding but with regards to naming here is what others do:
Cause is the most common but obiously not available. For the non cause uses they are all different. However one other thing that comes to mind is that since we are already fixing this it might be reasonable to consider aggregate exceptions as well. A fanout can collect multiple errors that might make sense to capture. In that case the name |
In failure backtrace just always act like the backtrace variable is off when compiled in no_std. We could possibly do the same thing with core someday.
Not sure what you were thinking but |
fn backtrace(&self) -> Option<&Backtrace> {
self.source().map(|s| s.backtrace())
}
This is more hypothetical. I am not completely sure on motivations. Possible motivations:
Possible ways of doing this
I can't remember how it was good for |
text/0000-fix-error.md
Outdated
|
||
Today, the `RUST_BACKTRACE` controls backtraces generated by panics. After this | ||
RFC, it also controls backtraces generated in the standard library: no backtrace | ||
will be generated when calling `Backtrace::new` unless this variable is set. |
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.
Does this mean Backtrace::new
should return an Option, or that it will simply not be called by any code inside std (and always produces a backtrace when called)?
For what reason was
Given that the text makes a prior distinction "end-user display message" and "programmer debug message", I think the quoted section intends to suggest that backtraces are for programmers rather than end-users, yes? |
text/0000-fix-error.md
Outdated
|
||
Today, the `RUST_BACKTRACE` controls backtraces generated by panics. After this | ||
RFC, it also controls backtraces generated in the standard library: no backtrace | ||
will be generated when calling `Backtrace::new` unless this variable is set. |
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.
It seems kind of weird for it to be impossible to get a backtrace at all if the right environment variable isn't set. It seems reasonable to have a constructor that returns an Option<Backtrace>
by checking the environment, but I think Backtrace::new
should just unconditionally produce a backtrace.
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 agree. I effectively have to force this envvar on all the time now on startup which seems like a weird way to control the system.
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.
the behavior of a Backtrace is based on whether or not that environment variable is set.
Personally, I feel like that policy should be decoupled from being able to get a Backtrace
. We should have an aligned default policy but we should make it possible for people to create policies to suit their needs. For example, this RFC is bringing up a change in policy:
From RFC
Two additional variables will be added: RUST_PANIC_BACKTRACE and RUST_STD_BACKTRACE: these will independently override the behavior of RUST_BACKTRACE for backtraces generated for panics and from the std API.
How will Backtrace
know its calling context to use these two variables?
If it isn't, its a null type that doesn't collect any backtrace information and prints nothing when displayed.
And in Error
s case, is there a reason to use null objects rather than Option
like the API?
It was an oversight - |
@tmandry @sfackler To clarify, the way that error-chain and failure both work, |
cc @rust-lang/libs |
I was actually thinking it would return some sort of wrapped I do not completely want to lose track of the aggregation case though because with async code that will come up sooner or later. |
Along the lines of creating a backtrace, I agree with @sfackler's comment as well! I wonder, would something like this suffice? impl Backtrace {
// always captures a backtrace, unless platform
// does not support it, in which case `None` is returned
pub fn new() -> Option<Backtrace>;
// optionally capture a backtrace, dictated by environment variables
// returns `None` if env vars say to not capture a backtrace
// or on platforms that don't support it
pub fn maybe_new() -> Option<Backtrace>;
} That way if a tool wants to unconditionally capture a backtrace they have a means of doing so. At the same time though we'd provide an idiomatic constructor for crates like |
Is it possible to make panic use |
@alexcrichton agreed with this a whole bunch. I would generally not make Instead of impl Backtrace {
// capture a backtrace unless unsupported.
pub fn capture() -> Option<Backtrace>;
// capture a backtrace if possible and wanted for the given situation.
pub fn capture_for(c: BacktraceConsumer) -> Option<Backtrace>;
}
pub enum BacktraceConsumer {
Panic,
Error,
} (I started a spec for a better backtrace object a while back but never finished it because I ran into limitations with the symbolication support in backtrace.rs that makes the API I envisioned really hard to get. If there is interest I can unearth what I wrote together though and remove those bits). |
I'm uncertain what the benefit of any
The distinction is an intentional feature; I received a lot of feedback on failure that users want the ability to control the backtraces they get from panics differently from the backtraces created by their libraries, because they can't afford to have backtraces in library code but want to have backtraces when things catastrophically fail. |
Right now I as a user check against an empty string return from display.
Hardly any better :)
…On Fri, Jul 20, 2018 at 2:06 PM boats ***@***.***> wrote:
I'm uncertain what the benefit of any -> Option<Backtrace> constructor
is. How is a user supposed to handle the None case there? I can't think
of any way to handle it other than carrying an Option<Backtrace>
indefinitely, ultimately checking for the None case when you print it out;
in other words, the same behavior that having nullity be a permitted
backtrace behavior. I also notice that there is no API in which backtrace
is actually present unconditionally; it seems more correct and more user
friendly to incorporate this nullity into the behavior of the backtrace
type instead.
I don't know if it is possible, but if "panic backtraces" and "std
backtraces" were the same thing, that sounds better.
The distinction is an intentional feature; I received a lot of feedback on
failure that users want the ability to control the backtraces they get from
panics differently from the backtraces created by their libraries, because
they can't afford to have backtraces in library code but want to have
backtraces when things catastrophically fail.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#2504 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAAc5NVDzzXACXD8TydHh-OLep7KACBoks5uIcfagaJpZM4VWUn_>
.
|
@mitsuhiko What do you do when the string is empty? That's what I'm trying to get at: for most use cases, I don't know how you would handle a null backtrace. (I think the better solution would be to have an API on backtrace that tells you if its null or not.) |
@withoutboats in the trivial case i render differently (eg: i render out "stacktrace:\n{}" vs "set the envvar to get stacktraces). More importantly though I currently also need to regex parse the backtrace since there is no api to access so there is more to this. With a backtrace API I could also see that I did not get any frames. For me the main difference between |
I don't know what you mean by "no backtrace was requested," but I'm having trouble understanding how this comment squares with the API you proposed above, in which both constructors return an |
The usecase that comes up for me is that right now some APIs (like panic handlers, or errors with stacktraces bubbled up to main) can show backtraces to the user but only if the envvar is set. So I want to hint to the user when to turn it on. Not requested was that the envvar was not set.
It would maybe make sense to have the |
How about: enum Reason {
Envvar,
NotSupported,
}
enum Backtrace {
Captured(RealBacktrace),
NotCaptured(Reason)
Synthetic
}
impl Default for Backtrace {
fn default() {
Backtrace::Synthetic
}
}
impl Backtrace {
fn capture() -> Backtrace() {
unimplemented!("actually capture a backtrace here, NotSupported if not supported")
}
fn new() -> Backtrace {
match envvar {
true => Backtrace::capture(),
false => Backtrace::NotCaptured(Reason::Envvar),
}
}
} Then any user can place the desired printing on top of that. |
An example of why including the nullity in the backtrace is useful: if we don't, presumably errors will be storing I think it makes sense for backtrace to report its status somehow; I initially imagined a boolean, but probably we want it to be to give more information, that is, something like: #[non_exhaustive]
enum BacktraceStatus {
Captured,
Disabled,
Unsupported,
}
impl Backtrace {
pub fn status(&self) -> BacktraceStatus
} You could match on this status to convey to users, e.g. "turn the env var on," or "backtraces are unsupported on this platform" |
@withoutboats how are you planning on handling this requirement:
I have some thoughts on the API but I feel like the answer to the above might also help shape it and want to make sure its included. |
text/0000-fix-error.md
Outdated
methods will be encouraged (by warnings) to change their code, and library | ||
authors will need to revisit whether they should override one of the new | ||
methods. | ||
|
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.
Under "Drawbacks", could you please explicitly document whether there's any functionality drawback to adding the 'static
bound on source
? Is there any error pattern that that would prevent? And if not, could you state that explicitly?
@GuillaumeGomez "With this trait, you don't have the choice anymore". I do not see how this trait changes anything. You have the same choice now as you had before. |
Please reviewers, bias toward action (merging this) unless you find substantive compatibility problems not covered in The transition plan section of this RFC. |
Does creating a backtrace allocate? I suppose it might allocate a String but then Error probably cannot be used anywhere close to an allocator or one must be careful doing so. This limitation is ok, but I am not sure what the scope of this limitation is. Also, Backtrace contains a backtrace to what exactly? Where is the “leaf” stack frame of this backtrace? Is it some implementation detail of the Backtrace machinery? The stack frame of the caller method? Platform / optimization dependent (e.g. inlining)? I’d expect that for the backtrace to be useful it must point to the caller stackframe and all stackframes from the Backtrace implementation must have been pruned, but I haven’t found any information about this in the RFC or the comments. Sorry if this was already asked or discussed. |
@gnzlbg @GuillaumeGomez This RFC proposes to add this default method to the trait fn backtrace(&self) -> Option<&Backtrace> {
None
} Any error which doesn't include a backtrace just doesn't override this method; in other words, nothing about that experience changes. What has changed is that we have created a standardized API for accessing the backtrace of an error which does have one. |
I'm just afraid that on the opposite to std lib, you won't be able to disable backtraces when using crates. Maybe I'm just worrying about things that won't happen but still... |
There is no difference to today. There are already crates that carry backtraces. |
Small tweak: I would take |
And this is part of why I don't use them. |
The final comment period, with a disposition to merge, as per the review above, is now complete. |
Huzzah! This RFC has been merged! Tracking issue: rust-lang/rust#53487 |
From the first line of the RFC:
In particular, this RFC adds an API, My two questions are:
The RFC doesn't even say what a backtrace is, and when it states: "Capture the backtrace for the current stack if it is supported on this platform" I think it is important to state in which state the current stack is when its backtrace is captured. E.g. if I write: fn foo() {
let b = Backtrace::capture();
println!("{}", b);
} what am I going to see ? ...
...
foo or ...
...
foo
Backtrace::capture
Backtrace::barbaz
os::raw:..
... ? I find the meaning of:
unclear. What does "user display purposes" mean ? The answers to all these questions are the difference between getting a backtrace that I can just pass to panic to abort a process, or whether I can actually parse the backtrace to do something useful. |
Rendered
Tracking issue