【问题标题】:How do you see an error's backtrace when using SNAFU?使用 SNAFU 时如何查看错误的回溯?
【发布时间】:2020-03-31 05:13:58
【问题描述】:

如何让Backtrace 与 SNAFU 合作?我试过了,但我只是得到空的回溯。文档似乎很少。

return Error::SampleError {
    msg: "foo".to_string(),
    backtrace: Backtrace::generate(),
};

打印

SampleError { msg: "foo", backtrace: Backtrace(()) }

这是从调用堆栈中非常深的函数抛出的。

【问题讨论】:

  • 我认为你不需要自己调用回溯

标签: error-handling rust backtrace


【解决方案1】:

让我们从这个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()
}

注意它使用上下文选择器SampleError和方法fail而不是直接使用枚举变体来构造错误。

现在我们导入 snafu::Backtrace 并将其添加到我们的错误中,将其命名为 backtrace(如果您必须将其命名为其他名称,请参阅 controlling backtraces)。

use snafu::{Snafu, Backtrace};

#[derive(Debug, Snafu)]
enum Error {
    SampleError { msg: String, backtrace: Backtrace },
}

如果这是一个图书馆,那就是你应该停下来的地方。如果 二进制文件 认为回溯是值得的,您的错误现在将可选启用回溯。这是因为回溯在 Rust 中尚未稳定,因此 SNAFU 必须与多种可能的实现兼容。

如果您要控制二进制文件,则需要决定如何实现回溯。功能标志选择了三个主要实现:

  • backtraces — 提供不透明的 Backtrace 类型
  • backtraces-impl-backtrace-crate — 使用第三方 backtrace crate。 snafu::Backtrace 只是 backtrace::Backtrace 的别名。
  • unstable-backtraces-impl-std — 使用不稳定的标准库 Backtracesnafu::Backtrace 只是 std::backtrace::Backtrace 的别名。

一旦您选择了实现功能标志,请将其添加到您的 Cargo.toml:

[dependencies]
snafu = { version = "0.6.3", features = ["backtraces"] }

然后,您需要在程序中的某个位置处理错误并获取回溯并打印出来。这使用了 ErrorCompat 特征,我鼓励您以详细的方式使用它,以便以后在标准库中稳定时更容易将其删除:

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

免责声明:我是 SNAFU 的主要作者。


你说得对,这在the user's guide 中没有完全描述,我已经创建了an issue to improve that。最相关的部分是关于feature flags 的部分。

您可以查看 SNAFU 存储库中的多个回溯测试:

【讨论】:

    猜你喜欢
    • 2013-10-24
    • 1970-01-01
    • 2017-04-21
    • 2014-04-26
    • 1970-01-01
    • 2020-10-27
    • 2018-06-23
    • 1970-01-01
    相关资源
    最近更新 更多