🛈 Note: This is pre-release documentation for the upcoming tracing 0.2.0 ecosystem.

For the release documentation, please see docs.rs, instead.

tracing/
instrument.rs

1use crate::span::Span;
2use core::{
3    future::Future,
4    marker::Sized,
5    mem::ManuallyDrop,
6    pin::Pin,
7    task::{Context, Poll},
8};
9use pin_project_lite::pin_project;
10
11#[cfg(feature = "std")]
12use crate::dispatch::{self, Dispatch};
13
14/// Attaches spans to a [`std::future::Future`].
15///
16/// Extension trait allowing futures to be
17/// instrumented with a `tracing` [span].
18///
19/// [span]: super::Span
20pub trait Instrument: Sized {
21    /// Instruments this type with the provided [`Span`], returning an
22    /// `Instrumented` wrapper.
23    ///
24    /// The attached [`Span`] will be [entered] every time the instrumented
25    /// [`Future`] is polled or [`Drop`]ped.
26    ///
27    /// # Examples
28    ///
29    /// Instrumenting a future:
30    ///
31    /// ```rust
32    /// use tracing::Instrument;
33    ///
34    /// # async fn doc() {
35    /// let my_future = async {
36    ///     // ...
37    /// };
38    ///
39    /// my_future
40    ///     .instrument(tracing::info_span!("my_future"))
41    ///     .await
42    /// # }
43    /// ```
44    ///
45    /// The [`Span::or_current`] combinator can be used in combination with
46    /// `instrument` to ensure that the [current span] is attached to the
47    /// future if the span passed to `instrument` is [disabled]:
48    ///
49    /// ```
50    /// use tracing::Instrument;
51    /// # mod tokio {
52    /// #     pub(super) fn spawn(_: impl std::future::Future) {}
53    /// # }
54    ///
55    /// let my_future = async {
56    ///     // ...
57    /// };
58    ///
59    /// let outer_span = tracing::info_span!("outer").entered();
60    ///
61    /// // If the "my_future" span is enabled, then the spawned task will
62    /// // be within both "my_future" *and* "outer", since "outer" is
63    /// // "my_future"'s parent. However, if "my_future" is disabled,
64    /// // the spawned task will *not* be in any span.
65    /// tokio::spawn(
66    ///     my_future
67    ///         .instrument(tracing::debug_span!("my_future"))
68    /// );
69    ///
70    /// // Using `Span::or_current` ensures the spawned task is instrumented
71    /// // with the current span, if the new span passed to `instrument` is
72    /// // not enabled. This means that if the "my_future"  span is disabled,
73    /// // the spawned task will still be instrumented with the "outer" span:
74    /// # let my_future = async {};
75    /// tokio::spawn(
76    ///    my_future
77    ///         .instrument(tracing::debug_span!("my_future").or_current())
78    /// );
79    /// ```
80    ///
81    /// [entered]: super::Span::enter()
82    /// [`Span::or_current`]: super::Span::or_current()
83    /// [current span]: super::Span::current()
84    /// [disabled]: super::Span::is_disabled()
85    /// [`Future`]: std::future::Future
86    fn instrument(self, span: Span) -> Instrumented<Self> {
87        Instrumented {
88            inner: ManuallyDrop::new(self),
89            span,
90        }
91    }
92
93    /// Instruments this type with the [current] [`Span`], returning an
94    /// `Instrumented` wrapper.
95    ///
96    /// The attached [`Span`] will be [entered] every time the instrumented
97    /// [`Future`] is polled or [`Drop`]ped.
98    ///
99    /// This can be used to propagate the current span when spawning a new future.
100    ///
101    /// # Examples
102    ///
103    /// ```rust
104    /// use tracing::Instrument;
105    ///
106    /// # mod tokio {
107    /// #     pub(super) fn spawn(_: impl std::future::Future) {}
108    /// # }
109    /// # async fn doc() {
110    /// let span = tracing::info_span!("my_span");
111    /// let _enter = span.enter();
112    ///
113    /// // ...
114    ///
115    /// let future = async {
116    ///     tracing::debug!("this event will occur inside `my_span`");
117    ///     // ...
118    /// };
119    /// tokio::spawn(future.in_current_span());
120    /// # }
121    /// ```
122    ///
123    /// [current]: super::Span::current()
124    /// [entered]: super::Span::enter()
125    /// [`Span`]: crate::Span
126    /// [`Future`]: std::future::Future
127    #[inline]
128    fn in_current_span(self) -> Instrumented<Self> {
129        self.instrument(Span::current())
130    }
131}
132
133/// Extension trait allowing futures to be instrumented with
134/// a `tracing` collector.
135#[cfg(feature = "std")]
136#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
137pub trait WithCollector: Sized {
138    /// Attaches the provided [collector] to this type, returning a
139    /// [`WithDispatch`] wrapper.
140    ///
141    /// The attached [collector] will be set as the [default] when the returned
142    /// [`Future`] is polled.
143    ///
144    /// # Examples
145    ///
146    /// ```
147    /// # pub struct MyCollector;
148    /// # impl tracing::Collect for MyCollector {
149    /// #   fn new_span(&self, _: &tracing::span::Attributes) -> tracing::span::Id {
150    /// #       tracing::span::Id::from_u64(0)
151    /// #   }
152    /// #   fn record(&self, _: &tracing::span::Id, _: &tracing::span::Record) {}
153    /// #   fn event(&self, _: &tracing::Event<'_>) {}
154    /// #   fn record_follows_from(&self, _: &tracing::span::Id, _: &tracing::span::Id) {}
155    /// #   fn enabled(&self, _: &tracing::Metadata) -> bool { false }
156    /// #   fn enter(&self, _: &tracing::span::Id) {}
157    /// #   fn exit(&self, _: &tracing::span::Id) {}
158    /// #   fn current_span(&self) -> tracing_core::span::Current {
159    /// #       tracing_core::span::Current::unknown()
160    /// #    }
161    /// # }
162    /// # impl MyCollector { fn new() -> Self { Self } }
163    /// # async fn docs() {
164    /// use tracing::instrument::WithCollector;
165    ///
166    /// // Set the default collector
167    /// let _default = tracing::collect::set_default(MyCollector::new());
168    ///
169    /// tracing::info!("this event will be recorded by the default collector");
170    ///
171    /// // Create a different collector and attach it to a future.
172    /// let other_collector = MyCollector::new();
173    /// let future = async {
174    ///     tracing::info!("this event will be recorded by the other collector");
175    ///     // ...
176    /// };
177    ///
178    /// future
179    ///     // Attach the other collector to the future before awaiting it
180    ///     .with_collector(other_collector)
181    ///     .await;
182    ///
183    /// // Once the future has completed, we return to the default collector.
184    /// tracing::info!("this event will be recorded by the default collector");
185    /// # }
186    /// ```
187    ///
188    /// [collector]: super::Collect
189    /// [default]: crate::dispatch#setting-the-default-collector
190    /// [`Future`]: std::future::Future
191    fn with_collector<C>(self, collector: C) -> WithDispatch<Self>
192    where
193        C: Into<Dispatch>,
194    {
195        WithDispatch {
196            inner: self,
197            dispatch: collector.into(),
198        }
199    }
200
201    /// Attaches the current [default] [collector] to this type, returning a
202    /// [`WithDispatch`] wrapper.
203    ///
204    /// The attached collector will be set as the [default] when the returned
205    /// [`Future`] is polled.
206    ///
207    /// This can be used to propagate the current dispatcher context when
208    /// spawning a new future that may run on a different thread.
209    ///
210    /// # Examples
211    ///
212    /// ```
213    /// # mod tokio {
214    /// #     pub(super) fn spawn(_: impl std::future::Future) {}
215    /// # }
216    /// # pub struct MyCollector;
217    /// # impl tracing::Collect for MyCollector {
218    /// #   fn new_span(&self, _: &tracing::span::Attributes) -> tracing::span::Id {
219    /// #       tracing::span::Id::from_u64(0)
220    /// #   }
221    /// #   fn record(&self, _: &tracing::span::Id, _: &tracing::span::Record) {}
222    /// #   fn event(&self, _: &tracing::Event<'_>) {}
223    /// #   fn record_follows_from(&self, _: &tracing::span::Id, _: &tracing::span::Id) {}
224    /// #   fn enabled(&self, _: &tracing::Metadata) -> bool { false }
225    /// #   fn enter(&self, _: &tracing::span::Id) {}
226    /// #   fn exit(&self, _: &tracing::span::Id) {}
227    /// #   fn current_span(&self) -> tracing_core::span::Current {
228    /// #       tracing_core::span::Current::unknown()
229    /// #    }
230    /// # }
231    /// # impl MyCollector { fn new() -> Self { Self } }
232    /// # async fn docs() {
233    /// use tracing::instrument::WithCollector;
234    ///
235    /// // Using `set_default` (rather than `set_global_default`) sets the
236    /// // default collector for *this* thread only.
237    /// let _default = tracing::collect::set_default(MyCollector::new());
238    ///
239    /// let future = async {
240    ///     // ...
241    /// };
242    ///
243    /// // If a multi-threaded async runtime is in use, this spawned task may
244    /// // run on a different thread, in a different default collector's context.
245    /// tokio::spawn(future);
246    ///
247    /// // However, calling `with_current_collector` on the future before
248    /// // spawning it, ensures that the current thread's default collector is
249    /// // propagated to the spawned task, regardless of where it executes:
250    /// # let future = async { };
251    /// tokio::spawn(future.with_current_collector());
252    /// # }
253    /// ```
254    /// [collector]: super::Collect
255    /// [default]: crate::dispatch#setting-the-default-collector
256    /// [`Future`]: std::future::Future
257    #[inline]
258    fn with_current_collector(self) -> WithDispatch<Self> {
259        WithDispatch {
260            inner: self,
261            dispatch: dispatch::get_default(|default| default.clone()),
262        }
263    }
264}
265
266#[cfg(feature = "std")]
267pin_project! {
268    /// A [`Future`] that has been instrumented with a `tracing` [collector].
269    ///
270    /// This type is returned by the [`WithCollector`] extension trait. See that
271    /// trait's documentation for details.
272    ///
273    /// [`Future`]: std::future::Future
274    /// [collector]: crate::Collector
275    #[derive(Clone, Debug)]
276    #[must_use = "futures do nothing unless you `.await` or poll them"]
277    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
278    pub struct WithDispatch<T> {
279        #[pin]
280        inner: T,
281        dispatch: Dispatch,
282    }
283}
284
285pin_project! {
286    /// A [`Future`] that has been instrumented with a `tracing` [`Span`].
287    ///
288    /// This type is returned by the [`Instrument`] extension trait. See that
289    /// trait's documentation for details.
290    ///
291    /// [`Future`]: std::future::Future
292    /// [`Span`]: crate::Span
293    #[project = InstrumentedProj]
294    #[project_ref = InstrumentedProjRef]
295    #[derive(Debug, Clone)]
296    #[must_use = "futures do nothing unless you `.await` or poll them"]
297    pub struct Instrumented<T> {
298        // `ManuallyDrop` is used here to to enter instrument `Drop` by entering
299        // `Span` and executing `ManuallyDrop::drop`.
300        #[pin]
301        inner: ManuallyDrop<T>,
302        span: Span,
303    }
304
305    impl<T> PinnedDrop for Instrumented<T> {
306        fn drop(this: Pin<&mut Self>) {
307            let this = this.project();
308            let _enter = this.span.enter();
309            // SAFETY: 1. `Pin::get_unchecked_mut()` is safe, because this isn't
310            //             different from wrapping `T` in `Option` and calling
311            //             `Pin::set(&mut this.inner, None)`, except avoiding
312            //             additional memory overhead.
313            //         2. `ManuallyDrop::drop()` is safe, because
314            //            `PinnedDrop::drop()` is guaranteed to be called only
315            //            once.
316            unsafe { ManuallyDrop::drop(this.inner.get_unchecked_mut()) }
317        }
318    }
319}
320
321impl<'a, T> InstrumentedProj<'a, T> {
322    /// Get a mutable reference to the [`Span`] a pinned mutable reference to
323    /// the wrapped type.
324    fn span_and_inner_pin_mut(self) -> (&'a mut Span, Pin<&'a mut T>) {
325        // SAFETY: As long as `ManuallyDrop<T>` does not move, `T` won't move
326        //         and `inner` is valid, because `ManuallyDrop::drop` is called
327        //         only inside `Drop` of the `Instrumented`.
328        let inner = unsafe { self.inner.map_unchecked_mut(|v| &mut **v) };
329        (self.span, inner)
330    }
331}
332
333impl<'a, T> InstrumentedProjRef<'a, T> {
334    /// Get a reference to the [`Span`] a pinned reference to the wrapped type.
335    fn span_and_inner_pin_ref(self) -> (&'a Span, Pin<&'a T>) {
336        // SAFETY: As long as `ManuallyDrop<T>` does not move, `T` won't move
337        //         and `inner` is valid, because `ManuallyDrop::drop` is called
338        //         only inside `Drop` of the `Instrumented`.
339        let inner = unsafe { self.inner.map_unchecked(|v| &**v) };
340        (self.span, inner)
341    }
342}
343
344// === impl Instrumented ===
345
346impl<T: Future> Future for Instrumented<T> {
347    type Output = T::Output;
348
349    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
350        let (span, inner) = self.project().span_and_inner_pin_mut();
351        let _enter = span.enter();
352        inner.poll(cx)
353    }
354}
355
356impl<T: Sized> Instrument for T {}
357
358impl<T> Instrumented<T> {
359    /// Borrows the `Span` that this type is instrumented by.
360    pub fn span(&self) -> &Span {
361        &self.span
362    }
363
364    /// Mutably borrows the `Span` that this type is instrumented by.
365    pub fn span_mut(&mut self) -> &mut Span {
366        &mut self.span
367    }
368
369    /// Borrows the wrapped type.
370    pub fn inner(&self) -> &T {
371        &self.inner
372    }
373
374    /// Mutably borrows the wrapped type.
375    pub fn inner_mut(&mut self) -> &mut T {
376        &mut self.inner
377    }
378
379    /// Get a pinned reference to the wrapped type.
380    pub fn inner_pin_ref(self: Pin<&Self>) -> Pin<&T> {
381        self.project_ref().span_and_inner_pin_ref().1
382    }
383
384    /// Get a pinned mutable reference to the wrapped type.
385    pub fn inner_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
386        self.project().span_and_inner_pin_mut().1
387    }
388
389    /// Consumes the `Instrumented`, returning the wrapped type.
390    ///
391    /// Note that this drops the span.
392    pub fn into_inner(self) -> T {
393        // To manually destructure `Instrumented` without `Drop`, we
394        // move it into a ManuallyDrop and use pointers to its fields
395        let this = ManuallyDrop::new(self);
396        let span: *const Span = &this.span;
397        let inner: *const ManuallyDrop<T> = &this.inner;
398        // SAFETY: Those pointers are valid for reads, because `Drop` didn't
399        //         run, and properly aligned, because `Instrumented` isn't
400        //         `#[repr(packed)]`.
401        let _span = unsafe { span.read() };
402        let inner = unsafe { inner.read() };
403        ManuallyDrop::into_inner(inner)
404    }
405}
406
407// === impl WithDispatch ===
408
409#[cfg(feature = "std")]
410#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
411impl<T: Future> Future for WithDispatch<T> {
412    type Output = T::Output;
413
414    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
415        let this = self.project();
416        let dispatch = this.dispatch;
417        let future = this.inner;
418        let _default = dispatch::set_default(dispatch);
419        future.poll(cx)
420    }
421}
422
423#[cfg(feature = "std")]
424#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
425impl<T: Sized> WithCollector for T {}
426
427#[cfg(feature = "std")]
428#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
429impl<T> WithDispatch<T> {
430    /// Borrows the [`Dispatch`] that is entered when this type is polled.
431    pub fn dispatch(&self) -> &Dispatch {
432        &self.dispatch
433    }
434
435    /// Borrows the wrapped type.
436    pub fn inner(&self) -> &T {
437        &self.inner
438    }
439
440    /// Mutably borrows the wrapped type.
441    pub fn inner_mut(&mut self) -> &mut T {
442        &mut self.inner
443    }
444
445    /// Get a pinned reference to the wrapped type.
446    pub fn inner_pin_ref(self: Pin<&Self>) -> Pin<&T> {
447        self.project_ref().inner
448    }
449
450    /// Get a pinned mutable reference to the wrapped type.
451    pub fn inner_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
452        self.project().inner
453    }
454
455    /// Consumes the `Instrumented`, returning the wrapped type.
456    ///
457    /// Note that this drops the span.
458    pub fn into_inner(self) -> T {
459        self.inner
460    }
461}