-
Notifications
You must be signed in to change notification settings - Fork 662
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tracing: add an example of
tracing
in a panic hook (#1375)
It turns out that when using the global dispatcher, emitting tracing events in a panic hook will capture the span in which the program panicked. This is very handy for debugging panics! Thanks a lot to @nate_mara for pointing this out to me on twitter --- I hadn't even thought of it! Since it isn't necessarily immediately obvious that this works, I thought it would be nice to add an example.
- Loading branch information
Showing
1 changed file
with
51 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
//! This example demonstrates how `tracing` events can be recorded from within a | ||
//! panic hook, capturing the span context in which the program panicked. | ||
|
||
fn main() { | ||
let subscriber = tracing_subscriber::fmt() | ||
.with_max_level(tracing::Level::TRACE) | ||
.finish(); | ||
|
||
// NOTE: Using `tracing` in a panic hook requires the use of the *global* | ||
// trace dispatcher (`tracing::subscriber::set_global_default`), rather than | ||
// the per-thread scoped dispatcher | ||
// (`tracing::subscriber::with_default`/`set_default`). With the scoped trace | ||
// dispatcher, the subscriber's thread-local context may already have been | ||
// torn down by unwinding by the time the panic handler is reached. | ||
tracing::subscriber::set_global_default(subscriber).unwrap(); | ||
|
||
// Set a panic hook that records the panic as a `tracing` event at the | ||
// `ERROR` verbosity level. | ||
// | ||
// If we are currently in a span when the panic occurred, the logged event | ||
// will include the current span, allowing the context in which the panic | ||
// occurred to be recorded. | ||
std::panic::set_hook(Box::new(|panic| { | ||
// If the panic has a source location, record it as structured fields. | ||
if let Some(location) = panic.location() { | ||
// On nightly Rust, where the `PanicInfo` type also exposes a | ||
// `message()` method returning just the message, we could record | ||
// just the message instead of the entire `fmt::Display` | ||
// implementation, avoiding the duplciated location | ||
tracing::error!( | ||
message = %panic, | ||
panic.file = location.file(), | ||
panic.line = location.line(), | ||
panic.column = location.column(), | ||
); | ||
} else { | ||
tracing::error!(message = %panic); | ||
} | ||
})); | ||
|
||
for i in 0..10 { | ||
check_number(i); | ||
} | ||
} | ||
|
||
#[tracing::instrument] | ||
fn check_number(x: i32) { | ||
if x % 2 == 0 { | ||
panic!("I don't work with even numbers!"); | ||
} | ||
} |