diff --git a/Cargo.lock b/Cargo.lock index 4f0b516..160ce90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -119,6 +119,7 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" name = "bitwarden_rs" version = "1.0.0" dependencies = [ + "backtrace", "chashmap", "chrono", "data-encoding", diff --git a/Cargo.toml b/Cargo.toml index bdd9385..e8187fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -118,6 +118,9 @@ idna = "0.2.0" # CLI argument parsing structopt = "0.3.11" +# Logging panics to logfile instead stderr only +backtrace = "0.3.45" + [patch.crates-io] # Use newest ring rocket = { git = 'https://github.com/SergioBenitez/Rocket', rev = 'b95b6765e1cc8be7c1e7eaef8a9d9ad940b0ac13' } diff --git a/src/main.rs b/src/main.rs index 4de84ba..a8efb1d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,11 +20,14 @@ extern crate derive_more; #[macro_use] extern crate num_derive; +extern crate backtrace; + use std::{ fs::create_dir_all, path::Path, process::{exit, Command}, str::FromStr, + panic, thread, fmt // For panic logging }; #[macro_use] @@ -42,6 +45,16 @@ pub use error::{Error, MapResult}; use structopt::StructOpt; +// Used for catching panics and log them to file instead of stderr +use backtrace::Backtrace; +struct Shim(Backtrace); + +impl fmt::Debug for Shim { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "\n{:?}", self.0) + } +} + #[derive(Debug, StructOpt)] #[structopt(name = "bitwarden_rs", about = "A Bitwarden API server written in Rust")] struct Opt { @@ -142,6 +155,44 @@ fn init_logging(level: log::LevelFilter) -> Result<(), fern::InitError> { logger.apply()?; + // Catch panics and log them instead of default output to StdErr + panic::set_hook(Box::new(|info| { + let backtrace = Backtrace::new(); + + let thread = thread::current(); + let thread = thread.name().unwrap_or("unnamed"); + + let msg = match info.payload().downcast_ref::<&'static str>() { + Some(s) => *s, + None => match info.payload().downcast_ref::() { + Some(s) => &**s, + None => "Box", + }, + }; + + match info.location() { + Some(location) => { + error!( + target: "panic", "thread '{}' panicked at '{}': {}:{}{:?}", + thread, + msg, + location.file(), + location.line(), + Shim(backtrace) + ); + } + None => { + error!( + target: "panic", + "thread '{}' panicked at '{}'{:?}", + thread, + msg, + Shim(backtrace) + ) + } + } + })); + Ok(()) }