use crate::{ dispatcher::{self, Dispatch}, span::Span, }; use core::{ future::Future, marker::Sized, mem::ManuallyDrop, pin::Pin, task::{Context, Poll}, }; 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]: super::Span 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 or [`Drop`]ped. /// /// # Examples /// /// Instrumenting a future: /// /// ```rust /// use tracing::Instrument; /// /// # async fn doc() { /// let my_future = async { /// // ... /// }; /// /// my_future /// .instrument(tracing::info_span!("my_future")) /// .await /// # } /// ``` /// /// The [`Span::or_current`] combinator can be used in combination with /// `instrument` to ensure that the [current span] is attached to the /// future if the span passed to `instrument` is [disabled]: /// /// ``` /// use tracing::Instrument; /// # mod tokio { /// # pub(super) fn spawn(_: impl std::future::Future) {} /// # } /// /// let my_future = async { /// // ... /// }; /// /// let outer_span = tracing::info_span!("outer").entered(); /// /// // If the "my_future" span is enabled, then the spawned task will /// // be within both "my_future" *and* "outer", since "outer" is /// // "my_future"'s parent. However, if "my_future" is disabled, /// // the spawned task will *not* be in any span. /// tokio::spawn( /// my_future /// .instrument(tracing::debug_span!("my_future")) /// ); /// /// // Using `Span::or_current` ensures the spawned task is instrumented /// // with the current span, if the new span passed to `instrument` is /// // not enabled. This means that if the "my_future" span is disabled, /// // the spawned task will still be instrumented with the "outer" span: /// # let my_future = async {}; /// tokio::spawn( /// my_future /// .instrument(tracing::debug_span!("my_future").or_current()) /// ); /// ``` /// /// [entered]: super::Span::enter() /// [`Span::or_current`]: super::Span::or_current() /// [current span]: super::Span::current() /// [disabled]: super::Span::is_disabled() /// [`Future`]: std::future::Future fn instrument(self, span: Span) -> Instrumented { Instrumented { inner: ManuallyDrop::new(self), span, } } /// Instruments this type with the [current] [`Span`], returning an /// `Instrumented` wrapper. /// /// The attached [`Span`] will be [entered] every time the instrumented /// [`Future`] is polled or [`Drop`]ped. /// /// This can be used to propagate the current span when spawning a new future. /// /// # Examples /// /// ```rust /// use tracing::Instrument; /// /// # mod tokio { /// # pub(super) fn spawn(_: impl std::future::Future) {} /// # } /// # 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]: super::Span::current() /// [entered]: super::Span::enter() /// [`Span`]: crate::Span /// [`Future`]: std::future::Future #[inline] fn in_current_span(self) -> Instrumented { self.instrument(Span::current()) } } /// Extension trait allowing futures to be instrumented with /// a `tracing` [`Subscriber`](crate::Subscriber). #[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub trait WithSubscriber: Sized { /// 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. /// /// # Examples /// /// ``` /// # use tracing::subscriber::NoSubscriber as MySubscriber; /// # use tracing::subscriber::NoSubscriber as MyOtherSubscriber; /// # async fn docs() { /// use tracing::instrument::WithSubscriber; /// /// // Set the default `Subscriber` /// let _default = tracing::subscriber::set_default(MySubscriber::default()); /// /// tracing::info!("this event will be recorded by the default `Subscriber`"); /// /// // Create a different `Subscriber` and attach it to a future. /// let other_subscriber = MyOtherSubscriber::default(); /// let future = async { /// tracing::info!("this event will be recorded by the other `Subscriber`"); /// // ... /// }; /// /// future /// // Attach the other `Subscriber` to the future before awaiting it /// .with_subscriber(other_subscriber) /// .await; /// /// // Once the future has completed, we return to the default `Subscriber`. /// tracing::info!("this event will be recorded by the default `Subscriber`"); /// # } /// ``` /// /// [`Subscriber`]: super::Subscriber /// [default]: crate::dispatcher#setting-the-default-subscriber /// [`Future`]: std::future::Future fn with_subscriber(self, subscriber: S) -> WithDispatch where S: Into, { WithDispatch { inner: self, dispatcher: subscriber.into(), } } /// Attaches the current [default] [`Subscriber`] to this type, returning a /// [`WithDispatch`] wrapper. /// /// The attached `Subscriber` will be set as the [default] when the returned /// [`Future`] is polled. /// /// This can be used to propagate the current dispatcher context when /// spawning a new future that may run on a different thread. /// /// # Examples /// /// ``` /// # mod tokio { /// # pub(super) fn spawn(_: impl std::future::Future) {} /// # } /// # use tracing::subscriber::NoSubscriber as MySubscriber; /// # async fn docs() { /// use tracing::instrument::WithSubscriber; /// /// // Using `set_default` (rather than `set_global_default`) sets the /// // default `Subscriber` for *this* thread only. /// let _default = tracing::subscriber::set_default(MySubscriber::default()); /// /// let future = async { /// // ... /// }; /// /// // If a multi-threaded async runtime is in use, this spawned task may /// // run on a different thread, in a different default `Subscriber`'s context. /// tokio::spawn(future); /// /// // However, calling `with_current_subscriber` on the future before /// // spawning it, ensures that the current thread's default `Subscriber` is /// // propagated to the spawned task, regardless of where it executes: /// # let future = async { }; /// tokio::spawn(future.with_current_subscriber()); /// # } /// ``` /// [`Subscriber`]: super::Subscriber /// [default]: crate::dispatcher#setting-the-default-subscriber /// [`Future`]: std::future::Future #[inline] fn with_current_subscriber(self) -> WithDispatch { WithDispatch { inner: self, dispatcher: crate::dispatcher::get_default(|default| default.clone()), } } } pin_project! { /// A [`Future`] that has been instrumented with a `tracing` [`Subscriber`]. /// /// This type is returned by the [`WithSubscriber`] extension trait. See that /// trait's documentation for details. /// /// [`Future`]: std::future::Future /// [`Subscriber`]: crate::Subscriber #[derive(Clone, Debug)] #[must_use = "futures do nothing unless you `.await` or poll them"] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub struct WithDispatch { #[pin] inner: T, dispatcher: Dispatch, } } pin_project! { /// A [`Future`] that has been instrumented with a `tracing` [`Span`]. /// /// This type is returned by the [`Instrument`] extension trait. See that /// trait's documentation for details. /// /// [`Future`]: std::future::Future /// [`Span`]: crate::Span #[project = InstrumentedProj] #[project_ref = InstrumentedProjRef] #[derive(Debug, Clone)] #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Instrumented { // `ManuallyDrop` is used here to to enter instrument `Drop` by entering // `Span` and executing `ManuallyDrop::drop`. #[pin] inner: ManuallyDrop, span: Span, } impl PinnedDrop for Instrumented { fn drop(this: Pin<&mut Self>) { let this = this.project(); let _enter = this.span.enter(); // SAFETY: 1. `Pin::get_unchecked_mut()` is safe, because this isn't // different from wrapping `T` in `Option` and calling // `Pin::set(&mut this.inner, None)`, except avoiding // additional memory overhead. // 2. `ManuallyDrop::drop()` is safe, because // `PinnedDrop::drop()` is guaranteed to be called only // once. unsafe { ManuallyDrop::drop(this.inner.get_unchecked_mut()) } } } } impl<'a, T> InstrumentedProj<'a, T> { /// Get a mutable reference to the [`Span`] a pinned mutable reference to /// the wrapped type. fn span_and_inner_pin_mut(self) -> (&'a mut Span, Pin<&'a mut T>) { // SAFETY: As long as `ManuallyDrop` does not move, `T` won't move // and `inner` is valid, because `ManuallyDrop::drop` is called // only inside `Drop` of the `Instrumented`. let inner = unsafe { self.inner.map_unchecked_mut(|v| &mut **v) }; (self.span, inner) } } impl<'a, T> InstrumentedProjRef<'a, T> { /// Get a reference to the [`Span`] a pinned reference to the wrapped type. fn span_and_inner_pin_ref(self) -> (&'a Span, Pin<&'a T>) { // SAFETY: As long as `ManuallyDrop` does not move, `T` won't move // and `inner` is valid, because `ManuallyDrop::drop` is called // only inside `Drop` of the `Instrumented`. let inner = unsafe { self.inner.map_unchecked(|v| &**v) }; (self.span, inner) } } // === impl Instrumented === impl Future for Instrumented { type Output = T::Output; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let (span, inner) = self.project().span_and_inner_pin_mut(); let _enter = span.enter(); inner.poll(cx) } } impl Instrument for T {} impl Instrumented { /// 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().span_and_inner_pin_ref().1 } /// Get a pinned mutable reference to the wrapped type. pub fn inner_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { self.project().span_and_inner_pin_mut().1 } /// Consumes the `Instrumented`, returning the wrapped type. /// /// Note that this drops the span. pub fn into_inner(self) -> T { // To manually destructure `Instrumented` without `Drop`, we // move it into a ManuallyDrop and use pointers to its fields let this = ManuallyDrop::new(self); let span: *const Span = &this.span; let inner: *const ManuallyDrop = &this.inner; // SAFETY: Those pointers are valid for reads, because `Drop` didn't // run, and properly aligned, because `Instrumented` isn't // `#[repr(packed)]`. let _span = unsafe { span.read() }; let inner = unsafe { inner.read() }; ManuallyDrop::into_inner(inner) } } // === impl WithDispatch === #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl Future for WithDispatch { type Output = T::Output; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.project(); let dispatcher = this.dispatcher; let future = this.inner; let _default = dispatcher::set_default(dispatcher); future.poll(cx) } } #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl WithSubscriber for T {} #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl WithDispatch { /// Borrows the [`Dispatch`] that is entered when this type is polled. pub fn dispatcher(&self) -> &Dispatch { &self.dispatcher } /// 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 } }