Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

examples: add tokio_panic_hook example #1593

Merged
merged 2 commits into from
Sep 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions examples/examples/panic_hook.rs
Original file line number Diff line number Diff line change
@@ -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 collector = tracing_subscriber::fmt()
Expand Down
54 changes: 54 additions & 0 deletions examples/examples/tokio_panic_hook.rs
Original file line number Diff line number Diff line change
@@ -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 collector = 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::collect::set_global_default`), rather than
// the per-thread scoped dispatcher
// (`tracing::collect::with_default`/`set_default`). With the scoped trace
// dispatcher, the collector's thread-local context may already have been
// torn down by unwinding by the time the panic handler is reached.
tracing::collect::set_global_default(collector).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!")
}