获取 Rust 中多重传播错误的详细信息?

问题描述 投票:0回答:1

我可以看到几个关于 Rust 中传播错误的问题,但没有一个真正与我想要实现的目标有关。

开发第一个小型 Rust 项目时,我已经养成了使用此返回签名的习惯:

-> Result<[something from success], Box<dyn std::error::Error>> {
    ...

...并在这些方法的主体中尽可能多地使用

?
运算符。

但现在我发现有时很难找出错误来自哪里,即使使用

backtrace::Backtrace
也是如此。事实上这是一个 PyO3 项目,所以主要的“入口点”看起来像这样:

#[pyfunction]
fn index_documents(py: Python, dir_root_path_str: String, index_name: String, op_type: String, app_version_str: String, 
    index_version_str: String, option_suspended_framework: Option<HandlingFramework>) 
    -> PyResult<(usize, usize, Option<HandlingFramework>)> {
    py.allow_threads(move || {
        match index_docs_rust(dir_root_path_str, index_name, op_type, app_version_str, index_version_str, option_suspended_framework) {
            Ok(three_tuple) => Ok(three_tuple),
            Err(e) => {
                error!("backtrace:\n{}", Backtrace::force_capture());
                Err(PyErr::new::<PyTypeError, _>(e.to_string()))
            }
        }
    })
}

fn index_docs_rust( ... 
    -> Result<(usize, usize, Option<HandlingFramework>), Box<dyn std::error::Error>> {
    // makes structs, which call multiple methods, create other structs, which call their
    // own multiple methods, etc.

force_capture
中生成了很多行,但实际上没有一个为您提供堆栈跟踪
(即之后)
index_documents

中的行,即使在进行开发编译时也是如此。

据我了解(不多),我相信与 Python 不同,跟踪信息实际上并不随错误对象一起传输。

我找到了这个答案

,这可能是尽可能好的解决方案。但这样做的麻烦在于(看起来)你必须将“预期”代码放在可能发生错误的任何地方......这会破坏对象:你不妨使用 
match
 块并将内容记录在
Err分支。但事实上,这并不是全面有用的:真正有用的堆栈跟踪将向您准确显示(如在 Python 中)代码在错误发生之前通过多种方法采用的完整路径

Rust 有什么方法可以做到这一点吗?

rust error-handling stack-trace
1个回答
0
投票

感谢 kmdreko 提供的解决方案。详细内容如下。

在 Cargo.toml 中:

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

添加永久或临时环境变量:

(SET) RUST_BACKTRACE=1

(注意可能还有其他方法可以打开回溯......)

在每个文件中:

use anyhow::{anyhow, Result};

...这似乎会在该文件的持续时间内覆盖

std::result::Result
。所以现在你必须使用仅带有一个类型参数的
Result

典型方法签名:

fn do_something(&self, param: String) -> anyhow::Result<()> {
   ...

然后您可以在该方法的主体中使用

?
并进行适当的函数调用。

您可以按如下方式“包装”

String
Error
(不是感叹号:这是一个宏):

return Err(anyhow!(msg))

return Err(anyhow!(e))

或者(

lock()
方法有点复杂):

let mut vec = my_mutex.lock().map_err(|_| anyhow!("lock poisoned!"))?;

在调用路径顶部的函数中:

...
match self.do_something(my_string) {
    Ok() => Ok(),
    Err(e) => {
        error!("e {:#?}\ne.backtrace():\n{}", e, e.backtrace());
        Err(e)
    }
}

然后将完整的堆栈跟踪打印到错误行,包括行号。最初似乎不包括发生错误的实际行号(只是对该方法的调用),但在重新检查时,我现在看到跟踪实际上给出了该行号...

此外,我找不到将

Box<dyn std::error::Error>
“转换”为
anyhow::Error
的方法。因此,整个模块确实必须切换为使用
anyhow
的处理方式。

© www.soinside.com 2019 - 2024. All rights reserved.