/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 | | } |