Coverage Report

Created: 2025-08-26 07:09

/rust/registry/src/index.crates.io-6f17d22bba15001f/tracing-0.1.41/src/instrument.rs
Line
Count
Source (jump to first uncovered line)
1
use crate::{
2
    dispatcher::{self, Dispatch},
3
    span::Span,
4
};
5
use core::{
6
    future::Future,
7
    marker::Sized,
8
    mem::ManuallyDrop,
9
    pin::Pin,
10
    task::{Context, Poll},
11
};
12
use pin_project_lite::pin_project;
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
20
pub 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
12.3k
    fn instrument(self, span: Span) -> Instrumented<Self> {
87
12.3k
        Instrumented {
88
12.3k
            inner: ManuallyDrop::new(self),
89
12.3k
            span,
90
12.3k
        }
91
12.3k
    }
Unexecuted instantiation: <_ as tracing::instrument::Instrument>::instrument
<<h2::client::Connection<fuzz_e2e::MockIo>>::handshake2::{closure#0} as tracing::instrument::Instrument>::instrument
Line
Count
Source
86
12.3k
    fn instrument(self, span: Span) -> Instrumented<Self> {
87
12.3k
        Instrumented {
88
12.3k
            inner: ManuallyDrop::new(self),
89
12.3k
            span,
90
12.3k
        }
91
12.3k
    }
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
0
    fn in_current_span(self) -> Instrumented<Self> {
129
0
        self.instrument(Span::current())
130
0
    }
131
}
132
133
/// Extension trait allowing futures to be instrumented with
134
/// a `tracing` [`Subscriber`](crate::Subscriber).
135
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
136
pub trait WithSubscriber: Sized {
137
    /// Attaches the provided [`Subscriber`] to this type, returning a
138
    /// [`WithDispatch`] wrapper.
139
    ///
140
    /// The attached [`Subscriber`] will be set as the [default] when the returned
141
    /// [`Future`] is polled.
142
    ///
143
    /// # Examples
144
    ///
145
    /// ```
146
    /// # use tracing::subscriber::NoSubscriber as MySubscriber;
147
    /// # use tracing::subscriber::NoSubscriber as MyOtherSubscriber;
148
    /// # async fn docs() {
149
    /// use tracing::instrument::WithSubscriber;
150
    ///
151
    /// // Set the default `Subscriber`
152
    /// let _default = tracing::subscriber::set_default(MySubscriber::default());
153
    ///
154
    /// tracing::info!("this event will be recorded by the default `Subscriber`");
155
    ///
156
    /// // Create a different `Subscriber` and attach it to a future.
157
    /// let other_subscriber = MyOtherSubscriber::default();
158
    /// let future = async {
159
    ///     tracing::info!("this event will be recorded by the other `Subscriber`");
160
    ///     // ...
161
    /// };
162
    ///
163
    /// future
164
    ///     // Attach the other `Subscriber` to the future before awaiting it
165
    ///     .with_subscriber(other_subscriber)
166
    ///     .await;
167
    ///
168
    /// // Once the future has completed, we return to the default `Subscriber`.
169
    /// tracing::info!("this event will be recorded by the default `Subscriber`");
170
    /// # }
171
    /// ```
172
    ///
173
    /// [`Subscriber`]: super::Subscriber
174
    /// [default]: crate::dispatcher#setting-the-default-subscriber
175
    /// [`Future`]: std::future::Future
176
0
    fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
177
0
    where
178
0
        S: Into<Dispatch>,
179
0
    {
180
0
        WithDispatch {
181
0
            inner: self,
182
0
            dispatcher: subscriber.into(),
183
0
        }
184
0
    }
185
186
    /// Attaches the current [default] [`Subscriber`] to this type, returning a
187
    /// [`WithDispatch`] wrapper.
188
    ///
189
    /// The attached `Subscriber` will be set as the [default] when the returned
190
    /// [`Future`] is polled.
191
    ///
192
    /// This can be used to propagate the current dispatcher context when
193
    /// spawning a new future that may run on a different thread.
194
    ///
195
    /// # Examples
196
    ///
197
    /// ```
198
    /// # mod tokio {
199
    /// #     pub(super) fn spawn(_: impl std::future::Future) {}
200
    /// # }
201
    /// # use tracing::subscriber::NoSubscriber as MySubscriber;
202
    /// # async fn docs() {
203
    /// use tracing::instrument::WithSubscriber;
204
    ///
205
    /// // Using `set_default` (rather than `set_global_default`) sets the
206
    /// // default `Subscriber` for *this* thread only.
207
    /// let _default = tracing::subscriber::set_default(MySubscriber::default());
208
    ///
209
    /// let future = async {
210
    ///     // ...
211
    /// };
212
    ///
213
    /// // If a multi-threaded async runtime is in use, this spawned task may
214
    /// // run on a different thread, in a different default `Subscriber`'s context.
215
    /// tokio::spawn(future);
216
    ///
217
    /// // However, calling `with_current_subscriber` on the future before
218
    /// // spawning it, ensures that the current thread's default `Subscriber` is
219
    /// // propagated to the spawned task, regardless of where it executes:
220
    /// # let future = async { };
221
    /// tokio::spawn(future.with_current_subscriber());
222
    /// # }
223
    /// ```
224
    /// [`Subscriber`]: super::Subscriber
225
    /// [default]: crate::dispatcher#setting-the-default-subscriber
226
    /// [`Future`]: std::future::Future
227
    #[inline]
228
0
    fn with_current_subscriber(self) -> WithDispatch<Self> {
229
0
        WithDispatch {
230
0
            inner: self,
231
0
            dispatcher: crate::dispatcher::get_default(|default| default.clone()),
232
0
        }
233
0
    }
234
}
235
236
pin_project! {
237
    /// A [`Future`] that has been instrumented with a `tracing` [`Subscriber`].
238
    ///
239
    /// This type is returned by the [`WithSubscriber`] extension trait. See that
240
    /// trait's documentation for details.
241
    ///
242
    /// [`Future`]: std::future::Future
243
    /// [`Subscriber`]: crate::Subscriber
244
    #[derive(Clone, Debug)]
245
    #[must_use = "futures do nothing unless you `.await` or poll them"]
246
    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
247
    pub struct WithDispatch<T> {
248
        #[pin]
249
        inner: T,
250
        dispatcher: Dispatch,
251
    }
252
}
253
254
pin_project! {
255
    /// A [`Future`] that has been instrumented with a `tracing` [`Span`].
256
    ///
257
    /// This type is returned by the [`Instrument`] extension trait. See that
258
    /// trait's documentation for details.
259
    ///
260
    /// [`Future`]: std::future::Future
261
    /// [`Span`]: crate::Span
262
    #[project = InstrumentedProj]
263
    #[project_ref = InstrumentedProjRef]
264
    #[derive(Debug, Clone)]
265
    #[must_use = "futures do nothing unless you `.await` or poll them"]
266
    pub struct Instrumented<T> {
267
        // `ManuallyDrop` is used here to to enter instrument `Drop` by entering
268
        // `Span` and executing `ManuallyDrop::drop`.
269
        #[pin]
270
        inner: ManuallyDrop<T>,
271
        span: Span,
272
    }
273
274
    impl<T> PinnedDrop for Instrumented<T> {
275
        fn drop(this: Pin<&mut Self>) {
276
            let this = this.project();
277
            let _enter = this.span.enter();
278
            // SAFETY: 1. `Pin::get_unchecked_mut()` is safe, because this isn't
279
            //             different from wrapping `T` in `Option` and calling
280
            //             `Pin::set(&mut this.inner, None)`, except avoiding
281
            //             additional memory overhead.
282
            //         2. `ManuallyDrop::drop()` is safe, because
283
            //            `PinnedDrop::drop()` is guaranteed to be called only
284
            //            once.
285
            unsafe { ManuallyDrop::drop(this.inner.get_unchecked_mut()) }
286
        }
287
    }
288
}
289
290
impl<'a, T> InstrumentedProj<'a, T> {
291
    /// Get a mutable reference to the [`Span`] a pinned mutable reference to
292
    /// the wrapped type.
293
105k
    fn span_and_inner_pin_mut(self) -> (&'a mut Span, Pin<&'a mut T>) {
294
105k
        // SAFETY: As long as `ManuallyDrop<T>` does not move, `T` won't move
295
105k
        //         and `inner` is valid, because `ManuallyDrop::drop` is called
296
105k
        //         only inside `Drop` of the `Instrumented`.
297
105k
        let inner = unsafe { self.inner.map_unchecked_mut(|v| &mut **v) };
Unexecuted instantiation: <tracing::instrument::InstrumentedProj<_>>::span_and_inner_pin_mut::{closure#0}
<tracing::instrument::InstrumentedProj<<h2::client::Connection<fuzz_e2e::MockIo>>::handshake2::{closure#0}>>::span_and_inner_pin_mut::{closure#0}
Line
Count
Source
297
105k
        let inner = unsafe { self.inner.map_unchecked_mut(|v| &mut **v) };
298
105k
        (self.span, inner)
299
105k
    }
Unexecuted instantiation: <tracing::instrument::InstrumentedProj<_>>::span_and_inner_pin_mut
<tracing::instrument::InstrumentedProj<<h2::client::Connection<fuzz_e2e::MockIo>>::handshake2::{closure#0}>>::span_and_inner_pin_mut
Line
Count
Source
293
105k
    fn span_and_inner_pin_mut(self) -> (&'a mut Span, Pin<&'a mut T>) {
294
105k
        // SAFETY: As long as `ManuallyDrop<T>` does not move, `T` won't move
295
105k
        //         and `inner` is valid, because `ManuallyDrop::drop` is called
296
105k
        //         only inside `Drop` of the `Instrumented`.
297
105k
        let inner = unsafe { self.inner.map_unchecked_mut(|v| &mut **v) };
298
105k
        (self.span, inner)
299
105k
    }
300
}
301
302
impl<'a, T> InstrumentedProjRef<'a, T> {
303
    /// Get a reference to the [`Span`] a pinned reference to the wrapped type.
304
0
    fn span_and_inner_pin_ref(self) -> (&'a Span, Pin<&'a T>) {
305
0
        // SAFETY: As long as `ManuallyDrop<T>` does not move, `T` won't move
306
0
        //         and `inner` is valid, because `ManuallyDrop::drop` is called
307
0
        //         only inside `Drop` of the `Instrumented`.
308
0
        let inner = unsafe { self.inner.map_unchecked(|v| &**v) };
309
0
        (self.span, inner)
310
0
    }
311
}
312
313
// === impl Instrumented ===
314
315
impl<T: Future> Future for Instrumented<T> {
316
    type Output = T::Output;
317
318
105k
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
319
105k
        let (span, inner) = self.project().span_and_inner_pin_mut();
320
105k
        let _enter = span.enter();
321
105k
        inner.poll(cx)
322
105k
    }
Unexecuted instantiation: <tracing::instrument::Instrumented<_> as core::future::future::Future>::poll
<tracing::instrument::Instrumented<<h2::client::Connection<fuzz_e2e::MockIo>>::handshake2::{closure#0}> as core::future::future::Future>::poll
Line
Count
Source
318
105k
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
319
105k
        let (span, inner) = self.project().span_and_inner_pin_mut();
320
105k
        let _enter = span.enter();
321
105k
        inner.poll(cx)
322
105k
    }
323
}
324
325
impl<T: Sized> Instrument for T {}
326
327
impl<T> Instrumented<T> {
328
    /// Borrows the `Span` that this type is instrumented by.
329
0
    pub fn span(&self) -> &Span {
330
0
        &self.span
331
0
    }
332
333
    /// Mutably borrows the `Span` that this type is instrumented by.
334
0
    pub fn span_mut(&mut self) -> &mut Span {
335
0
        &mut self.span
336
0
    }
337
338
    /// Borrows the wrapped type.
339
0
    pub fn inner(&self) -> &T {
340
0
        &self.inner
341
0
    }
342
343
    /// Mutably borrows the wrapped type.
344
0
    pub fn inner_mut(&mut self) -> &mut T {
345
0
        &mut self.inner
346
0
    }
347
348
    /// Get a pinned reference to the wrapped type.
349
0
    pub fn inner_pin_ref(self: Pin<&Self>) -> Pin<&T> {
350
0
        self.project_ref().span_and_inner_pin_ref().1
351
0
    }
352
353
    /// Get a pinned mutable reference to the wrapped type.
354
0
    pub fn inner_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
355
0
        self.project().span_and_inner_pin_mut().1
356
0
    }
357
358
    /// Consumes the `Instrumented`, returning the wrapped type.
359
    ///
360
    /// Note that this drops the span.
361
0
    pub fn into_inner(self) -> T {
362
0
        // To manually destructure `Instrumented` without `Drop`, we
363
0
        // move it into a ManuallyDrop and use pointers to its fields
364
0
        let this = ManuallyDrop::new(self);
365
0
        let span: *const Span = &this.span;
366
0
        let inner: *const ManuallyDrop<T> = &this.inner;
367
0
        // SAFETY: Those pointers are valid for reads, because `Drop` didn't
368
0
        //         run, and properly aligned, because `Instrumented` isn't
369
0
        //         `#[repr(packed)]`.
370
0
        let _span = unsafe { span.read() };
371
0
        let inner = unsafe { inner.read() };
372
0
        ManuallyDrop::into_inner(inner)
373
0
    }
374
}
375
376
// === impl WithDispatch ===
377
378
#[cfg(feature = "std")]
379
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
380
impl<T: Future> Future for WithDispatch<T> {
381
    type Output = T::Output;
382
383
0
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
384
0
        let this = self.project();
385
0
        let dispatcher = this.dispatcher;
386
0
        let future = this.inner;
387
0
        let _default = dispatcher::set_default(dispatcher);
388
0
        future.poll(cx)
389
0
    }
390
}
391
392
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
393
impl<T: Sized> WithSubscriber for T {}
394
395
#[cfg(feature = "std")]
396
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
397
impl<T> WithDispatch<T> {
398
    /// Borrows the [`Dispatch`] that is entered when this type is polled.
399
0
    pub fn dispatcher(&self) -> &Dispatch {
400
0
        &self.dispatcher
401
0
    }
402
403
    /// Borrows the wrapped type.
404
0
    pub fn inner(&self) -> &T {
405
0
        &self.inner
406
0
    }
407
408
    /// Mutably borrows the wrapped type.
409
0
    pub fn inner_mut(&mut self) -> &mut T {
410
0
        &mut self.inner
411
0
    }
412
413
    /// Get a pinned reference to the wrapped type.
414
0
    pub fn inner_pin_ref(self: Pin<&Self>) -> Pin<&T> {
415
0
        self.project_ref().inner
416
0
    }
417
418
    /// Get a pinned mutable reference to the wrapped type.
419
0
    pub fn inner_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
420
0
        self.project().inner
421
0
    }
422
423
    /// Consumes the `Instrumented`, returning the wrapped type.
424
    ///
425
    /// Note that this drops the span.
426
0
    pub fn into_inner(self) -> T {
427
0
        self.inner
428
0
    }
429
}