• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
new(subscriber: &'a S) -> Self55     pub(super) fn new(subscriber: &'a S) -> Self {
56         Self {
57             subscriber: Some(subscriber),
58 
59             #[cfg(feature = "registry")]
60             filter: FilterId::none(),
61         }
62     }
63 
64     /// Returns the wrapped subscriber's view of the current span.
65     #[inline]
current_span(&self) -> span::Current66     pub fn current_span(&self) -> span::Current {
67         self.subscriber
68             .map(Subscriber::current_span)
69             // TODO: this would be more correct as "unknown", so perhaps
70             // `tracing-core` should make `Current::unknown()` public?
71             .unwrap_or_else(span::Current::none)
72     }
73 
74     /// Returns whether the wrapped subscriber would enable the current span.
75     #[inline]
enabled(&self, metadata: &Metadata<'_>) -> bool76     pub fn enabled(&self, metadata: &Metadata<'_>) -> bool {
77         self.subscriber
78             .map(|subscriber| subscriber.enabled(metadata))
79             // If this context is `None`, we are registering a callsite, so
80             // return `true` so that the layer does not incorrectly assume that
81             // the inner subscriber has disabled this metadata.
82             // TODO(eliza): would it be more correct for this to return an `Option`?
83             .unwrap_or(true)
84     }
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]
event(&self, event: &Event<'_>)106     pub fn event(&self, event: &Event<'_>) {
107         if let Some(subscriber) = self.subscriber {
108             subscriber.event(event);
109         }
110     }
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]
event_span(&self, event: &Event<'_>) -> Option<SpanRef<'_, S>> where S: for<'lookup> LookupSpan<'lookup>,169     pub fn event_span(&self, event: &Event<'_>) -> Option<SpanRef<'_, S>>
170     where
171         S: for<'lookup> LookupSpan<'lookup>,
172     {
173         if event.is_root() {
174             None
175         } else if event.is_contextual() {
176             self.lookup_current()
177         } else {
178             // TODO(eliza): this should handle parent IDs
179             event.parent().and_then(|id| self.span(id))
180         }
181     }
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]
metadata(&self, id: &span::Id) -> Option<&'static Metadata<'static>> where S: for<'lookup> LookupSpan<'lookup>,188     pub fn metadata(&self, id: &span::Id) -> Option<&'static Metadata<'static>>
189     where
190         S: for<'lookup> LookupSpan<'lookup>,
191     {
192         let span = self.span(id)?;
193         Some(span.metadata())
194     }
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]
span(&self, id: &span::Id) -> Option<registry::SpanRef<'_, S>> where S: for<'lookup> LookupSpan<'lookup>,211     pub fn span(&self, id: &span::Id) -> Option<registry::SpanRef<'_, S>>
212     where
213         S: for<'lookup> LookupSpan<'lookup>,
214     {
215         let span = self.subscriber.as_ref()?.span(id)?;
216 
217         #[cfg(all(feature = "registry", feature = "std"))]
218         return span.try_with_filter(self.filter);
219 
220         #[cfg(not(feature = "registry"))]
221         Some(span)
222     }
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]
exists(&self, id: &span::Id) -> bool where S: for<'lookup> LookupSpan<'lookup>,234     pub fn exists(&self, id: &span::Id) -> bool
235     where
236         S: for<'lookup> LookupSpan<'lookup>,
237     {
238         self.subscriber.as_ref().and_then(|s| s.span(id)).is_some()
239     }
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]
lookup_current(&self) -> Option<registry::SpanRef<'_, S>> where S: for<'lookup> LookupSpan<'lookup>,256     pub fn lookup_current(&self) -> Option<registry::SpanRef<'_, S>>
257     where
258         S: for<'lookup> LookupSpan<'lookup>,
259     {
260         let subscriber = *self.subscriber.as_ref()?;
261         let current = subscriber.current_span();
262         let id = current.id()?;
263         let span = subscriber.span(id);
264         debug_assert!(
265             span.is_some(),
266             "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             if let Some(span) = span?.try_with_filter(self.filter) {
275                 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                 self.lookup_current_filtered(subscriber)
288             }
289         }
290 
291         #[cfg(not(feature = "registry"))]
292         span
293     }
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"))]
lookup_current_filtered<'lookup>( &self, subscriber: &'lookup S, ) -> Option<registry::SpanRef<'lookup, S>> where S: LookupSpan<'lookup>,303     fn lookup_current_filtered<'lookup>(
304         &self,
305         subscriber: &'lookup S,
306     ) -> Option<registry::SpanRef<'lookup, S>>
307     where
308         S: LookupSpan<'lookup>,
309     {
310         let registry = (subscriber as &dyn Subscriber).downcast_ref::<Registry>()?;
311         registry
312             .span_stack()
313             .iter()
314             .find_map(|id| subscriber.span(id)?.try_with_filter(self.filter))
315     }
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 and ending with the current span.
320     ///
321     /// <pre class="ignore" style="white-space:normal;font:inherit;">
322     /// <strong>Note</strong>: Compared to <a href="#method.scope"><code>scope</code></a> this
323     /// returns the spans in reverse order (from leaf to root). Use
324     /// <a href="../registry/struct.Scope.html#method.from_root"><code>Scope::from_root</code></a>
325     /// in case root-to-leaf ordering is desired.
326     /// </pre>
327     ///
328     /// <pre class="ignore" style="white-space:normal;font:inherit;">
329     ///     <strong>Note</strong>: This requires the wrapped subscriber to
330     ///     implement the <a href="../registry/trait.LookupSpan.html"><code>
331     ///     LookupSpan</code></a> trait. See the documentation on
332     ///     <a href="./struct.Context.html"><code>Context</code>'s
333     ///     declaration</a> for details.
334     /// </pre>
335     ///
336     /// [stored data]: crate::registry::SpanRef
span_scope(&self, id: &span::Id) -> Option<registry::Scope<'_, S>> where S: for<'lookup> LookupSpan<'lookup>,337     pub fn span_scope(&self, id: &span::Id) -> Option<registry::Scope<'_, S>>
338     where
339         S: for<'lookup> LookupSpan<'lookup>,
340     {
341         Some(self.span(id)?.scope())
342     }
343 
344     /// Returns an iterator over the [stored data] for all the spans in the
345     /// current context, starting with the parent span of the specified event,
346     /// and ending with the root of the trace tree and ending with the current span.
347     ///
348     /// <pre class="ignore" style="white-space:normal;font:inherit;">
349     /// <strong>Note</strong>: Compared to <a href="#method.scope"><code>scope</code></a> this
350     /// returns the spans in reverse order (from leaf to root). Use
351     /// <a href="../registry/struct.Scope.html#method.from_root"><code>Scope::from_root</code></a>
352     /// in case root-to-leaf ordering is desired.
353     /// </pre>
354     ///
355     /// <pre class="ignore" style="white-space:normal;font:inherit;">
356     ///     <strong>Note</strong>: This requires the wrapped subscriber to
357     ///     implement the <a href="../registry/trait.LookupSpan.html"><code>
358     ///     LookupSpan</code></a> trait. See the documentation on
359     ///     <a href="./struct.Context.html"><code>Context</code>'s
360     ///     declaration</a> for details.
361     /// </pre>
362     ///
363     /// [stored data]: crate::registry::SpanRef
event_scope(&self, event: &Event<'_>) -> Option<registry::Scope<'_, S>> where S: for<'lookup> LookupSpan<'lookup>,364     pub fn event_scope(&self, event: &Event<'_>) -> Option<registry::Scope<'_, S>>
365     where
366         S: for<'lookup> LookupSpan<'lookup>,
367     {
368         Some(self.event_span(event)?.scope())
369     }
370 
371     #[cfg(all(feature = "registry", feature = "std"))]
with_filter(self, filter: FilterId) -> Self372     pub(crate) fn with_filter(self, filter: FilterId) -> Self {
373         // If we already have our own `FilterId`, combine it with the provided
374         // one. That way, the new `FilterId` will consider a span to be disabled
375         // if it was disabled by the given `FilterId` *or* any `FilterId`s for
376         // layers "above" us in the stack.
377         //
378         // See the doc comment for `FilterId::and` for details.
379         let filter = self.filter.and(filter);
380         Self { filter, ..self }
381     }
382 
383     #[cfg(all(feature = "registry", feature = "std"))]
is_enabled_for(&self, span: &span::Id, filter: FilterId) -> bool where S: for<'lookup> LookupSpan<'lookup>,384     pub(crate) fn is_enabled_for(&self, span: &span::Id, filter: FilterId) -> bool
385     where
386         S: for<'lookup> LookupSpan<'lookup>,
387     {
388         self.is_enabled_inner(span, filter).unwrap_or(false)
389     }
390 
391     #[cfg(all(feature = "registry", feature = "std"))]
if_enabled_for(self, span: &span::Id, filter: FilterId) -> Option<Self> where S: for<'lookup> LookupSpan<'lookup>,392     pub(crate) fn if_enabled_for(self, span: &span::Id, filter: FilterId) -> Option<Self>
393     where
394         S: for<'lookup> LookupSpan<'lookup>,
395     {
396         if self.is_enabled_inner(span, filter)? {
397             Some(self.with_filter(filter))
398         } else {
399             None
400         }
401     }
402 
403     #[cfg(all(feature = "registry", feature = "std"))]
is_enabled_inner(&self, span: &span::Id, filter: FilterId) -> Option<bool> where S: for<'lookup> LookupSpan<'lookup>,404     fn is_enabled_inner(&self, span: &span::Id, filter: FilterId) -> Option<bool>
405     where
406         S: for<'lookup> LookupSpan<'lookup>,
407     {
408         Some(self.span(span)?.is_enabled_for(filter))
409     }
410 }
411 
412 impl<'a, S> Context<'a, S> {
none() -> Self413     pub(crate) fn none() -> Self {
414         Self {
415             subscriber: None,
416 
417             #[cfg(feature = "registry")]
418             filter: FilterId::none(),
419         }
420     }
421 }
422 
423 impl<'a, S> Clone for Context<'a, S> {
424     #[inline]
clone(&self) -> Self425     fn clone(&self) -> Self {
426         let subscriber = self.subscriber.as_ref().copied();
427         Context {
428             subscriber,
429 
430             #[cfg(all(feature = "registry", feature = "std"))]
431             filter: self.filter,
432         }
433     }
434 }
435