1 //! Storage for span data shared by multiple [`Layer`]s.
2 //!
3 //! ## Using the Span Registry
4 //!
5 //! This module provides the [`Registry`] type, a [`Subscriber`] implementation
6 //! which tracks per-span data and exposes it to [`Layer`]s. When a `Registry`
7 //! is used as the base `Subscriber` of a `Layer` stack, the
8 //! [`layer::Context`][ctx] type will provide methods allowing `Layer`s to
9 //! [look up span data][lookup] stored in the registry. While [`Registry`] is a
10 //! reasonable default for storing spans and events, other stores that implement
11 //! [`LookupSpan`] and [`Subscriber`] themselves (with [`SpanData`] implemented
12 //! by the per-span data they store) can be used as a drop-in replacement.
13 //!
14 //! For example, we might create a `Registry` and add multiple `Layer`s like so:
15 //! ```rust
16 //! use tracing_subscriber::{registry::Registry, Layer, prelude::*};
17 //! # use tracing_core::Subscriber;
18 //! # pub struct FooLayer {}
19 //! # pub struct BarLayer {}
20 //! # impl<S: Subscriber> Layer<S> for FooLayer {}
21 //! # impl<S: Subscriber> Layer<S> for BarLayer {}
22 //! # impl FooLayer {
23 //! # fn new() -> Self { Self {} }
24 //! # }
25 //! # impl BarLayer {
26 //! # fn new() -> Self { Self {} }
27 //! # }
28 //!
29 //! let subscriber = Registry::default()
30 //!     .with(FooLayer::new())
31 //!     .with(BarLayer::new());
32 //! ```
33 //!
34 //! If a type implementing `Layer` depends on the functionality of a `Registry`
35 //! implementation, it should bound its `Subscriber` type parameter with the
36 //! [`LookupSpan`] trait, like so:
37 //!
38 //! ```rust
39 //! use tracing_subscriber::{registry, Layer};
40 //! use tracing_core::Subscriber;
41 //!
42 //! pub struct MyLayer {
43 //!     // ...
44 //! }
45 //!
46 //! impl<S> Layer<S> for MyLayer
47 //! where
48 //!     S: Subscriber + for<'a> registry::LookupSpan<'a>,
49 //! {
50 //!     // ...
51 //! }
52 //! ```
53 //! When this bound is added, the `Layer` implementation will be guaranteed
54 //! access to the [`Context`][ctx] methods, such as [`Context::span`][lookup], that
55 //! require the root subscriber to be a registry.
56 //!
57 //! [`Layer`]: crate::layer::Layer
58 //! [`Subscriber`]: tracing_core::Subscriber
59 //! [ctx]: crate::layer::Context
60 //! [lookup]: crate::layer::Context::span()
61 use tracing_core::{field::FieldSet, span::Id, Metadata};
62 
63 feature! {
64     #![feature = "std"]
65     /// A module containing a type map of span extensions.
66     mod extensions;
67     pub use extensions::{Extensions, ExtensionsMut};
68 
69 }
70 
71 feature! {
72     #![all(feature = "registry", feature = "std")]
73 
74     mod sharded;
75     mod stack;
76 
77     pub use sharded::Data;
78     pub use sharded::Registry;
79 
80     use crate::filter::FilterId;
81 }
82 
83 /// Provides access to stored span data.
84 ///
85 /// Subscribers which store span data and associate it with span IDs should
86 /// implement this trait; if they do, any [`Layer`]s wrapping them can look up
87 /// metadata via the [`Context`] type's [`span()`] method.
88 ///
89 /// [`Layer`]: super::layer::Layer
90 /// [`Context`]: super::layer::Context
91 /// [`span()`]: super::layer::Context::span
92 pub trait LookupSpan<'a> {
93     /// The type of span data stored in this registry.
94     type Data: SpanData<'a>;
95 
96     /// Returns the [`SpanData`] for a given `Id`, if it exists.
97     ///
98     /// <pre class="ignore" style="white-space:normal;font:inherit;">
99     /// <strong>Note</strong>: users of the <code>LookupSpan</code> trait should
100     /// typically call the <a href="#method.span"><code>span</code></a> method rather
101     /// than this method. The <code>span</code> method is implemented by
102     /// <em>calling</em> <code>span_data</code>, but returns a reference which is
103     /// capable of performing more sophisiticated queries.
104     /// </pre>
105     ///
span_data(&'a self, id: &Id) -> Option<Self::Data>106     fn span_data(&'a self, id: &Id) -> Option<Self::Data>;
107 
108     /// Returns a [`SpanRef`] for the span with the given `Id`, if it exists.
109     ///
110     /// A `SpanRef` is similar to [`SpanData`], but it allows performing
111     /// additional lookups against the registryr that stores the wrapped data.
112     ///
113     /// In general, _users_ of the `LookupSpan` trait should use this method
114     /// rather than the [`span_data`] method; while _implementors_ of this trait
115     /// should only implement `span_data`.
116     ///
117     /// [`span_data`]: LookupSpan::span_data()
span(&'a self, id: &Id) -> Option<SpanRef<'_, Self>> where Self: Sized,118     fn span(&'a self, id: &Id) -> Option<SpanRef<'_, Self>>
119     where
120         Self: Sized,
121     {
122         let data = self.span_data(id)?;
123         Some(SpanRef {
124             registry: self,
125             data,
126             #[cfg(feature = "registry")]
127             filter: FilterId::none(),
128         })
129     }
130 
131     /// Registers a [`Filter`] for [per-layer filtering] with this
132     /// [`Subscriber`].
133     ///
134     /// The [`Filter`] can then use the returned [`FilterId`] to
135     /// [check if it previously enabled a span][check].
136     ///
137     /// # Panics
138     ///
139     /// If this `Subscriber` does not support [per-layer filtering].
140     ///
141     /// [`Filter`]: crate::layer::Filter
142     /// [per-layer filtering]: crate::layer::Layer#per-layer-filtering
143     /// [`Subscriber`]: tracing_core::Subscriber
144     /// [`FilterId`]: crate::filter::FilterId
145     /// [check]: SpanData::is_enabled_for
146     #[cfg(feature = "registry")]
147     #[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
register_filter(&mut self) -> FilterId148     fn register_filter(&mut self) -> FilterId {
149         panic!(
150             "{} does not currently support filters",
151             std::any::type_name::<Self>()
152         )
153     }
154 }
155 
156 /// A stored representation of data associated with a span.
157 pub trait SpanData<'a> {
158     /// Returns this span's ID.
id(&self) -> Id159     fn id(&self) -> Id;
160 
161     /// Returns a reference to the span's `Metadata`.
metadata(&self) -> &'static Metadata<'static>162     fn metadata(&self) -> &'static Metadata<'static>;
163 
164     /// Returns a reference to the ID
parent(&self) -> Option<&Id>165     fn parent(&self) -> Option<&Id>;
166 
167     /// Returns a reference to this span's `Extensions`.
168     ///
169     /// The extensions may be used by `Layer`s to store additional data
170     /// describing the span.
171     #[cfg(feature = "std")]
172     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
extensions(&self) -> Extensions<'_>173     fn extensions(&self) -> Extensions<'_>;
174 
175     /// Returns a mutable reference to this span's `Extensions`.
176     ///
177     /// The extensions may be used by `Layer`s to store additional data
178     /// describing the span.
179     #[cfg(feature = "std")]
180     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
extensions_mut(&self) -> ExtensionsMut<'_>181     fn extensions_mut(&self) -> ExtensionsMut<'_>;
182 
183     /// Returns `true` if this span is enabled for the [per-layer filter][plf]
184     /// corresponding to the provided [`FilterId`].
185     ///
186     /// ## Default Implementation
187     ///
188     /// By default, this method assumes that the [`LookupSpan`] implementation
189     /// does not support [per-layer filtering][plf], and always returns `true`.
190     ///
191     /// [plf]: crate::layer::Layer#per-layer-filtering
192     /// [`FilterId`]: crate::filter::FilterId
193     #[cfg(feature = "registry")]
194     #[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
is_enabled_for(&self, filter: FilterId) -> bool195     fn is_enabled_for(&self, filter: FilterId) -> bool {
196         let _ = filter;
197         true
198     }
199 }
200 
201 /// A reference to [span data] and the associated [registry].
202 ///
203 /// This type implements all the same methods as [`SpanData`], and provides
204 /// additional methods for querying the registry based on values from the span.
205 ///
206 /// [registry]: LookupSpan
207 #[derive(Debug)]
208 pub struct SpanRef<'a, R: LookupSpan<'a>> {
209     registry: &'a R,
210     data: R::Data,
211 
212     #[cfg(feature = "registry")]
213     filter: FilterId,
214 }
215 
216 /// An iterator over the parents of a span, ordered from leaf to root.
217 ///
218 /// This is returned by the [`SpanRef::scope`] method.
219 #[derive(Debug)]
220 pub struct Scope<'a, R> {
221     registry: &'a R,
222     next: Option<Id>,
223 
224     #[cfg(all(feature = "registry", feature = "std"))]
225     filter: FilterId,
226 }
227 
228 feature! {
229     #![any(feature = "alloc", feature = "std")]
230 
231     #[cfg(not(feature = "smallvec"))]
232     use alloc::vec::{self, Vec};
233 
234     use core::{fmt,iter};
235 
236     /// An iterator over the parents of a span, ordered from root to leaf.
237     ///
238     /// This is returned by the [`Scope::from_root`] method.
239     pub struct ScopeFromRoot<'a, R>
240     where
241         R: LookupSpan<'a>,
242     {
243         #[cfg(feature = "smallvec")]
244         spans: iter::Rev<smallvec::IntoIter<SpanRefVecArray<'a, R>>>,
245         #[cfg(not(feature = "smallvec"))]
246         spans: iter::Rev<vec::IntoIter<SpanRef<'a, R>>>,
247     }
248 
249     #[cfg(feature = "smallvec")]
250     type SpanRefVecArray<'span, L> = [SpanRef<'span, L>; 16];
251 
252     impl<'a, R> Scope<'a, R>
253     where
254         R: LookupSpan<'a>,
255     {
256         /// Flips the order of the iterator, so that it is ordered from root to leaf.
257         ///
258         /// The iterator will first return the root span, then that span's immediate child,
259         /// and so on until it finally returns the span that [`SpanRef::scope`] was called on.
260         ///
261         /// If any items were consumed from the [`Scope`] before calling this method then they
262         /// will *not* be returned from the [`ScopeFromRoot`].
263         ///
264         /// **Note**: this will allocate if there are many spans remaining, or if the
265         /// "smallvec" feature flag is not enabled.
266         #[allow(clippy::wrong_self_convention)]
267         pub fn from_root(self) -> ScopeFromRoot<'a, R> {
268             #[cfg(feature = "smallvec")]
269             type Buf<T> = smallvec::SmallVec<T>;
270             #[cfg(not(feature = "smallvec"))]
271             type Buf<T> = Vec<T>;
272             ScopeFromRoot {
273                 spans: self.collect::<Buf<_>>().into_iter().rev(),
274             }
275         }
276     }
277 
278     impl<'a, R> Iterator for ScopeFromRoot<'a, R>
279     where
280         R: LookupSpan<'a>,
281     {
282         type Item = SpanRef<'a, R>;
283 
284         #[inline]
285         fn next(&mut self) -> Option<Self::Item> {
286             self.spans.next()
287         }
288 
289         #[inline]
290         fn size_hint(&self) -> (usize, Option<usize>) {
291             self.spans.size_hint()
292         }
293     }
294 
295     impl<'a, R> fmt::Debug for ScopeFromRoot<'a, R>
296     where
297         R: LookupSpan<'a>,
298     {
299         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300             f.pad("ScopeFromRoot { .. }")
301         }
302     }
303 }
304 
305 impl<'a, R> Iterator for Scope<'a, R>
306 where
307     R: LookupSpan<'a>,
308 {
309     type Item = SpanRef<'a, R>;
310 
next(&mut self) -> Option<Self::Item>311     fn next(&mut self) -> Option<Self::Item> {
312         loop {
313             let curr = self.registry.span(self.next.as_ref()?)?;
314 
315             #[cfg(all(feature = "registry", feature = "std"))]
316             let curr = curr.with_filter(self.filter);
317             self.next = curr.data.parent().cloned();
318 
319             // If the `Scope` is filtered, check if the current span is enabled
320             // by the selected filter ID.
321 
322             #[cfg(all(feature = "registry", feature = "std"))]
323             {
324                 if !curr.is_enabled_for(self.filter) {
325                     // The current span in the chain is disabled for this
326                     // filter. Try its parent.
327                     continue;
328                 }
329             }
330 
331             return Some(curr);
332         }
333     }
334 }
335 
336 impl<'a, R> SpanRef<'a, R>
337 where
338     R: LookupSpan<'a>,
339 {
340     /// Returns this span's ID.
id(&self) -> Id341     pub fn id(&self) -> Id {
342         self.data.id()
343     }
344 
345     /// Returns a static reference to the span's metadata.
metadata(&self) -> &'static Metadata<'static>346     pub fn metadata(&self) -> &'static Metadata<'static> {
347         self.data.metadata()
348     }
349 
350     /// Returns the span's name,
name(&self) -> &'static str351     pub fn name(&self) -> &'static str {
352         self.data.metadata().name()
353     }
354 
355     /// Returns a list of [fields] defined by the span.
356     ///
357     /// [fields]: tracing_core::field
fields(&self) -> &FieldSet358     pub fn fields(&self) -> &FieldSet {
359         self.data.metadata().fields()
360     }
361 
362     /// Returns a `SpanRef` describing this span's parent, or `None` if this
363     /// span is the root of its trace tree.
parent(&self) -> Option<Self>364     pub fn parent(&self) -> Option<Self> {
365         let id = self.data.parent()?;
366         let data = self.registry.span_data(id)?;
367 
368         #[cfg(all(feature = "registry", feature = "std"))]
369         {
370             // move these into mut bindings if the registry feature is enabled,
371             // since they may be mutated in the loop.
372             let mut data = data;
373             loop {
374                 // Is this parent enabled by our filter?
375                 if data.is_enabled_for(self.filter) {
376                     return Some(Self {
377                         registry: self.registry,
378                         filter: self.filter,
379                         data,
380                     });
381                 }
382 
383                 // It's not enabled. If the disabled span has a parent, try that!
384                 let id = data.parent()?;
385                 data = self.registry.span_data(id)?;
386             }
387         }
388 
389         #[cfg(not(all(feature = "registry", feature = "std")))]
390         Some(Self {
391             registry: self.registry,
392             data,
393         })
394     }
395 
396     /// Returns an iterator over all parents of this span, starting with this span,
397     /// ordered from leaf to root.
398     ///
399     /// The iterator will first return the span, then the span's immediate parent,
400     /// followed by that span's parent, and so on, until it reaches a root span.
401     ///
402     /// ```rust
403     /// use tracing::{span, Subscriber};
404     /// use tracing_subscriber::{
405     ///     layer::{Context, Layer},
406     ///     prelude::*,
407     ///     registry::LookupSpan,
408     /// };
409     ///
410     /// struct PrintingLayer;
411     /// impl<S> Layer<S> for PrintingLayer
412     /// where
413     ///     S: Subscriber + for<'lookup> LookupSpan<'lookup>,
414     /// {
415     ///     fn on_enter(&self, id: &span::Id, ctx: Context<S>) {
416     ///         let span = ctx.span(id).unwrap();
417     ///         let scope = span.scope().map(|span| span.name()).collect::<Vec<_>>();
418     ///         println!("Entering span: {:?}", scope);
419     ///     }
420     /// }
421     ///
422     /// tracing::subscriber::with_default(tracing_subscriber::registry().with(PrintingLayer), || {
423     ///     let _root = tracing::info_span!("root").entered();
424     ///     // Prints: Entering span: ["root"]
425     ///     let _child = tracing::info_span!("child").entered();
426     ///     // Prints: Entering span: ["child", "root"]
427     ///     let _leaf = tracing::info_span!("leaf").entered();
428     ///     // Prints: Entering span: ["leaf", "child", "root"]
429     /// });
430     /// ```
431     ///
432     /// If the opposite order (from the root to this span) is desired, calling [`Scope::from_root`] on
433     /// the returned iterator reverses the order.
434     ///
435     /// ```rust
436     /// # use tracing::{span, Subscriber};
437     /// # use tracing_subscriber::{
438     /// #     layer::{Context, Layer},
439     /// #     prelude::*,
440     /// #     registry::LookupSpan,
441     /// # };
442     /// # struct PrintingLayer;
443     /// impl<S> Layer<S> for PrintingLayer
444     /// where
445     ///     S: Subscriber + for<'lookup> LookupSpan<'lookup>,
446     /// {
447     ///     fn on_enter(&self, id: &span::Id, ctx: Context<S>) {
448     ///         let span = ctx.span(id).unwrap();
449     ///         let scope = span.scope().from_root().map(|span| span.name()).collect::<Vec<_>>();
450     ///         println!("Entering span: {:?}", scope);
451     ///     }
452     /// }
453     ///
454     /// tracing::subscriber::with_default(tracing_subscriber::registry().with(PrintingLayer), || {
455     ///     let _root = tracing::info_span!("root").entered();
456     ///     // Prints: Entering span: ["root"]
457     ///     let _child = tracing::info_span!("child").entered();
458     ///     // Prints: Entering span: ["root", "child"]
459     ///     let _leaf = tracing::info_span!("leaf").entered();
460     ///     // Prints: Entering span: ["root", "child", "leaf"]
461     /// });
462     /// ```
scope(&self) -> Scope<'a, R>463     pub fn scope(&self) -> Scope<'a, R> {
464         Scope {
465             registry: self.registry,
466             next: Some(self.id()),
467 
468             #[cfg(feature = "registry")]
469             filter: self.filter,
470         }
471     }
472 
473     /// Returns a reference to this span's `Extensions`.
474     ///
475     /// The extensions may be used by `Layer`s to store additional data
476     /// describing the span.
477     #[cfg(feature = "std")]
478     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
extensions(&self) -> Extensions<'_>479     pub fn extensions(&self) -> Extensions<'_> {
480         self.data.extensions()
481     }
482 
483     /// Returns a mutable reference to this span's `Extensions`.
484     ///
485     /// The extensions may be used by `Layer`s to store additional data
486     /// describing the span.
487     #[cfg(feature = "std")]
488     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
extensions_mut(&self) -> ExtensionsMut<'_>489     pub fn extensions_mut(&self) -> ExtensionsMut<'_> {
490         self.data.extensions_mut()
491     }
492 
493     #[cfg(all(feature = "registry", feature = "std"))]
try_with_filter(self, filter: FilterId) -> Option<Self>494     pub(crate) fn try_with_filter(self, filter: FilterId) -> Option<Self> {
495         if self.is_enabled_for(filter) {
496             return Some(self.with_filter(filter));
497         }
498 
499         None
500     }
501 
502     #[inline]
503     #[cfg(all(feature = "registry", feature = "std"))]
is_enabled_for(&self, filter: FilterId) -> bool504     pub(crate) fn is_enabled_for(&self, filter: FilterId) -> bool {
505         self.data.is_enabled_for(filter)
506     }
507 
508     #[inline]
509     #[cfg(all(feature = "registry", feature = "std"))]
with_filter(self, filter: FilterId) -> Self510     fn with_filter(self, filter: FilterId) -> Self {
511         Self { filter, ..self }
512     }
513 }
514 
515 #[cfg(all(test, feature = "registry", feature = "std"))]
516 mod tests {
517     use crate::{
518         layer::{Context, Layer},
519         prelude::*,
520         registry::LookupSpan,
521     };
522     use std::sync::{Arc, Mutex};
523     use tracing::{span, Subscriber};
524 
525     #[test]
spanref_scope_iteration_order()526     fn spanref_scope_iteration_order() {
527         let last_entered_scope = Arc::new(Mutex::new(Vec::new()));
528 
529         #[derive(Default)]
530         struct PrintingLayer {
531             last_entered_scope: Arc<Mutex<Vec<&'static str>>>,
532         }
533 
534         impl<S> Layer<S> for PrintingLayer
535         where
536             S: Subscriber + for<'lookup> LookupSpan<'lookup>,
537         {
538             fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
539                 let span = ctx.span(id).unwrap();
540                 let scope = span.scope().map(|span| span.name()).collect::<Vec<_>>();
541                 *self.last_entered_scope.lock().unwrap() = scope;
542             }
543         }
544 
545         let _guard = tracing::subscriber::set_default(crate::registry().with(PrintingLayer {
546             last_entered_scope: last_entered_scope.clone(),
547         }));
548 
549         let _root = tracing::info_span!("root").entered();
550         assert_eq!(&*last_entered_scope.lock().unwrap(), &["root"]);
551         let _child = tracing::info_span!("child").entered();
552         assert_eq!(&*last_entered_scope.lock().unwrap(), &["child", "root"]);
553         let _leaf = tracing::info_span!("leaf").entered();
554         assert_eq!(
555             &*last_entered_scope.lock().unwrap(),
556             &["leaf", "child", "root"]
557         );
558     }
559 
560     #[test]
spanref_scope_fromroot_iteration_order()561     fn spanref_scope_fromroot_iteration_order() {
562         let last_entered_scope = Arc::new(Mutex::new(Vec::new()));
563 
564         #[derive(Default)]
565         struct PrintingLayer {
566             last_entered_scope: Arc<Mutex<Vec<&'static str>>>,
567         }
568 
569         impl<S> Layer<S> for PrintingLayer
570         where
571             S: Subscriber + for<'lookup> LookupSpan<'lookup>,
572         {
573             fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
574                 let span = ctx.span(id).unwrap();
575                 let scope = span
576                     .scope()
577                     .from_root()
578                     .map(|span| span.name())
579                     .collect::<Vec<_>>();
580                 *self.last_entered_scope.lock().unwrap() = scope;
581             }
582         }
583 
584         let _guard = tracing::subscriber::set_default(crate::registry().with(PrintingLayer {
585             last_entered_scope: last_entered_scope.clone(),
586         }));
587 
588         let _root = tracing::info_span!("root").entered();
589         assert_eq!(&*last_entered_scope.lock().unwrap(), &["root"]);
590         let _child = tracing::info_span!("child").entered();
591         assert_eq!(&*last_entered_scope.lock().unwrap(), &["root", "child",]);
592         let _leaf = tracing::info_span!("leaf").entered();
593         assert_eq!(
594             &*last_entered_scope.lock().unwrap(),
595             &["root", "child", "leaf"]
596         );
597     }
598 }
599