Coverage Report

Created: 2025-07-18 06:42

/rust/registry/src/index.crates.io-6f17d22bba15001f/tracing-subscriber-0.3.19/src/layer/context.rs
Line
Count
Source (jump to first uncovered line)
1
use tracing_core::{metadata::Metadata, span, subscriber::Subscriber, Event};
2
3
use crate::registry::{self, LookupSpan, SpanRef};
4
5
#[cfg(all(feature = "registry", feature = "std"))]
6
use crate::{filter::FilterId, registry::Registry};
7
/// Represents information about the current context provided to [`Layer`]s by the
8
/// wrapped [`Subscriber`].
9
///
10
/// To access [stored data] keyed by a span ID, implementors of the `Layer`
11
/// trait should ensure that the `Subscriber` type parameter is *also* bound by the
12
/// [`LookupSpan`]:
13
///
14
/// ```rust
15
/// use tracing::Subscriber;
16
/// use tracing_subscriber::{Layer, registry::LookupSpan};
17
///
18
/// pub struct MyLayer;
19
///
20
/// impl<S> Layer<S> for MyLayer
21
/// where
22
///     S: Subscriber + for<'a> LookupSpan<'a>,
23
/// {
24
///     // ...
25
/// }
26
/// ```
27
///
28
/// [`Layer`]: super::Layer
29
/// [`Subscriber`]: tracing_core::Subscriber
30
/// [stored data]: crate::registry::SpanRef
31
/// [`LookupSpan`]: crate::registry::LookupSpan
32
#[derive(Debug)]
33
pub struct Context<'a, S> {
34
    subscriber: Option<&'a S>,
35
    /// The bitmask of all [`Filtered`] layers that currently apply in this
36
    /// context. If there is only a single [`Filtered`] wrapping the layer that
37
    /// produced this context, then this is that filter's ID. Otherwise, if we
38
    /// are in a nested tree with multiple filters, this is produced by
39
    /// [`and`]-ing together the [`FilterId`]s of each of the filters that wrap
40
    /// the current layer.
41
    ///
42
    /// [`Filtered`]: crate::filter::Filtered
43
    /// [`FilterId`]: crate::filter::FilterId
44
    /// [`and`]: crate::filter::FilterId::and
45
    #[cfg(all(feature = "registry", feature = "std"))]
46
    filter: FilterId,
47
}
48
49
// === impl Context ===
50
51
impl<'a, S> Context<'a, S>
52
where
53
    S: Subscriber,
