diff options
author | Eliza Weisman <eliza@buoyant.io> | 2020-11-01 10:48:44 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-01 10:48:44 -0800 |
commit | fede3db76aef95c010c3e0c3da3b732380285097 (patch) | |
tree | 0aa934da682d7f31cf093e69e420ba88601acb6e /tokio/src/util/trace.rs | |
parent | 2b23aa7389686f341e564c8da565a3b4c8b1188f (diff) |
tracing: replace future names with spawn locations in task spans (#3074)
## Motivation
Currently, the per-task `tracing` spans generated by tokio's `tracing`
feature flag include the `std::any::type_name` of the future that was
spawned. When future combinators and/or libraries like Tower are in use,
these future names can get _quite_ long. Furthermore, when formatting
the `tracing` spans with their parent spans as context, any other task
spans in the span context where the future was spawned from can _also_
include extremely long future names.
In some cases, this can result in extremely high memory use just to
store the future names. For example, in Linkerd, when we enable
`tokio=trace` to enable the task spans, there's a spawned task whose
future name is _232990 characters long_. A proxy with only 14 spawned
tasks generates a task list that's over 690 KB. Enabling task spans
under load results in the process getting OOM killed very quickly.
## Solution
This branch removes future type names from the spans generated by
`spawn`. As a replacement, to allow identifying which `spawn` call a
span corresponds to, the task span now contains the source code location
where `spawn` was called, when the compiler supports the
`#[track_caller]` attribute. Since `track_caller` was stabilized in Rust
1.46.0, and our minimum supported Rust version is 1.45.0, we can't
assume that `#[track_caller]` is always available. Instead, we have a
RUSTFLAGS cfg, `tokio_track_caller`, that guards whether or not we use
it. I've also added a `build.rs` that detects the compiler minor
version, and sets the cfg flag automatically if the current compiler
version is >= 1.46. This means users shouldn't have to enable
`tokio_track_caller` manually.
Here's the trace output from the `chat` example, before this change:
![Screenshot_20201030_110157](https://user-images.githubusercontent.com/2796466/97741071-6d408800-1a9f-11eb-9ed6-b25e72f58c7b.png)
...and after:
![Screenshot_20201030_110303](https://user-images.githubusercontent.com/2796466/97741112-7e899480-1a9f-11eb-9197-c5a3f9ea1c05.png)
Closes #3073
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Diffstat (limited to 'tokio/src/util/trace.rs')
-rw-r--r-- | tokio/src/util/trace.rs | 48 |
1 files changed, 14 insertions, 34 deletions
diff --git a/tokio/src/util/trace.rs b/tokio/src/util/trace.rs index 18956a36..96a9db91 100644 --- a/tokio/src/util/trace.rs +++ b/tokio/src/util/trace.rs @@ -1,47 +1,27 @@ cfg_trace! { cfg_rt! { - use std::future::Future; - use std::pin::Pin; - use std::task::{Context, Poll}; - use pin_project_lite::pin_project; - - use tracing::Span; - - pin_project! { - /// A future that has been instrumented with a `tracing` span. - #[derive(Debug, Clone)] - pub(crate) struct Instrumented<T> { - #[pin] - inner: T, - span: Span, - } - } - - impl<T: Future> Future for Instrumented<T> { - type Output = T::Output; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { - let this = self.project(); - let _enter = this.span.enter(); - this.inner.poll(cx) - } - } - - impl<T> Instrumented<T> { - pub(crate) fn new(inner: T, span: Span) -> Self { - Self { inner, span } - } - } + pub(crate) use tracing::instrument::Instrumented; #[inline] + #[cfg_attr(tokio_track_caller, track_caller)] pub(crate) fn task<F>(task: F, kind: &'static str) -> Instrumented<F> { + use tracing::instrument::Instrument; + #[cfg(tokio_track_caller)] + let location = std::panic::Location::caller(); + #[cfg(tokio_track_caller)] + let span = tracing::trace_span!( + target: "tokio::task", + "task", + %kind, + spawn.location = %format_args!("{}:{}:{}", location.file(), location.line(), location.column()), + ); + #[cfg(not(tokio_track_caller))] let span = tracing::trace_span!( target: "tokio::task", "task", %kind, - future = %std::any::type_name::<F>(), ); - Instrumented::new(task, span) + task.instrument(span) } } } |