【问题标题】:How to trace errors when using `anyhow`使用`anyhow`时如何跟踪错误
【发布时间】:2022-01-20 13:33:39
【问题描述】:

使用anyhow crate 时,可以方便地将错误冒泡到应用程序的根目录,在那里进行处理。

但是,有时我想知道错误发生在哪里,但我找不到使用 anyhow 的方法。

我的回溯只提到了根:

   4: mp_parser::main
             at ./src/main.rs:37:5

运行 RUST_BACKTRACE=full 会为我提供详细的内部调用堆栈,但它没有显示错误源自我自己的代码中的位置。

因此,我经常不注释代码的不同部分以找出错误实际发生的位置。

有什么方法可以得到它出现的原始行吗?

【问题讨论】:

  • 使用 snafu 或 thiserror 并进行适当的错误设计,无论如何都是邪恶的(IMO)
  • 也许你可以尝试激活功能features = ["backtrace"]
  • @Stargateur 如果你开发一个库,anyhow 不是一个(完整的)解决方案。但是对于二进制文件,您能否详细说明为什么您认为它“邪恶”?
  • 我刚刚测试了features = ["backtrace"] 设置RUST_BACKTRACE=full 并且它可以正常工作!
  • @rodrigo “它有效”到底是什么意思? release 模式下的行号你搞定了吗?

标签: rust error-handling


【解决方案1】:

我使用以下应用运行了一些测试(均在发布模式下):

use anyhow::{ensure, Result};

fn main() -> Result<()> {
    aa()?;
    Ok(())
}

fn aa() -> Result<()> {
    bb(33)?;
    bb(77)?;
    bb(5)?;
    Ok(())
}

fn bb(p: i32) -> Result<i32> {
    ensure!(p >= 10, "param not big enough!");
    Ok(p)
}

我测试了各种组合:

  • 在 Stable (1.58) 和 Nightly (1.60) 工具链上。
  • 有和没有“回溯”功能;
  • 没有设置RUST_BACKTRACE并将其设置为1full(在此测试中1full之间没有区别)。

当使用RUST_BACKTRACE=1RUST_BACKTRACE=full 运行应用程序时,我们会得到这样的回溯:

Error: param not big enough!

Stack backtrace:
   0: anyhow::error::<impl anyhow::Error>::msg
   1: an::main
   2: std::sys_common::backtrace::__rust_begin_short_backtrace
   3: std::rt::lang_start::{{closure}}
   4: core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once
             at /rustc/5e57faa78aa7661c6000204591558f6665f11abc/library/core/src/ops/function.rs:259:13
   5: std::panicking::try::do_call
             at /rustc/5e57faa78aa7661c6000204591558f6665f11abc/library/std/src/panicking.rs:485:40
   6: std::panicking::try
             at /rustc/5e57faa78aa7661c6000204591558f6665f11abc/library/std/src/panicking.rs:449:19
   7: std::panic::catch_unwind
             at /rustc/5e57faa78aa7661c6000204591558f6665f11abc/library/std/src/panic.rs:136:14
   8: std::rt::lang_start_internal::{{closure}}
             at /rustc/5e57faa78aa7661c6000204591558f6665f11abc/library/std/src/rt.rs:128:48
   9: std::panicking::try::do_call
             at /rustc/5e57faa78aa7661c6000204591558f6665f11abc/library/std/src/panicking.rs:485:40
  10: std::panicking::try
             at /rustc/5e57faa78aa7661c6000204591558f6665f11abc/library/std/src/panicking.rs:449:19
  11: std::panic::catch_unwind
             at /rustc/5e57faa78aa7661c6000204591558f6665f11abc/library/std/src/panic.rs:136:14
  12: std::rt::lang_start_internal
             at /rustc/5e57faa78aa7661c6000204591558f6665f11abc/library/std/src/rt.rs:128:20
  13: main
  14: __libc_start_main
  15: _start

我还测试了“回溯”功能:

    anyhow = { version = "1.0.52", features = ["backtrace"] }

,但这似乎没有向堆栈跟踪添加任何有价值的信息。

我们只看到1: an::main 的原因是在这个简单的程序中,其他函数是内联的。

我们可以尝试禁用特定函数的内联,如下所示:

#[inline(never)]
fn aa() -> Result<()> {...

现在我们得到这个:

Stack backtrace:
   0: anyhow::error::<impl anyhow::Error>::msg
   1: an::aa
   2: std::sys_common::backtrace::__rust_begin_short_backtrace
   ...

这可能有助于缩小错误源自单个函数的位置,但仍远非完美。而且,显然,仅仅为了这个目的而禁用内联通常不是一个好主意。

看来我们可以做到这一点:

ensure!(p >= 10, "param not big enough! {}:{}", file!(), line!());

即使在发布模式下,我们也可以获得有关文件和行的信息:

Error: param not big enough! src/main.rs:18

很明显, 可以围绕它构建一些东西,但我不熟悉这些宏的工作原理以及开销是多少。如果有人能对此有所了解,我会很高兴。


按照罗德里戈的建议,我也试过这个:

[profile.release]
debug = true

结果看起来很棒:

Stack backtrace:
   0: anyhow::error::<impl anyhow::Error>::msg
             at /home/xyz/.cargo/registry/src/github.com-1ecc6299db9ec823/anyhow-1.0.52/src/error.rs:79:36
   1: an::bb
             at ./src/main.rs:18:5
   2: an::aa
             at ./src/main.rs:13:2
   3: an::main
             at ./src/main.rs:6:2
   4: core::ops::function::FnOnce::call_once
             at /rustc/5e57faa78aa7661c6000204591558f6665f11abc/library/core/src/ops/function.rs:227:5
   5: std::sys_common::backtrace::__rust_begin_short_backtrace
             at /rustc/5e57faa78aa7661c6000204591558f6665f11abc/library/std/src/sys_common/backtrace.rs:123:18
   ...
   

因此,二进制大小增加了 16%。

设置debug = 1 产生与debug = true 相同的堆栈跟踪(顺便说一句,与debug = 2 相同),但与默认debug = 0 相比,二进制大小仅大6%

我尚未测试该设置是否/如何影响性能。

【讨论】:

    猜你喜欢
    • 2013-07-23
    • 1970-01-01
    • 2017-06-15
    • 2011-07-03
    • 2019-12-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-25
    • 2014-09-28
    相关资源
    最近更新 更多