54
{
55
0
    pub(super) fn new(subscriber: &'a S) -> Self {
56
0
        Self {
57
0
            subscriber: Some(subscriber),
58
0
59
0
            #[cfg(feature = "registry")]
60
0
            filter: FilterId::none(),
61
0
        }
62
0
    }
Unexecuted instantiation: <tracing_subscriber::layer::context::Context<tracing_subscriber::layer::layered::Layered<tracing_subscriber::fmt::fmt_layer::Layer<tracing_subscriber::registry::sharded::Registry>, tracing_subscriber::registry::sharded::Registry>>>::new
Unexecuted instantiation: <tracing_subscriber::layer::context::Context<tracing_subscriber::fmt::Subscriber>>::new
Unexecuted instantiation: <tracing_subscriber::layer::context::Context<tracing_subscriber::registry::sharded::Registry>>::new
63
64
    /// Returns the wrapped subscriber's view of the current span.
65
    #[inline]
66
0
    pub fn current_span(&self) -> span::Current {
67
0
        self.subscriber
68
0
            .map(Subscriber::current_span)
69
0
            // TODO: this would be more correct as "unknown", so perhaps
70
0
            // `tracing-core` should make `Current::unknown()` public?
71
0
            .unwrap_or_else(span::Current::none)
72
0
    }
Unexecuted instantiation: <tracing_subscriber::layer::context::Context<tracing_subscriber::registry::sharded::Registry>>::current_span
Unexecuted instantiation: <tracing_subscriber::layer::context::Context<_>>::current_span
73
74
    /// Returns whether the wrapped subscriber would enable the current span.
75
    #[inline]
76
0
    pub fn enabled(&self, metadata: &Metadata<'_>) -> bool {
77
0
        self.subscriber
78
0
            .map(|subscriber| subscriber.enabled(metadata))
79
0
            // If this context is `None`, we are registering a callsite, so
80
0
            // return `true` so that the layer does not incorrectly assume that
81
0
            // the inner subscriber has disabled this metadata.
82
0
            // TODO(eliza): would it be more correct for this to return an `Option`?
83
0
            .unwrap_or(true)
84
0
    }
85
86
    /// Records the provided `event` with the wrapped subscriber.
87
    ///
88
    /// # Notes
89
    ///
90
    /// - The subscriber is free to expect that the event's callsite has been
91
    ///   [registered][register], and may panic or fail to observe the event if this is
92
    ///   not the case. The `tracing` crate's macros ensure that all events are
93
    ///   registered, but if the event is constructed through other means, the
94
    ///   user is responsible for ensuring that [`register_callsite`][register]
95
    ///   has been called prior to calling this method.
96
    /// - This does _not_ call [`enabled`] on the inner subscriber. If the
97
    ///   caller wishes to apply the wrapped subscriber's filter before choosing
98
    ///   whether to record the event, it may first call [`Context::enabled`] to
99
    ///   check whether the event would be enabled. This allows `Layer`s to
100
    ///   elide constructing the event if it would not be recorded.
101
    ///
102
    /// [register]: tracing_core::subscriber::Subscriber::register_callsite()
103
    /// [`enabled`]: tracing_core::subscriber::Subscriber::enabled()
104
    /// [`Context::enabled`]: Context::enabled()
105
    #[inline]
106
0
    pub fn event(&self, event: &Event<'_>) {
107
0
        if let Some(subscriber) = self.subscriber {
108
0
            subscriber.event(event);
109
0
        }
110
0
    }
111
112
    /// Returns a [`SpanRef`] for the parent span of the given [`Event`], if
113
    /// it has a parent.
114
    ///
115
    /// If the event has an explicitly overridden parent, this method returns
116
    /// a reference to that span. If the event's parent is the current span,
117
    /// this returns a reference to the current span, if there is one. If this
118
    /// returns `None`, then either the event's parent was explicitly set to
119
    /// `None`, or the event's parent was defined contextually, but no span
120
    /// is currently entered.
121
    ///
122
    /// Compared to [`Context::current_span`] and [`Context::lookup_current`],
123
    /// this respects overrides provided by the [`Event`].
124
    ///
125
    /// Compared to [`Event::parent`], this automatically falls back to the contextual
126
    /// span, if required.
127
    ///
128
    /// ```rust
129
    /// use tracing::{Event, Subscriber};
130
    /// use tracing_subscriber::{
131
    ///     layer::{Context, Layer},
132
    ///     prelude::*,
133
    ///     registry::LookupSpan,
134
    /// };
135
    ///
136
    /// struct PrintingLayer;
137
    /// impl<S> Layer<S> for PrintingLayer
138
    /// where
139
    ///     S: Subscriber + for<'lookup> LookupSpan<'lookup>,
140
    /// {
141
    ///     fn on_event(&self, event: &Event, ctx: Context<S>) {
142
    ///         let span = ctx.event_span(event);
143
    ///         println!("Event in span: {:?}", span.map(|s| s.name()));
144
    ///     }
145
    /// }
146
    ///
147
    /// tracing::subscriber::with_default(tracing_subscriber::registry().with(PrintingLayer), || {
148
    ///     tracing::info!("no span");
149
    ///     // Prints: Event in span: None
150
    ///
151
    ///     let span = tracing::info_span!("span");
152
    ///     tracing::info!(parent: &span, "explicitly specified");
153
    ///     // Prints: Event in span: Some("span")
154
    ///
155
    ///     let _guard = span.enter();
156
    ///     tracing::info!("contextual span");
157
    ///     // Prints: Event in span: Some("span")
158
    /// });
159
    /// ```
160
    ///
161
    /// <pre class="ignore" style="white-space:normal;font:inherit;">
162
    ///     <strong>Note</strong>: This requires the wrapped subscriber to
163
    ///     implement the <a href="../registry/trait.LookupSpan.html"><code>
164
    ///     LookupSpan</code></a> trait. See the documentation on
165
    ///     <a href="./struct.Context.html"><code>Context</code>'s
166
    ///     declaration</a> for details.
167
    /// </pre>
168
    #[inline]
169
0
    pub fn event_span(&self, event: &Event<'_>) -> Option<SpanRef<'_, S>>
170
0
    where
171
0
        S: for<'lookup> LookupSpan<'lookup>,
172
0
    {
173
0
        if event.is_root() {
174
0
            None
175
0
        } else if event.is_contextual() {
176
0
            self.lookup_current()
177
        } else {
178
            // TODO(eliza): this should handle parent IDs
179
0
            event.parent().and_then(|id| self.span(id))
180
        }
181
0
    }
182
183
    /// Returns metadata for the span with the given `id`, if it exists.
184
    ///
185
    /// If this returns `None`, then no span exists for that ID (either it has
186
    /// closed or the ID is invalid).
187
    #[inline]
188
0
    pub fn metadata(&self, id: &span::Id) -> Option<&'static Metadata<'static>>
189
0
    where
190
0
        S: for<'lookup> LookupSpan<'lookup>,
191
0
    {
192
0
        let span = self.span(id)?;
193
0
        Some(span.metadata())
194
0
    }
195
196
    /// Returns [stored data] for the span with the given `id`, if it exists.
197
    ///
198
    /// If this returns `None`, then no span exists for that ID (either it has
199
    /// closed or the ID is invalid).
200
    ///
201
    /// <pre class="ignore" style="white-space:normal;font:inherit;">
202
    ///     <strong>Note</strong>: This requires the wrapped subscriber to
203
    ///     implement the <a href="../registry/trait.LookupSpan.html"><code>
204
    ///     LookupSpan</code></a> trait. See the documentation on
205
    ///     <a href="./struct.Context.html"><code>Context</code>'s
206
    ///     declaration</a> for details.
207
    /// </pre>
208
    ///
209
    /// [stored data]: crate::registry::SpanRef
210
    #[inline]
211
0
    pub fn span(&self, id: &span::Id) -> Option<registry::SpanRef<'_, S>>
212
0
    where
213
0
        S: for<'lookup> LookupSpan<'lookup>,
214
0
    {
215
0
        let span = self.subscriber.as_ref()?.span(id)?;
216
217
        #[cfg(all(feature = "registry", feature = "std"))]
218
0
        return span.try_with_filter(self.filter);
219
220
        #[cfg(not(feature = "registry"))]
221
        Some(span)
222
0
    }
223
224
    /// Returns `true` if an active span exists for the given `Id`.
225
    ///
226
    /// <pre class="ignore" style="white-space:normal;font:inherit;">
227
    ///     <strong>Note</strong>: This requires the wrapped subscriber to
228
    ///     implement the <a href="../registry/trait.LookupSpan.html"><code>
229
    ///     LookupSpan</code></a> trait. See the documentation on
230
    ///     <a href="./struct.Context.html"><code>Context</code>'s
231
    ///     declaration</a> for details.
232
    /// </pre>
233
    #[inline]
234
0
    pub fn exists(&self, id: &span::Id) -> bool
235
0
    where
236
0
        S: for<'lookup> LookupSpan<'lookup>,
237
0
    {
238
0
        self.subscriber.as_ref().and_then(|s| s.span(id)).is_some()
239
0
    }
240
241
    /// Returns [stored data] for the span that the wrapped subscriber considers
242
    /// to be the current.
243
    ///
244
    /// If this returns `None`, then we are not currently within a span.
245
    ///
246
    /// <pre class="ignore" style="white-space:normal;font:inherit;">
247
    ///     <strong>Note</strong>: This requires the wrapped subscriber to
248
    ///     implement the <a href="../registry/trait.LookupSpan.html"><code>
249
    ///     LookupSpan</code></a> trait. See the documentation on
250
    ///     <a href="./struct.Context.html"><code>Context</code>'s
251
    ///     declaration</a> for details.
252
    /// </pre>
253
    ///
254
    /// [stored data]: crate::registry::SpanRef
255
    #[inline]
256
0
    pub fn lookup_current(&self) -> Option<registry::SpanRef<'_, S>>
257
0
    where
258
0
        S: for<'lookup> LookupSpan<'lookup>,
259
0
    {
260
0
        let subscriber = *self.subscriber.as_ref()?;
261
0
        let current = subscriber.current_span();
262
0
        let id = current.id()?;
263
0
        let span = subscriber.span(id);
264
0
        debug_assert!(
265
0
            span.is_some(),
266
0
            "the subscriber should have data for the current span ({:?})!",
267
            id,
268
        );
269
270
        // If we found a span, and our per-layer filter enables it, return that
271
        // span!
272
        #[cfg(all(feature = "registry", feature = "std"))]
273
        {
274
0
            if let Some(span) = span?.try_with_filter(self.filter) {
275
0
                Some(span)
276
            } else {
277
                // Otherwise, the span at the *top* of the stack is disabled by
278
                // per-layer filtering, but there may be additional spans in the stack.
279
                //
280
                // Currently, `LookupSpan` doesn't have a nice way of exposing access to
281
                // the whole span stack. However, if we can downcast the innermost
282
                // subscriber to a a `Registry`, we can iterate over its current span
283
                // stack.
284
                //
285
                // TODO(eliza): when https://github.com/tokio-rs/tracing/issues/1459 is
286
                // implemented, change this to use that instead...
287
0
                self.lookup_current_filtered(subscriber)
288
            }
289
        }
290
291
        #[cfg(not(feature = "registry"))]
292
        span
293
0
    }
294
295
    /// Slow path for when the current span is disabled by PLF and we have a
296
    /// registry.
297
    // This is called by `lookup_current` in the case that per-layer filtering
298
    // is in use. `lookup_current` is allowed to be inlined, but this method is
299
    // factored out to prevent the loop and (potentially-recursive) subscriber
300
    // downcasting from being inlined if `lookup_current` is inlined.
301
    #[inline(never)]
302
    #[cfg(all(feature = "registry", feature = "std"))]
303
0
    fn lookup_current_filtered<'lookup>(
304
0
        &self,
305
0
        subscriber: &'lookup S,
306
0
    ) -> Option<registry::SpanRef<'lookup, S>>
307
0
    where
308
0
        S: LookupSpan<'lookup>,
309
0
    {
310
0
        let registry = (subscriber as &dyn Subscriber).downcast_ref::<Registry>()?;
311
0
        registry
312
0
            .span_stack()
313
0
            .iter()
314
0
            .find_map(|id| subscriber.span(id)?.try_with_filter(self.filter))
315
0
    }
316
317
    /// Returns an iterator over the [stored data] for all the spans in the
318
    /// current context, starting with the specified span and ending with the
319
    /// root of the trace tree.
320
    ///
321
    /// <pre class="ignore" style="white-space:normal;font:inherit;">
322
    /// <strong>Note</strong>: This returns the spans in reverse order (from leaf to root). Use
323
    /// <a href="../registry/struct.Scope.html#method.from_root"><code>Scope::from_root</code></a>
324
    /// in case root-to-leaf ordering is desired.
325
    /// </pre>
326
    ///
327
    /// <pre class="ignore" style="white-space:normal;font:inherit;">
328
    ///     <strong>Note</strong>: This requires the wrapped subscriber to
329
    ///     implement the <a href="../registry/trait.LookupSpan.html"><code>
330
    ///     LookupSpan</code></a> trait. See the documentation on
331
    ///     <a href="./struct.Context.html"><code>Context</code>'s
332
    ///     declaration</a> for details.
333
    /// </pre>
334
    ///
335
    /// [stored data]: crate::registry::SpanRef
336
0
    pub fn span_scope(&self, id: &span::Id) -> Option<registry::Scope<'_, S>>
337
0
    where
338
0
        S: for<'lookup> LookupSpan<'lookup>,
339
0
    {
340
0
        Some(self.span(id)?.scope())
341
0
    }
342
343
    /// Returns an iterator over the [stored data] for all the spans in the
344
    /// current context, starting with the parent span of the specified event,
345
    /// and ending with the root of the trace tree and ending with the current span.
346
    ///
347
    /// <pre class="ignore" style="white-space:normal;font:inherit;">
348
    /// <strong>Note</strong>: Compared to <a href="#method.scope"><code>scope</code></a> this
349
    /// returns the spans in reverse order (from leaf to root). Use
350
    /// <a href="../registry/struct.Scope.html#method.from_root"><code>Scope::from_root</code></a>
351
    /// in case root-to-leaf ordering is desired.
352
    /// </pre>
353
    ///
354
    /// <pre class="ignore" style="white-space:normal;font:inherit;">
355
    ///     <strong>Note</strong>: This requires the wrapped subscriber to
356
    ///     implement the <a href="../registry/trait.LookupSpan.html"><code>
357
    ///     LookupSpan</code></a> trait. See the documentation on
358
    ///     <a href="./struct.Context.html"><code>Context</code>'s
359
    ///     declaration</a> for details.
360
    /// </pre>
361
    ///
362
    /// [stored data]: crate::registry::SpanRef
363
0
    pub fn event_scope(&self, event: &Event<'_>) -> Option<registry::Scope<'_, S>>
364
0
    where
365
0
        S: for<'lookup> LookupSpan<'lookup>,
366
0
    {
367
0
        Some(self.event_span(event)?.scope())
368
0
    }
369
370
    #[cfg(all(feature = "registry", feature = "std"))]
371
0
    pub(crate) fn with_filter(self, filter: FilterId) -> Self {
372
0
        // If we already have our own `FilterId`, combine it with the provided
373
0
        // one. That way, the new `FilterId` will consider a span to be disabled
374
0
        // if it was disabled by the given `FilterId` *or* any `FilterId`s for
375
0
        // layers "above" us in the stack.
376
0
        //
377
0
        // See the doc comment for `FilterId::and` for details.
378
0
        let filter = self.filter.and(filter);
379
0
        Self { filter, ..self }
380
0
    }
381
382
    #[cfg(all(feature = "registry", feature = "std"))]
383
0
    pub(crate) fn is_enabled_for(&self, span: &span::Id, filter: FilterId) -> bool
384
0
    where
385
0
        S: for<'lookup> LookupSpan<'lookup>,
386
0
    {
387
0
        self.is_enabled_inner(span, filter).unwrap_or(false)
388
0
    }
389
390
    #[cfg(all(feature = "registry", feature = "std"))]
391
0
    pub(crate) fn if_enabled_for(self, span: &span::Id, filter: FilterId) -> Option<Self>
392
0
    where
393
0
        S: for<'lookup> LookupSpan<'lookup>,
394
0
    {
395
0
        if self.is_enabled_inner(span, filter)? {
396
0
            Some(self.with_filter(filter))
397
        } else {
398
0
            None
399
        }
400
0
    }
401
402
    #[cfg(all(feature = "registry", feature = "std"))]
403
0
    fn is_enabled_inner(&self, span: &span::Id, filter: FilterId) -> Option<bool>
404
0
    where
405
0
        S: for<'lookup> LookupSpan<'lookup>,
406
0
    {
407
0
        Some(self.span(span)?.is_enabled_for(filter))
408
0
    }
409
}
410
411
impl<S> Context<'_, S> {
412
0
    pub(crate) fn none() -> Self {
413
0
        Self {
414
0
            subscriber: None,
415
0
416
0
            #[cfg(feature = "registry")]
417
0
            filter: FilterId::none(),
418
0
        }
419
0
    }
420
}
421
422
impl<S> Clone for Context<'_, S> {
423
    #[inline]
424
0
    fn clone(&self) -> Self {
425
0
        let subscriber = self.subscriber.as_ref().copied();
426
0
        Context {
427
0
            subscriber,
428
0
429
0
            #[cfg(all(feature = "registry", feature = "std"))]
430
0
            filter: self.filter,
431
0
        }
432
0
    }
433
}