如何使用“catch_unwind”获取恐慌信息(即堆栈跟踪)?

fzy*_*cjy 6 error-handling panic rust

如果使用set_hook,我们可以获得大量信息,尤其是堆栈跟踪 - 这非常有帮助。然而,对于catch_unwind,我只得到 a Result,其中几乎不包含任何有用的信息。因此,我想知道如何使用 Rust 获取恐慌信息(尤其是堆栈跟踪)catch_unwind

我处于多线程环境中,其中有许多线程同时运行,任何线程都可能出现恐慌。我想我应该set_hook与 一起使用catch_unwind,并且还使用一些线程局部变量,但我不确定它是否可行以及细节。

kmd*_*eko 7

您可以使用backtrace crate在恐慌钩子中获取回溯,但这并没有帮助,catch_unwind因为堆栈已经从发生恐慌的地方展开。

您可以做的就是通过将回溯从恐慌钩子存储在线程局部变量中,将其偷偷放入捕获器中。这应该是可靠的,因为恐慌时的恐慌是一种自动进程中止(因此您无法覆盖尚未捕获的进程),并且恐慌不会跨线程边界传播(加入恐慌线程会返回一个恐慌为错误)。Result<_, Box<dyn Any>>

这是一个完整的示例:

use std::cell::RefCell;
use backtrace::Backtrace;

thread_local! {
    static Backtrace: RefCell<Option<Backtrace>> = RefCell::new(None);
}

fn f() {
    panic!("xyz");
}

fn g() {
    if let Err(err) = std::panic::catch_unwind(f) {
        let b = Backtrace.with(|b| b.borrow_mut().take()).unwrap();
        println!("at panic:\n{:?}", b);
    }
}

fn main() {
    std::panic::set_hook(Box::new(|_| {
        let trace = Backtrace::new();
        Backtrace.with(move |b| b.borrow_mut().replace(trace));
    }));
    
    g();
}
Run Code Online (Sandbox Code Playgroud)