diff --git a/src/main/mod.rs b/src/main/mod.rs index d3108e53..a6fd9cef 100644 --- a/src/main/mod.rs +++ b/src/main/mod.rs @@ -7,6 +7,7 @@ use conduwuit_core::{debug_info, error}; mod clap; mod logging; mod mods; +mod panic; mod restart; mod runtime; mod sentry; @@ -19,6 +20,8 @@ use server::Server; pub use crate::clap::Args; pub fn run() -> Result<()> { + panic::init(); + let args = clap::parse(); run_with_args(&args) } diff --git a/src/main/panic.rs b/src/main/panic.rs new file mode 100644 index 00000000..45be7881 --- /dev/null +++ b/src/main/panic.rs @@ -0,0 +1,34 @@ +use std::{backtrace::Backtrace, panic}; + +/// Initialize the panic hook to capture backtraces at the point of panic. +/// This is needed to capture the backtrace before the unwind destroys it. +pub(crate) fn init() { + let default_hook = panic::take_hook(); + + panic::set_hook(Box::new(move |info| { + let backtrace = Backtrace::force_capture(); + + let location_str = info.location().map_or_else(String::new, |loc| { + format!(" at {}:{}:{}", loc.file(), loc.line(), loc.column()) + }); + + let message = if let Some(s) = info.payload().downcast_ref::<&str>() { + (*s).to_owned() + } else if let Some(s) = info.payload().downcast_ref::() { + s.clone() + } else { + "Box".to_owned() + }; + + let thread_name = std::thread::current() + .name() + .map_or_else(|| "".to_owned(), ToOwned::to_owned); + + eprintln!( + "\nthread '{thread_name}' panicked{location_str}: \ + {message}\n\nBacktrace:\n{backtrace}" + ); + + default_hook(info); + })); +}