crates/nornir-crashlog/examples/crash_probe.rs
// **The deliberate crash.** ONE source file, built under TWO names.
//
// `examples/crash_probe_gpu.rs` is a single `include!` of this file, so the two
// `[[example]]` artifacts are compiled from the same source TEXT and the *only*
// difference between them is `CARGO_BIN_NAME`. That is deliberate: it is
// the dwarves `dwarves-ui` / `dwarves-ui-gpu` shape (two `[[bin]]`s off one `main.rs`)
// reproduced in a crate that builds in seconds, so
// `tests/a_panic_leaves_a_file.rs::two_names_off_one_source_report_two_variants` can
// assert the discriminator without a twenty-minute GUI build.
//
// `argv[1]` picks WHERE the panic happens, because a hook that catches a main-thread
// panic and misses a worker's is a hook that would have missed the measured crash:
//
// * `main` — panic on the main thread
// * `thread` — panic on a NAMED spawned thread, and let the process die on the join
// * `nested` — panic inside a closure two frames deep on an unnamed thread
// * `clean` — do not panic at all (the control: no panic ⇒ no file)
fn main() {
// The variant comes from `CARGO_BIN_NAME`, expanded HERE, in the target being
// compiled. Nothing else in this file differs between the two artifacts.
let installed = nornir_crashlog::install_crash_hook!(
env!("CARGO_PKG_VERSION"),
// A stand-in for a git sha; the real callers pass their build stamp.
"probe-build"
);
// The startup announcement — printed BEFORE the crash, which is the whole point.
println!("{}", installed.announce());
match std::env::args().nth(1).unwrap_or_default().as_str() {
"main" => panic!("deliberate crash probe: main thread"),
"thread" => {
let h = std::thread::Builder::new()
.name("render-worker".to_string())
.spawn(|| panic!("deliberate crash probe: non-main thread"))
.expect("spawn the probe thread");
// A panicking thread does NOT end the process; the join is what surfaces it.
// This mirrors an eframe worker: the window stays up and the record is the
// only trace, which is exactly why the file has to exist.
let _ = h.join();
std::process::exit(101);
}
"nested" => {
let h = std::thread::spawn(|| {
let f = || -> i32 { panic!("deliberate crash probe: nested closure") };
let g = || f();
g()
});
let _ = h.join();
std::process::exit(101);
}
"clean" => println!("crash-probe: no panic requested"),
other => {
eprintln!("crash-probe: unknown mode `{other}` (main|thread|nested|clean)");
std::process::exit(2);
}
}
}