-
Notifications
You must be signed in to change notification settings - Fork 814
tracing: Instrument std::future::Future in tracing #808
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
Changes from all commits
ee0fc2b
5e3905a
6de0d8a
6841eea
83e15dd
58481f8
65818d9
8e7b0a0
388a3d9
a261cdb
7d54948
ed11567
28ddc27
ea5c7b5
2c4f3d1
1f847a4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
use crate::stdlib::pin::Pin; | ||
use crate::stdlib::task::{Context, Poll}; | ||
use crate::stdlib::{future::Future, marker::Sized}; | ||
use crate::{dispatcher, span::Span, Dispatch}; | ||
use pin_project_lite::pin_project; | ||
|
||
/// Attaches spans to a `std::future::Future`. | ||
/// | ||
/// Extension trait allowing futures to be | ||
/// instrumented with a `tracing` [span]. | ||
/// | ||
/// [span]: ../struct.Span.html | ||
pub trait Instrument: Sized { | ||
/// Instruments this type with the provided `Span`, returning an | ||
/// `Instrumented` wrapper. | ||
/// | ||
/// The attached `Span` will be [entered] every time the instrumented `Future` is polled. | ||
/// | ||
/// # Examples | ||
/// | ||
/// Instrumenting a future: | ||
/// | ||
/// ```rust | ||
/// use tracing::Instrument; | ||
/// | ||
/// # async fn doc() { | ||
/// let my_future = async { | ||
/// // ... | ||
/// }; | ||
/// | ||
/// my_future | ||
/// .instrument(tracing::info_span!("my_future")) | ||
/// .await | ||
/// # } | ||
/// ``` | ||
/// | ||
/// [entered]: ../struct.Span.html#method.enter | ||
fn instrument(self, span: Span) -> Instrumented<Self> { | ||
Instrumented { inner: self, span } | ||
} | ||
|
||
/// Instruments this type with the [current] `Span`, returning an | ||
/// `Instrumented` wrapper. | ||
/// | ||
/// If the instrumented type is a future, stream, or sink, the attached `Span` | ||
/// will be [entered] every time it is polled. If the instrumented type | ||
/// is a future executor, every future spawned on that executor will be | ||
/// instrumented by the attached `Span`. | ||
/// | ||
/// This can be used to propagate the current span when spawning a new future. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```rust | ||
/// use tracing::Instrument; | ||
/// | ||
/// # async fn doc() { | ||
/// let span = tracing::info_span!("my_span"); | ||
/// let _enter = span.enter(); | ||
/// | ||
/// // ... | ||
/// | ||
/// let future = async { | ||
/// tracing::debug!("this event will occur inside `my_span`"); | ||
/// // ... | ||
/// }; | ||
/// tokio::spawn(future.in_current_span()); | ||
/// # } | ||
/// ``` | ||
/// | ||
/// [current]: ../struct.Span.html#method.current | ||
/// [entered]: ../struct.Span.html#method.enter | ||
#[inline] | ||
fn in_current_span(self) -> Instrumented<Self> { | ||
self.instrument(Span::current()) | ||
} | ||
} | ||
|
||
/// Extension trait allowing futures to be instrumented with | ||
/// a `tracing` [`Subscriber`]. | ||
/// | ||
/// [`Subscriber`]: ../trait.Subscriber.html | ||
pub trait WithSubscriber: Sized { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i'm on the fence about whether or not this needs to be in |
||
/// Attaches the provided [`Subscriber`] to this type, returning a | ||
/// `WithDispatch` wrapper. | ||
/// | ||
/// The attached subscriber will be set as the [default] when the returned `Future` is polled. | ||
/// | ||
/// [`Subscriber`]: ../trait.Subscriber.html | ||
/// [default]: https://docs.rs/tracing/latest/tracing/dispatcher/index.html#setting-the-default-subscriber | ||
fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> | ||
where | ||
S: Into<Dispatch>, | ||
{ | ||
WithDispatch { | ||
inner: self, | ||
dispatch: subscriber.into(), | ||
} | ||
} | ||
|
||
/// Attaches the current [default] [`Subscriber`] to this type, returning a | ||
/// `WithDispatch` wrapper. | ||
/// | ||
/// When the wrapped type is a future, stream, or sink, the attached | ||
/// subscriber will be set as the [default] while it is being polled. | ||
/// When the wrapped type is an executor, the subscriber will be set as the | ||
/// default for any futures spawned on that executor. | ||
/// | ||
/// This can be used to propagate the current dispatcher context when | ||
/// spawning a new future. | ||
/// | ||
/// [`Subscriber`]: ../trait.Subscriber.html | ||
/// [default]: https://docs.rs/tracing/latest/tracing/dispatcher/index.html#setting-the-default-subscriber | ||
#[inline] | ||
fn with_current_subscriber(self) -> WithDispatch<Self> { | ||
WithDispatch { | ||
inner: self, | ||
dispatch: dispatcher::get_default(|default| default.clone()), | ||
} | ||
} | ||
} | ||
|
||
pin_project! { | ||
/// A future that has been instrumented with a `tracing` subscriber. | ||
#[derive(Clone, Debug)] | ||
#[must_use = "futures do nothing unless you `.await` or poll them"] | ||
pub struct WithDispatch<T> { | ||
#[pin] | ||
inner: T, | ||
dispatch: Dispatch, | ||
} | ||
} | ||
|
||
pin_project! { | ||
/// A future that has been instrumented with a `tracing` span. | ||
#[derive(Debug, Clone)] | ||
#[must_use = "futures do nothing unless you `.await` or poll them"] | ||
pub 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: Sized> Instrument for T {} | ||
|
||
impl<T> Instrumented<T> { | ||
/// Borrows the `Span` that this type is instrumented by. | ||
pub fn span(&self) -> &Span { | ||
&self.span | ||
} | ||
|
||
/// Mutably borrows the `Span` that this type is instrumented by. | ||
pub fn span_mut(&mut self) -> &mut Span { | ||
&mut self.span | ||
} | ||
|
||
/// Borrows the wrapped type. | ||
pub fn inner(&self) -> &T { | ||
&self.inner | ||
} | ||
|
||
/// Mutably borrows the wrapped type. | ||
pub fn inner_mut(&mut self) -> &mut T { | ||
&mut self.inner | ||
} | ||
|
||
/// Get a pinned reference to the wrapped type. | ||
pub fn inner_pin_ref(self: Pin<&Self>) -> Pin<&T> { | ||
self.project_ref().inner | ||
} | ||
|
||
/// Get a pinned mutable reference to the wrapped type. | ||
pub fn inner_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { | ||
self.project().inner | ||
} | ||
|
||
/// Consumes the `Instrumented`, returning the wrapped type. | ||
/// | ||
/// Note that this drops the span. | ||
pub fn into_inner(self) -> T { | ||
self.inner | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -173,15 +173,6 @@ | |
//! # fn main() {} | ||
//! ``` | ||
//! | ||
//! <div class="information"> | ||
//! <div class="tooltip ignore" style="">ⓘ<span class="tooltiptext">Note</span></div> | ||
//! </div> | ||
//! <div class="example-wrap" style="display:inline-block"> | ||
//! <pre class="ignore" style="white-space:normal;font:inherit;"> | ||
//! <strong>Note</strong>: Using <code>#[instrument]</code> on | ||
//! <code>async fn</code>s requires the <a href="https://crates.io/crates/tracing-futures"> | ||
//! <code>tracing-futures</code> crate</a> as a dependency as well. | ||
//! </pre></div> | ||
//! | ||
//! You can find more examples showing how to use this crate [here][examples]. | ||
//! | ||
|
@@ -889,6 +880,8 @@ pub use log; | |
#[doc(hidden)] | ||
use tracing_core::*; | ||
|
||
#[doc(inline)] | ||
pub use self::instrument::Instrument; | ||
pub use self::{dispatcher::Dispatch, event::Event, field::Value, subscriber::Subscriber}; | ||
|
||
#[doc(hidden)] | ||
|
@@ -913,6 +906,8 @@ mod macros; | |
|
||
pub mod dispatcher; | ||
pub mod field; | ||
/// Attach a span to a `std::future::Future`. | ||
pub mod instrument; | ||
Comment on lines
+909
to
+910
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IDK if I really think this needs its own module, I might either reexport it from the root and make the instrument module hidden, or put it in the |
||
pub mod level_filters; | ||
pub mod span; | ||
pub(crate) mod stdlib; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whoopsy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup 😬