如何在使用"anywhere"时跟踪错误



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

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

我的回溯只提到了根:

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

运行RUST_BACKTRACE=full为我提供了一个详细的内部调用堆栈,但它并没有显示错误在我自己的代码中的来源。

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

有什么方法可以把原来的线路放到它发生的地方吗?

我用以下应用程序运行了一些测试(全部在发布模式下(:

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相同的堆栈跟踪(BTW与debug = 2相同(,但与默认的debug = 0相比,二进制大小仅大6%

我还没有测试该设置是否/如何影响性能。

最新更新