1use crate::{
2 dispatcher::{self, Dispatch},
3 span::Span,
4};
5use core::{
6 future::Future,
7 marker::Sized,
8 mem::ManuallyDrop,
9 pin::Pin,
10 task::{Context, Poll},
11};
12use 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
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` [`Subscriber`](crate::Subscriber).
135#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
136pub 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 fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
177 where
178 S: Into<Dispatch>,
179 {
180 WithDispatch {
181 inner: self,
182 dispatcher: subscriber.into(),
183 }
184 }
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 fn with_current_subscriber(self) -> WithDispatch<Self> {
229 WithDispatch {
230 inner: self,
231 dispatcher: crate::dispatcher::get_default(|default| default.clone()),
232 }
233 }
234}
235
236pin_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
254pin_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
290impl<'a, T> InstrumentedProj<'a, T> {
291 /// Get a mutable reference to the [`Span`] a pinned mutable reference to
292 /// the wrapped type.
293 fn span_and_inner_pin_mut(self) -> (&'a mut Span, Pin<&'a mut T>) {
294 // SAFETY: As long as `ManuallyDrop<T>` does not move, `T` won't move
295 // and `inner` is valid, because `ManuallyDrop::drop` is called
296 // only inside `Drop` of the `Instrumented`.
297 let inner = unsafe { self.inner.map_unchecked_mut(|v| &mut **v) };
298 (self.span, inner)
299 }
300}
301
302impl<'a, T> InstrumentedProjRef<'a, T> {
303 /// Get a reference to the [`Span`] a pinned reference to the wrapped type.
304 fn span_and_inner_pin_ref(self) -> (&'a Span, Pin<&'a T>) {
305 // SAFETY: As long as `ManuallyDrop<T>` does not move, `T` won't move
306 // and `inner` is valid, because `ManuallyDrop::drop` is called
307 // only inside `Drop` of the `Instrumented`.
308 let inner = unsafe { self.inner.map_unchecked(|v| &**v) };
309 (self.span, inner)
310 }
311}
312
313// === impl Instrumented ===
314
315impl<T: Future> Future for Instrumented<T> {
316 type Output = T::Output;
317
318 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
319 let (span, inner) = self.project().span_and_inner_pin_mut();
320 let _enter = span.enter();
321 inner.poll(cx)
322 }
323}
324
325impl<T: Sized> Instrument for T {}
326
327impl<T> Instrumented<T> {
328 /// Borrows the `Span` that this type is instrumented by.
329 pub fn span(&self) -> &Span {
330 &self.span
331 }
332
333 /// Mutably borrows the `Span` that this type is instrumented by.
334 pub fn span_mut(&mut self) -> &mut Span {
335 &mut self.span
336 }
337
338 /// Borrows the wrapped type.
339 pub fn inner(&self) -> &T {
340 &self.inner
341 }
342
343 /// Mutably borrows the wrapped type.
344 pub fn inner_mut(&mut self) -> &mut T {
345 &mut self.inner
346 }
347
348 /// Get a pinned reference to the wrapped type.
349 pub fn inner_pin_ref(self: Pin<&Self>) -> Pin<&T> {
350 self.project_ref().span_and_inner_pin_ref().1
351 }
352
353 /// Get a pinned mutable reference to the wrapped type.
354 pub fn inner_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
355 self.project().span_and_inner_pin_mut().1
356 }
357
358 /// Consumes the `Instrumented`, returning the wrapped type.
359 ///
360 /// Note that this drops the span.
361 pub fn into_inner(self) -> T {
362 // To manually destructure `Instrumented` without `Drop`, we
363 // move it into a ManuallyDrop and use pointers to its fields
364 let this = ManuallyDrop::new(self);
365 let span: *const Span = &this.span;
366 let inner: *const ManuallyDrop<T> = &this.inner;
367 // SAFETY: Those pointers are valid for reads, because `Drop` didn't
368 // run, and properly aligned, because `Instrumented` isn't
369 // `#[repr(packed)]`.
370 let _span = unsafe { span.read() };
371 let inner = unsafe { inner.read() };
372 ManuallyDrop::into_inner(inner)
373 }
374}
375
376// === impl WithDispatch ===
377
378#[cfg(feature = "std")]
379#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
380impl<T: Future> Future for WithDispatch<T> {
381 type Output = T::Output;
382
383 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
384 let this = self.project();
385 let dispatcher = this.dispatcher;
386 let future = this.inner;
387 let _default = dispatcher::set_default(dispatcher);
388 future.poll(cx)
389 }
390}
391
392#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
393impl<T: Sized> WithSubscriber for T {}
394
395#[cfg(feature = "std")]
396#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
397impl<T> WithDispatch<T> {
398 /// Borrows the [`Dispatch`] that is entered when this type is polled.
399 pub fn dispatcher(&self) -> &Dispatch {
400 &self.dispatcher
401 }
402
403 /// Borrows the wrapped type.
404 pub fn inner(&self) -> &T {
405 &self.inner
406 }
407
408 /// Mutably borrows the wrapped type.
409 pub fn inner_mut(&mut self) -> &mut T {
410 &mut self.inner
411 }
412
413 /// Get a pinned reference to the wrapped type.
414 pub fn inner_pin_ref(self: Pin<&Self>) -> Pin<&T> {
415 self.project_ref().inner
416 }
417
418 /// Get a pinned mutable reference to the wrapped type.
419 pub fn inner_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
420 self.project().inner
421 }
422
423 /// Consumes the `Instrumented`, returning the wrapped type.
424 ///
425 /// Note that this drops the span.
426 pub fn into_inner(self) -> T {
427 self.inner
428 }
429}
430