node: Log Panics

Register a panic handler that logs a backtrace via the `backtrace`
crate, instead of setting `RUST_BACKTRACE`.

Co-authored-by: Lorenz Leutgeb <lorenz.leutgeb@radicle.xy>
This commit is contained in:
Fintan Halpenny 2025-07-28 11:15:24 +01:00
parent 0441b048f9
commit ed8b086045
3 changed files with 37 additions and 8 deletions

1
Cargo.lock generated
View File

@ -2908,6 +2908,7 @@ name = "radicle-node"
version = "0.15.0"
dependencies = [
"amplify",
"backtrace",
"bloomy",
"bytes",
"chrono",

View File

@ -10,12 +10,13 @@ build = "build.rs"
rust-version.workspace = true
[features]
default = ["systemd", "structured-logger"]
default = ["backtrace", "systemd", "structured-logger"]
systemd = ["dep:radicle-systemd"]
test = ["radicle/test", "radicle-crypto/test", "radicle-crypto/cyphernet", "radicle-protocol/test", "qcheck", "snapbox"]
[dependencies]
amplify = { workspace = true }
backtrace = { version = "0.3.75", optional = true }
bloomy = "1.2"
bytes = { workspace = true }
chrono = { workspace = true, features = ["clock"] }

View File

@ -300,15 +300,40 @@ fn initialize_logging(options: &LogOptions) -> Result<(), Box<dyn std::error::Er
Ok(())
}
fn main() {
// If `RUST_BACKTRACE` does not have a value, then we set it to capture
// backtraces for better debugging, otherwise we keep the environments
// value.
const RUST_BACKTRACE: &str = "RUST_BACKTRACE";
if std::env::var_os(RUST_BACKTRACE).is_none() {
std::env::set_var(RUST_BACKTRACE, "1");
fn panic_hook(info: &std::panic::PanicHookInfo) {
#[cfg(feature = "backtrace")]
let backtrace = format!("{:?}", backtrace::Backtrace::new());
#[cfg(not(feature = "backtrace"))]
let backtrace = " (no backtrace available)";
let thread = std::thread::current();
let thread = thread.name().unwrap_or("<unnamed>");
let msg = info
.payload()
.downcast_ref::<&'static str>()
.copied()
.or(info.payload().downcast_ref::<String>().map(|s| s.as_str()))
.unwrap_or("Box<Any>");
match info.location() {
Some(location) => {
log::error!(
target: "panic", "thread '{thread}' panicked at '{msg}': {}:{}{backtrace}",
location.file(),
location.line(),
);
}
None => log::error!(
target: "panic", "thread '{thread}' panicked at '{msg}'{backtrace}",
),
}
log::logger().flush();
}
fn main() {
let options = parse_options().unwrap_or_else(|err| {
// The lexopt errors read nicely with a comma.
eprintln!("Failed to parse options, {err:#}");
@ -320,6 +345,8 @@ fn main() {
exit(3);
});
std::panic::set_hook(Box::new(panic_hook));
if let Err(err) = execute(options) {
log::error!(target: "node", "{err:#}");
exit(1);