#![doc(html_root_url = "https://docs.rs/log-panics/2.0.0")]
#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#[macro_use]
extern crate log;
#[cfg(feature = "with-backtrace")]
extern crate backtrace;
use std::{fmt, panic, thread};
use backtrace::Backtrace;
#[cfg(not(feature = "with-backtrace"))]
mod backtrace {
#[derive(Default)]
pub struct Backtrace;
}
struct Shim(Backtrace);
impl fmt::Debug for Shim {
#[cfg(feature = "with-backtrace")]
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
if !self.0.frames().is_empty() {
write!(fmt, "\n{:?}", self.0)
} else {
Ok(())
}
}
#[inline]
#[cfg(not(feature = "with-backtrace"))]
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
Ok(())
}
}
#[cfg(feature = "with-backtrace")]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum BacktraceMode {
Off,
Unresolved,
Resolved
}
#[derive(Debug)]
pub struct Config {
make_backtrace: fn() -> Backtrace,
}
impl Config {
pub fn new() -> Self {
Self {
make_backtrace: Backtrace::default,
}
}
#[cfg(feature = "with-backtrace")]
pub fn backtrace_mode(mut self, mode: BacktraceMode) -> Self {
self.make_backtrace = match mode {
BacktraceMode::Off => || Backtrace::from(vec![]),
BacktraceMode::Unresolved => Backtrace::new_unresolved,
BacktraceMode::Resolved => Backtrace::default,
};
self
}
pub fn install_panic_hook(self) {
panic::set_hook(Box::new(move |info| {
let backtrace = (self.make_backtrace)();
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::<String>() {
Some(s) => &**s,
None => "Box<Any>",
},
};
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)
),
}
}));
}
}
impl Default for Config {
fn default() -> Self {
Self::new()
}
}
pub fn init() {
Config::new().install_panic_hook()
}