#[cfg(doc)]
use crate::{shutdown, Shutdown};
use crate::{Event, Level, Value};
#[cfg(doc)]
use std::process::abort;
use std::{
collections::BTreeMap,
convert::TryFrom,
panic::{self, PanicInfo},
};
pub fn set_hook(
before_send: Option<Box<dyn Fn(Event) -> Event + 'static + Send + Sync>>,
hook: Option<Box<dyn Fn(&PanicInfo) + 'static + Send + Sync>>,
) {
panic::set_hook(Box::new(move |panic_info| {
let mut event = Event::new_message(
Level::Error,
Some("rust panic".into()),
panic_info.to_string(),
);
if let Some(location) = panic_info.location() {
let mut extra = BTreeMap::new();
extra.insert("file", Value::from(location.file()));
if let Ok(line) = i32::try_from(location.line()) {
extra.insert("line", line.into());
}
if let Ok(column) = i32::try_from(location.column()) {
extra.insert("column", column.into());
}
event.insert("extra", extra);
}
event.add_stacktrace(0);
if let Some(before_send) = &before_send {
event = before_send(event);
}
event.capture();
if let Some(hook) = &hook {
hook(panic_info);
}
}));
}
#[cfg(test)]
#[rusty_fork::fork_test(timeout_ms = 60000)]
fn hook() {
use std::{
sync::atomic::{AtomicBool, Ordering},
thread,
};
static BEFORE_SEND: AtomicBool = AtomicBool::new(false);
static HOOK: AtomicBool = AtomicBool::new(false);
set_hook(None, None);
set_hook(
Some(Box::new(|event| {
BEFORE_SEND.store(true, Ordering::SeqCst);
event
})),
Some(Box::new(|_| HOOK.store(true, Ordering::SeqCst))),
);
thread::spawn(|| panic!("this panic is a test"))
.join()
.unwrap_err();
assert!(BEFORE_SEND.load(Ordering::SeqCst));
assert!(HOOK.load(Ordering::SeqCst));
}