How do I get Backtrace
working with SNAFU? I tried, but I just get empty backtraces. The documentation is sparse on that it seems.
return Error::SampleError {
msg: "foo".to_string(),
backtrace: Backtrace::generate(),
};
prints
SampleError { msg: "foo", backtrace: Backtrace(()) }
This is being thrown from a function that is very deep in the call stack.
Let's start with this minimal, reproducible example:
use snafu::Snafu;
#[derive(Debug, Snafu)]
enum Error {
SampleError { msg: String },
}
type Result<T, E = Error> = std::result::Result<T, E>;
fn alpha() -> Result<()> {
beta()
}
fn beta() -> Result<()> {
gamma()
}
fn gamma() -> Result<()> {
SampleError { msg: "foo" }.fail()
}
Note that it uses the context selector SampleError
and the method fail
instead of directly using the enum variant to construct the error.
Now we import snafu::Backtrace
and add it to our error, naming it backtrace
(see controlling backtraces if you must call it something else).
use snafu::{Snafu, Backtrace};
#[derive(Debug, Snafu)]
enum Error {
SampleError { msg: String, backtrace: Backtrace },
}
If this were a library, that's where you should stop. Your error now will optionally have a backtrace enabled if the binary decides that backtraces are worth it. This is done as backtraces aren't yet stabilized in Rust, so SNAFU has to be compatible with multiple possible implementations.
If you are controlling the binary, you will need to decide how the backtraces will be implemented. There are three main implementations selected by a feature flag:
backtraces
— Provides an opaque Backtrace
typebacktraces-impl-backtrace-crate
— uses the third-party backtrace crate. snafu::Backtrace
is just an alias to backtrace::Backtrace
.unstable-backtraces-impl-std
— uses the unstable standard library Backtrace
. snafu::Backtrace
is just an alias to std::backtrace::Backtrace
.Once you've picked an implementation feature flag, add it to your Cargo.toml:
[dependencies]
snafu = { version = "0.6.3", features = ["backtraces"] }
Then, you will need to handle the error somewhere high up in your program and get the backtrace and print it out. This uses the ErrorCompat
trait, which I encourage you to use in a verbose manner so it's easier to remove it later, when it's stabilized in the standard library:
use snafu::ErrorCompat;
fn main() {
if let Err(e) = alpha() {
if let Some(bt) = ErrorCompat::backtrace(&e) {
println!("{:?}", bt);
}
}
}
0: backtrace::backtrace::trace_unsynchronized
1: backtrace::backtrace::trace
2: backtrace::capture::Backtrace::create
3: backtrace::capture::Backtrace::new
4: <backtrace::capture::Backtrace as snafu::GenerateBacktrace>::generate
5: so::SampleError<__T0>::fail
6: so::gamma
7: so::beta
8: so::alpha
9: so::main
10: std::rt::lang_start::{{closure}}
11: std::panicking::try::do_call
12: __rust_maybe_catch_panic
13: std::rt::lang_start_internal
14: std::rt::lang_start
15: main
Disclaimer: I'm the primary author of SNAFU.
You are correct that this isn't thoroughly described in the user's guide and I've created an issue to improve that. The most relevant section is the one about feature flags.
There are multiple tests for backtraces in the SNAFU repository that you could look to:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With