1use tracing_core::{metadata::Metadata, span, subscriber::Subscriber, Event};
2
3use crate::registry::{self, LookupSpan, SpanRef};
4
5#[cfg(all(feature = "registry", feature = "std"))]
6use 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)]
33pub 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
51impl<'a, S> Context<'a, S>
52where
53 S: Subscriber,
54{
55 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]
66 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]
76 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]
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]
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]
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]
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]
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]
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"))]
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
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
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"))]
372 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"))]
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"))]
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"))]
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
412impl<'a, S> Context<'a, S> {
413 pub(crate) fn none() -> Self {
414 Self {
415 subscriber: None,
416
417 #[cfg(feature = "registry")]
418 filter: FilterId::none(),
419 }
420 }
421}
422
423impl<'a, S> Clone for Context<'a, S> {
424 #[inline]
425 fn clone(&self) -> Self {
426 let subscriber: Option<&S> = 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