Retrieving backtrace from a panic in hook in Rust?
Asked Answered
S

3

13

My application needs to send logs to fluentd as JSON format through stdout.
While I'm trying to handle panics and arrange a &std::panic::PanicInfo as a JSON with std::panic::set_hook, I could not find a way to retrieve backtrace from a &PanicInfo.

Is there a way to retrieve a backtrace from a panic in a custom hook?

Strainer answered 28/2, 2019 at 2:14 Comment(0)
I
10

PanicInfo does not contain a backtrace, but you can capture it yourself in the panic hook.

From the set_hook documentation:

Registers a custom panic hook, replacing any that was previously registered.

The panic hook is invoked when a thread panics, but before the panic runtime is invoked. As such, the hook will run with both the aborting and unwinding runtimes. The default hook prints a message to standard error and generates a backtrace if requested, but this behavior can be customized with the set_hook and take_hook functions.

Since the panic hook runs before unwinding, you can capture the backtrace yourself in the panic hook using the backtrace crate already mentioned by @hellow:

panic::set_hook(Box::new(|panic_info| {
    let backtrace = Backtrace::new();
    //  Do something with backtrace and panic_info.
}));
Intreat answered 28/2, 2019 at 12:18 Comment(1)
I thought about providing this answer, but the idea of doing complicated logic in a panic handler feels very dicey...Leucine
P
5

Since Rust 1.65 you can use std::backtrace::Backtrace on the stable channel, no need for an external crate:

std::panic::set_hook(Box::new(|panic_info| {
    let backtrace = std::backtrace::Backtrace::capture();
    eprintln!("My backtrace: {:#?}", backtrace);
}));
Pyrrho answered 29/9, 2023 at 14:48 Comment(0)
S
4

You can use the backtrace crate to generate a backtrace of your current stack.

This is the exact same crate as rust uses internally when you use RUST_BACKTRACE=1 when a panic occurs.

The simplest example (taken from the docs) is just calling backtrace::Backtrace:

use backtrace::Backtrace;

fn main() {
    println!("{:?}", Backtrace::new());
}

which will return (in my example)

stack backtrace:
   0: playground::main::h990b23e2761eee55 (0x564800753fb1)
             at src/main.rs:4
   1: std::rt::lang_start::{{closure}}::hd025ca578a744b4f (0x564800753d3f)
             at /rustc/9fda7c2237db910e41d6a712e9a2139b352e558b/src/libstd/rt.rs:74
   2: std::rt::lang_start_internal::{{closure}}::hdfc28107b5be47c9 (0x564800789f92)
             at src/libstd/rt.rs:59
      std::panicking::try::do_call::h69790245ac2d03fe
             at src/libstd/panicking.rs:310
   3: __rust_maybe_catch_panic (0x564800797409)
             at src/libpanic_unwind/lib.rs:102
   4: std::panicking::try::h9c1cbc5599e1efbf (0x56480078a963)
             at src/libstd/panicking.rs:289
      std::panic::catch_unwind::h0562757d03ff60b3
             at src/libstd/panic.rs:398
      std::rt::lang_start_internal::h540c897fe52ba9c5
             at src/libstd/rt.rs:58
   5: std::rt::lang_start::h78189d3d761bfa86 (0x564800753d18)
             at /rustc/9fda7c2237db910e41d6a712e9a2139b352e558b/src/libstd/rt.rs:74
   6: main (0x5648007540b9)
   7: __libc_start_main (0x7fdab1a23b96)
   8: _start (0x564800753be9)
   9: <unknown> (0x0)
Sperling answered 28/2, 2019 at 6:17 Comment(2)
backtrace requires nightly doesn't it?Susi
IIRC, not if you use the crate. If you use std::backtrace::Backtrace then yesSperling

© 2022 - 2024 — McMap. All rights reserved.