some times it countains the message:
Unknown Source of Error
This is probably because e
may not only be a String
, but also a &str
(well, it can basically be any type, but those two are the most common, you can only get other types when using panic_any()
). When calling panic!()
inside catch_unwind()
, you only get a String
if you are panic!
'ing with arguments, otherwise, the panic message is a &str
(as there is no need for allocating a String
).
I want to send the backtrace to the calling source so that he can log it and then we can debug the rust library afterwards, how can I do that ?
Solution on nightly Rust
On nightly Rust, you can generate a backtrace inside a panic handler via std::backtrace::Backtrace
:
#![feature(backtrace)]
use lazy_static::lazy_static;
use std::sync::{Arc, Mutex};
// on panic, save the backtrace here (as string)
lazy_static! {
static ref BACKTRACE: Arc<Mutex<Option<String>>> = Arc::new(Mutex::new(None));
}
#[no_mangle]
pub fn rust_calculation(json: &str) -> String {
let r = std::panic::catch_unwind(||{
panic!("Panic");
});
let r_str = match r {
Ok(v) => v,
Err(e) => {
let panic_information = match e.downcast::<String>() {
Ok(v) => *v,
Err(e) => match e.downcast::<&str>() {
Ok(v) => v.to_string(),
_ => "Unknown Source of Error".to_owned()
}
};
format!("{}\nBacktrace:\n{}", panic_information, BACKTRACE.lock().unwrap().take().unwrap_or("<Backtrace not found>".to_string()))
}
};
return r_str;
}
fn panic_hook(_: &std::panic::PanicInfo) {
*BACKTRACE.lock().unwrap() = Some(std::backtrace::Backtrace::force_capture().to_string());
}
fn main() {
std::panic::set_hook(Box::new(panic_hook));
println!("{}", rust_calculation(""));
}
Playground link
Output:
Panic
Backtrace:
0: playground::panic_hook
at ./src/main.rs:32:39
1: core::ops::function::Fn::call
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/core/src/ops/function.rs:70:5
2: std::panicking::rust_panic_with_hook
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/panicking.rs:626:17
3: std::panicking::begin_panic::{{closure}}
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/panicking.rs:542:9
4: std::sys_common::backtrace::__rust_end_short_backtrace
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/sys_common/backtrace.rs:141:18
5: std::panicking::begin_panic
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/panicking.rs:541:12
6: playground::rust_calculation::{{closure}}
at ./src/main.rs:13:9
7: std::panicking::try::do_call
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/panicking.rs:401:40
8: __rust_try
9: std::panicking::try
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/panicking.rs:365:19
10: std::panic::catch_unwind
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/panic.rs:434:14
11: rust_calculation
at ./src/main.rs:12:13
12: playground::main
at ./src/main.rs:37:20
13: core::ops::function::FnOnce::call_once
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/core/src/ops/function.rs:227:5
14: std::sys_common::backtrace::__rust_begin_short_backtrace
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/sys_common/backtrace.rs:125:18
15: std::rt::lang_start::{{closure}}
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/rt.rs:63:18
16: core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/core/src/ops/function.rs:259:13
17: std::panicking::try::do_call
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/panicking.rs:401:40
18: std::panicking::try
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/panicking.rs:365:19
19: std::panic::catch_unwind
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/panic.rs:434:14
20: std::rt::lang_start_internal::{{closure}}
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/rt.rs:45:48
21: std::panicking::try::do_call
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/panicking.rs:401:40
22: std::panicking::try
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/panicking.rs:365:19
23: std::panic::catch_unwind
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/panic.rs:434:14
24: std::rt::lang_start_internal
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/rt.rs:45:20
25: std::rt::lang_start
at /rustc/2faabf579323f5252329264cc53ba9ff803429a3/library/std/src/rt.rs:62:5
26: main
27: __libc_start_main
28: _start
Please note that this backtrace contains a few additional frames after the call to panic!
that are due to Rust's internal panic handling code.
Solution with dependencies
If you are not on nightly Rust, but are willing to use additional dependencies, you can do the same with the backtrace
crate (thanks to @BashirAbdelwahed for calling my attention to this):
use lazy_static::lazy_static;
use std::sync::{Arc, Mutex};
// on panic, save the backtrace here (as string)
lazy_static! {
static ref BACKTRACE: Arc<Mutex<Option<String>>> = Arc::new(Mutex::new(None));
}
#[no_mangle]
pub fn rust_calculation(json: &str) -> String {
let r = std::panic::catch_unwind(||{
panic!("Panic");
});
let r_str = match r {
Ok(v) => v,
Err(e) => {
let panic_information = match e.downcast::<String>() {
Ok(v) => *v,
Err(e) => match e.downcast::<&str>() {
Ok(v) => v.to_string(),
_ => "Unknown Source of Error".to_owned()
}
};
format!("{}\nBacktrace:\n{}", panic_information, BACKTRACE.lock().unwrap().take().unwrap_or("<Backtrace not found>".to_string()))
}
};
return r_str;
}
fn panic_hook(_: &std::panic::PanicInfo) {
*BACKTRACE.lock().unwrap() = Some(format!("{:?}", backtrace::Backtrace::new()));
}
fn main() {
std::panic::set_hook(Box::new(panic_hook));
println!("{}", rust_calculation(""));
}
Playground link
Output:
Panic
Backtrace:
0: playground::panic_hook
at src/main.rs:31:55
1: core::ops::function::Fn::call
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/core/src/ops/function.rs:70:5
2: std::panicking::rust_panic_with_hook
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/std/src/panicking.rs:595:17
3: std::panicking::begin_panic::{{closure}}
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/std/src/panicking.rs:520:9
4: std::sys_common::backtrace::__rust_end_short_backtrace
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/std/src/sys_common/backtrace.rs:141:18
5: std::panicking::begin_panic
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/std/src/panicking.rs:519:12
6: playground::rust_calculation::{{closure}}
at src/main.rs:12:9
7: std::panicking::try::do_call
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/std/src/panicking.rs:379:40
8: __rust_try
9: std::panicking::try
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/std/src/panicking.rs:343:19
10: std::panic::catch_unwind
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/std/src/panic.rs:431:14
11: rust_calculation
at src/main.rs:11:13
12: playground::main
at src/main.rs:36:20
13: core::ops::function::FnOnce::call_once
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/core/src/ops/function.rs:227:5
14: std::sys_common::backtrace::__rust_begin_short_backtrace
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/std/src/sys_common/backtrace.rs:125:18
15: std::rt::lang_start::{{closure}}
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/std/src/rt.rs:49:18
16: core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/core/src/ops/function.rs:259:13
std::panicking::try::do_call
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/std/src/panicking.rs:379:40
std::panicking::try
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/std/src/panicking.rs:343:19
std::panic::catch_unwind
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/std/src/panic.rs:431:14
std::rt::lang_start_internal
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/std/src/rt.rs:34:21
17: std::rt::lang_start
at /rustc/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/std/src/rt.rs:48:5
18: main
19: __libc_start_main
20: _start