1 use tracing_core
::{metadata::Metadata, span, subscriber::Subscriber, Event}
;
3 use crate::registry
::{self, LookupSpan, SpanRef}
;
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`].
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
15 /// use tracing::Subscriber;
16 /// use tracing_subscriber::{Layer, registry::LookupSpan};
18 /// pub struct MyLayer;
20 /// impl<S> Layer<S> for MyLayer
22 /// S: Subscriber + for<'a> LookupSpan<'a>,
28 /// [`Layer`]: super::Layer
29 /// [`Subscriber`]: tracing_core::Subscriber
30 /// [stored data]: crate::registry::SpanRef
31 /// [`LookupSpan`]: crate::registry::LookupSpan
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.
42 /// [`Filtered`]: crate::filter::Filtered
43 /// [`FilterId`]: crate::filter::FilterId
44 /// [`and`]: crate::filter::FilterId::and
45 #[cfg(all(feature = "registry", feature = "std"))]
49 // === impl Context ===
51 impl<'a
, S
> Context
<'a
, S
>
55 pub(super) fn new(subscriber
: &'a S
) -> Self {
57 subscriber
: Some(subscriber
),
59 #[cfg(feature = "registry")]
60 filter
: FilterId
::none(),
64 /// Returns the wrapped subscriber's view of the current span.
66 pub fn current_span(&self) -> span
::Current
{
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
)
74 /// Returns whether the wrapped subscriber would enable the current span.
76 pub fn enabled(&self, metadata
: &Metadata
<'_
>) -> bool
{
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`?
86 /// Records the provided `event` with the wrapped subscriber.
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.
102 /// [register]: tracing_core::subscriber::Subscriber::register_callsite()
103 /// [`enabled`]: tracing_core::subscriber::Subscriber::enabled()
104 /// [`Context::enabled`]: Context::enabled()
106 pub fn event(&self, event
: &Event
<'_
>) {
107 if let Some(subscriber
) = self.subscriber
{
108 subscriber
.event(event
);
112 /// Returns a [`SpanRef`] for the parent span of the given [`Event`], if
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.
122 /// Compared to [`Context::current_span`] and [`Context::lookup_current`],
123 /// this respects overrides provided by the [`Event`].
125 /// Compared to [`Event::parent`], this automatically falls back to the contextual
126 /// span, if required.
129 /// use tracing::{Event, Subscriber};
130 /// use tracing_subscriber::{
131 /// layer::{Context, Layer},
133 /// registry::LookupSpan,
136 /// struct PrintingLayer;
137 /// impl<S> Layer<S> for PrintingLayer
139 /// S: Subscriber + for<'lookup> LookupSpan<'lookup>,
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()));
147 /// tracing::subscriber::with_default(tracing_subscriber::registry().with(PrintingLayer), || {
148 /// tracing::info!("no span");
149 /// // Prints: Event in span: None
151 /// let span = tracing::info_span!("span");
152 /// tracing::info!(parent: &span, "explicitly specified");
153 /// // Prints: Event in span: Some("span")
155 /// let _guard = span.enter();
156 /// tracing::info!("contextual span");
157 /// // Prints: Event in span: Some("span")
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.
169 pub fn event_span(&self, event
: &Event
<'_
>) -> Option
<SpanRef
<'_
, S
>>
171 S
: for<'lookup
> LookupSpan
<'lookup
>,
175 } else if event
.is_contextual() {
176 self.lookup_current()
178 // TODO(eliza): this should handle parent IDs
179 event
.parent().and_then(|id
| self.span(id
))
183 /// Returns metadata for the span with the given `id`, if it exists.
185 /// If this returns `None`, then no span exists for that ID (either it has
186 /// closed or the ID is invalid).
188 pub fn metadata(&self, id
: &span
::Id
) -> Option
<&'
static Metadata
<'
static>>
190 S
: for<'lookup
> LookupSpan
<'lookup
>,
192 let span
= self.span(id
)?
;
193 Some(span
.metadata())
196 /// Returns [stored data] for the span with the given `id`, if it exists.
198 /// If this returns `None`, then no span exists for that ID (either it has
199 /// closed or the ID is invalid).
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.
209 /// [stored data]: crate::registry::SpanRef
211 pub fn span(&self, id
: &span
::Id
) -> Option
<registry
::SpanRef
<'_
, S
>>
213 S
: for<'lookup
> LookupSpan
<'lookup
>,
215 let span
= self.subscriber
.as_ref()?
.span(id
)?
;
217 #[cfg(all(feature = "registry", feature = "std"))]
218 return span
.try_with_filter(self.filter
);
220 #[cfg(not(feature = "registry"))]
224 /// Returns `true` if an active span exists for the given `Id`.
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.
234 pub fn exists(&self, id
: &span
::Id
) -> bool
236 S
: for<'lookup
> LookupSpan
<'lookup
>,
238 self.subscriber
.as_ref().and_then(|s
| s
.span(id
)).is_some()
241 /// Returns [stored data] for the span that the wrapped subscriber considers
242 /// to be the current.
244 /// If this returns `None`, then we are not currently within a span.
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.
254 /// [stored data]: crate::registry::SpanRef
256 pub fn lookup_current(&self) -> Option
<registry
::SpanRef
<'_
, S
>>
258 S
: for<'lookup
> LookupSpan
<'lookup
>,
260 let subscriber
= *self.subscriber
.as_ref()?
;
261 let current
= subscriber
.current_span();
262 let id
= current
.id()?
;
263 let span
= subscriber
.span(id
);
266 "the subscriber should have data for the current span ({:?})!",
270 // If we found a span, and our per-layer filter enables it, return that
272 #[cfg(all(feature = "registry", feature = "std"))]
274 if let Some(span
) = span?
.try_with_filter(self.filter
) {
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.
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
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
)
291 #[cfg(not(feature = "registry"))]
295 /// Slow path for when the current span is disabled by PLF and we have a
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.
302 #[cfg(all(feature = "registry", feature = "std"))]
303 fn lookup_current_filtered
<'lookup
>(
305 subscriber
: &'lookup S
,
306 ) -> Option
<registry
::SpanRef
<'lookup
, S
>>
308 S
: LookupSpan
<'lookup
>,
310 let registry
= (subscriber
as &dyn Subscriber
).downcast_ref
::<Registry
>()?
;
314 .find_map(|id
| subscriber
.span(id
)?
.try_with_filter(self.filter
))
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.
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.
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.
336 /// [stored data]: crate::registry::SpanRef
337 pub fn span_scope(&self, id
: &span
::Id
) -> Option
<registry
::Scope
<'_
, S
>>
339 S
: for<'lookup
> LookupSpan
<'lookup
>,
341 Some(self.span(id
)?
.scope())
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.
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.
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.
363 /// [stored data]: crate::registry::SpanRef
364 pub fn event_scope(&self, event
: &Event
<'_
>) -> Option
<registry
::Scope
<'_
, S
>>
366 S
: for<'lookup
> LookupSpan
<'lookup
>,
368 Some(self.event_span(event
)?
.scope())
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.
378 // See the doc comment for `FilterId::and` for details.
379 let filter
= self.filter
.and(filter
);
380 Self { filter, ..self }
383 #[cfg(all(feature = "registry", feature = "std"))]
384 pub(crate) fn is_enabled_for(&self, span
: &span
::Id
, filter
: FilterId
) -> bool
386 S
: for<'lookup
> LookupSpan
<'lookup
>,
388 self.is_enabled_inner(span
, filter
).unwrap_or(false)
391 #[cfg(all(feature = "registry", feature = "std"))]
392 pub(crate) fn if_enabled_for(self, span
: &span
::Id
, filter
: FilterId
) -> Option
<Self>
394 S
: for<'lookup
> LookupSpan
<'lookup
>,
396 if self.is_enabled_inner(span
, filter
)?
{
397 Some(self.with_filter(filter
))
403 #[cfg(all(feature = "registry", feature = "std"))]
404 fn is_enabled_inner(&self, span
: &span
::Id
, filter
: FilterId
) -> Option
<bool
>
406 S
: for<'lookup
> LookupSpan
<'lookup
>,
408 Some(self.span(span
)?
.is_enabled_for(filter
))
412 impl<'a
, S
> Context
<'a
, S
> {
413 pub(crate) fn none() -> Self {
417 #[cfg(feature = "registry")]
418 filter
: FilterId
::none(),
423 impl<'a
, S
> Clone
for Context
<'a
, S
> {
425 fn clone(&self) -> Self {
426 let subscriber
= self.subscriber
.as_ref().copied();
430 #[cfg(all(feature = "registry", feature = "std"))]