service_toolkit/panic.rs
1use std::backtrace::Backtrace;
2use std::io::stderr;
3use std::io::Write;
4use std::panic;
5use std::process;
6
7pub fn set_up_panic_hook() {
8 // Currently, even with `panic = abort`, thread panics will still not kill the process, so we'll install our own handler to ensure that any panic exits the process, as most likely some internal state/invariant has become corrupted and it's not safe to continue. Copied from https://stackoverflow.com/a/36031130.
9 let _orig_hook = panic::take_hook();
10 panic::set_hook(Box::new(move |panic_info| {
11 let bt = Backtrace::force_capture();
12 // Don't use `tracing::*` as it may be dangerous to do so from within a panic handler (e.g. it could itself panic).
13 // Do not lock stderr as we could deadlock.
14 // Build string first so we (hopefully) do one write syscall to stderr and don't get it mangled.
15 // Prepend with a newline to avoid mangling with any existing half-written stderr line.
16 let json = format!(
17 "\r\n{}\r\n",
18 serde_json::json!({
19 "level": "CRITICAL",
20 "panic": true,
21 "message": panic_info.to_string(),
22 "stack_trace": bt.to_string(),
23 })
24 );
25 // Try our best to write all and then flush, but don't panic if we don't.
26 let mut out = stderr();
27 let _ = out.write_all(json.as_bytes());
28 let _ = out.flush();
29 process::exit(1);
30 }));
31}