examples: add tokio_panic_hook example (#1593)

It turns out panic hooks also work nicely even when panics are captured.
I figured we may as well have an example demoing this!
This commit is contained in:
Eliza Weisman 2021-09-24 12:15:43 -07:00
parent 3b038ed3ad
commit 4f9987dcd1
2 changed files with 58 additions and 0 deletions

View File

@ -1,5 +1,9 @@
//! This example demonstrates how `tracing` events can be recorded from within a
//! panic hook, capturing the span context in which the program panicked.
//!
//! A custom panic hook can also be used to record panics that are captured
//! using `catch_unwind`, such as when Tokio catches panics in spawned async
//! tasks. See the `tokio_panic_hook.rs` example for an example of this.
fn main() {
let subscriber = tracing_subscriber::fmt()

View File

@ -0,0 +1,54 @@
//! This example demonstrates that a custom panic hook can be used to log panic
//! messages even when panics are captured (such as when a Tokio task panics).
//!
//! This is essentially the same as the `panic_hook.rs` example, but modified to
//! spawn async tasks using the Tokio runtime rather than panicking in a
//! synchronous function. See the `panic_hook.rs` example for details on using
//! custom panic hooks.
#[tokio::main]
async 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();
std::panic::set_hook(Box::new(|panic| {
if let Some(location) = panic.location() {
tracing::error!(
message = %panic,
panic.file = location.file(),
panic.line = location.line(),
panic.column = location.column(),
);
} else {
tracing::error!(message = %panic);
}
}));
// Spawn tasks to check the numbers from 1-10.
let tasks = (0..10)
.map(|i| tokio::spawn(check_number(i)))
.collect::<Vec<_>>();
futures::future::join_all(tasks).await;
tracing::trace!("all tasks done");
}
#[tracing::instrument]
async fn check_number(x: i32) {
tracing::trace!("checking number...");
tokio::task::yield_now().await;
if x % 2 == 0 {
panic!("I don't work with even numbers!");
}
tracing::info!("number checks out!")
}