async-backtrace is a crate that enables you to efficiently track and view the state of asynchronous tasks in your application.
In synchronous, multi-threaded applications, you can investigate deadlocks by inspecting stack traces of all running threads. Unfortunately, this approach breaks down for most asynchronous Rust applications, since suspended tasks — tasks that are not actively being polled — are invisible to traditional stack traces. The async-backtrace
crate fills this gap, allowing you see the state of these hidden tasks. It is architected to be highly efficient without configuration, and is suitable for deployment in production environments.
This crate complements (but is not yet integrated with) the tracing
library and tokio-console
. Use async-backtrace
for a birds-eye view of task state in your application, and tracing
for isolating the inputs that lead to that state. If your application uses the tokio runtime, you can use tokio-console
for a deeper look into your application's interactions with tokio's synchronization primitives.
Getting Started
To use async-backtrace
, first add the crate to your Cargo.toml
file:
[dependencies]
async-backtrace = "0.2"
Then, to include your async fn
s in async task traces, simply annotate them with #[async_backtrace::framed]
and call taskdump_tree
to receive pretty-printed trees of your application's tasks. For instance:
#[tokio::main(flavor = "current_thread")]
async fn main() {
tokio::select! {
// run the following branches in order of their appearance
biased;
// spawn task #1
_ = tokio::spawn(foo()) => { unreachable!() }
// spawn task #2
_ = tokio::spawn(foo()) => { unreachable!() }
// print the running tasks
_ = tokio::spawn(async {}) => {
println!("{}", async_backtrace::taskdump_tree(true));
}
};
}
#[async_backtrace::framed]
async fn foo() {
bar().await;
}
#[async_backtrace::framed]
async fn bar() {
baz().await;
}
#[async_backtrace::framed]
async fn baz() {
std::future::pending::<()>().await
}
Running the above example prints the trees:
╼ multiple::foo::{{closure}} at backtrace/examples/multiple.rs:22:1
└╼ multiple::bar::{{closure}} at backtrace/examples/multiple.rs:27:1
└╼ multiple::baz::{{closure}} at backtrace/examples/multiple.rs:32:1
╼ multiple::foo::{{closure}} at backtrace/examples/multiple.rs:22:1
└╼ multiple::bar::{{closure}} at backtrace/examples/multiple.rs:27:1
└╼ multiple::baz::{{closure}} at backtrace/examples/multiple.rs:32:1
See here for more examples!
Feedback Welcome
This launch is only an initial release. Work on async-backtrace
has just begun. To guide our development, we need your feedback. So, give it a shot, and let us know how it goes. Please file issues and ping us on Discord.