2个版本

0.1.1 2023年7月31日
0.1.0 2023年7月30日

#1361 in 异步

MIT许可证

17KB
108 代码行

tasktrace

异步函数的逻辑'栈'跟踪。

此crate允许您捕获正在运行的异步任务的堆栈跟踪。

用法

要使用,使用tasktrace::traced将您感兴趣的future(通常是顶层future)包装起来,并使用返回的句柄在任何时候请求堆栈跟踪。

#[tokio::main]
async fn main() {
    let (foo_fut, trace_handle) = tasktrace::traced(foo());
    tokio::spawn(foo_fut);

    println!("{}", trace_handle.backtrace().await.unwrap());
}

async fn pending() {
    let mut waker = None;
    std::future::poll_fn(|cx| {
        // Pretend to stash the waker for some future time like a real leaf Future would do.
        // This is what records the stacktrace.
        waker = Some(cx.waker().clone());
        std::task::Poll::Pending
    }).await
}

async fn foo() {
    bar().await;
}

async fn bar() {
    tokio::join!(fiz(), buz());
}

async fn fiz() {
    pending().await;
}

async fn buz() {
    baz().await;
}

async fn baz() {
    pending().await;
}

此示例程序将打印出类似以下内容:

╼ <tasktrace::TracedTask<F> as core::future::future::Future>::poll::{{closure}} at /home/petrosagg/projects/tasktrace/src/lib.rs:116:50
 └╼ taskdump::foo::{{closure}} at /home/petrosagg/projects/tasktrace/examples/taskdump.rs:18:11
    └╼ taskdump::bar::{{closure}} at /home/petrosagg/projects/tasktrace/examples/taskdump.rs:22:5
       └╼ <tokio::future::poll_fn::PollFn<F> as core::future::future::Future>::poll at /home/petrosagg/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.29.1/src/future/poll_fn.rs:58:9
          ├╼ taskdump::bar::{{closure}}::{{closure}} at /home/petrosagg/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.29.1/src/macros/join.rs:126:24
          │  └╼ <tokio::future::maybe_done::MaybeDone<Fut> as core::future::future::Future>::poll at /home/petrosagg/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.29.1/src/future/maybe_done.rs:68:48
          │     └╼ taskdump::fiz::{{closure}} at /home/petrosagg/projects/tasktrace/examples/taskdump.rs:26:15
          │        └╼ taskdump::pending::{{closure}} at /home/petrosagg/projects/tasktrace/examples/taskdump.rs:14:8
          │           └╼ <core::future::poll_fn::PollFn<F> as core::future::future::Future>::poll at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/core/src/future/poll_fn.rs:64:9
          │              └╼ taskdump::pending::{{closure}}::{{closure}} at /home/petrosagg/projects/tasktrace/examples/taskdump.rs:12:22
          │                 └╼ <core::task::wake::Waker as core::clone::Clone>::clone at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/core/src/task/wake.rs:342:29
          │                    └╼ tasktrace::clone_raw at /home/petrosagg/projects/tasktrace/src/lib.rs:135:5
          └╼ taskdump::bar::{{closure}}::{{closure}} at /home/petrosagg/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.29.1/src/macros/join.rs:126:24
             └╼ <tokio::future::maybe_done::MaybeDone<Fut> as core::future::future::Future>::poll at /home/petrosagg/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.29.1/src/future/maybe_done.rs:68:48
                └╼ taskdump::buz::{{closure}} at /home/petrosagg/projects/tasktrace/examples/taskdump.rs:30:11
                   └╼ taskdump::baz::{{closure}} at /home/petrosagg/projects/tasktrace/examples/taskdump.rs:34:15
                      └╼ taskdump::pending::{{closure}} at /home/petrosagg/projects/tasktrace/examples/taskdump.rs:14:8
                         └╼ <core::future::poll_fn::PollFn<F> as core::future::future::Future>::poll at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/core/src/future/poll_fn.rs:64:9
                            └╼ taskdump::pending::{{closure}}::{{closure}} at /home/petrosagg/projects/tasktrace/examples/taskdump.rs:12:22
                               └╼ <core::task::wake::Waker as core::clone::Clone>::clone at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/core/src/task/wake.rs:342:29
                                  └╼ tasktrace::clone_raw at /home/petrosagg/projects/tasktrace/src/lib.rs:135:5

工作原理

此crate利用了所有叶future都必须在稍后某个时间点克隆提供的上下文Waker才能调用它的事实。

当请求跟踪的future捕获调用栈时,它将正常waker包装成一个其Waker::clone方法被设置为捕获堆栈跟踪的waker。由于只有叶future会交互和克隆waker,因此堆栈跟踪将必然包含所需的调用栈。

如果正在等待多个future(例如,通过select!),则将为每个轮询的future捕获多个堆栈跟踪,并将它们的组合堆栈跟踪显示为树形结构。

依赖关系

~3.5–4.5MB
~90K SLoC