It's an area of active development! I'm hopeful the situation will improve significantly this year.
For tracing suspended Futures, I've worked on a few approaches:
1. If you don't mind annotating your async functions, you can use the async-backtrace crate, which provides pretty-printing out-of-the-box: https://crates.io/crates/async-backtrace
2. If you are already using the `tracing` ecosystem, you can use the tracing-causality crate (it doesn't yet include pretty-printing, but it's not too hard to add that on): https://crates.io/crates/tracing-causality
For tracing suspended Futures, I've worked on a few approaches:
1. If you don't mind annotating your async functions, you can use the async-backtrace crate, which provides pretty-printing out-of-the-box: https://crates.io/crates/async-backtrace
2. If you are already using the `tracing` ecosystem, you can use the tracing-causality crate (it doesn't yet include pretty-printing, but it's not too hard to add that on): https://crates.io/crates/tracing-causality
3. If you are only supporting Linux (and maybe MacOS) and you aren't stripping away debuginfo from your binaries, you can build atop the deflect crate (https://jack.wrenn.fyi/blog/deflect/). If your `Future` purely consists of `async` blocks, Tyler Mandry's reflection based approach works well: https://github.com/tmandry/rust-dbg-ext/tree/async-backtrace...
For analyzing stack traces of active futures, I'm not aware of any good ways to reliably filter out irrelevant frames (e.g., frames from the runtime).