tracing_subscriber/registry/
mod.rs

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()
61use tracing_core::{field::FieldSet, span::Id, Metadata};
62
63feature! {
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
71feature! {
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
92pub 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    ///
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()
118    fn span(&'a self, id: &Id) -> Option<SpanRef<'a, 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")))]
148    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.
157pub trait SpanData<'a> {
158    /// Returns this span's ID.
159    fn id(&self) -> Id;
160
161    /// Returns a reference to the span's `Metadata`.
162    fn metadata(&self) -> &'static Metadata<'static>;
163
164    /// Returns a reference to the 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")))]
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")))]
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")))]
195    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)]
208pub 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)]
220pub 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
228feature! {
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
305impl<'a, R> Iterator for Scope<'a, R>
306where
307    R: LookupSpan<'a>,
308{
309    type Item = SpanRef<'a, R>;
310
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
336impl<'a, R> SpanRef<'a, R>
337where
338    R: LookupSpan<'a>,
339{
340    /// Returns this span's ID.
341    pub fn id(&self) -> Id {
342        self.data.id()
343    }
344
345    /// Returns a static reference to the span's metadata.
346    pub fn metadata(&self) -> &'static Metadata<'static> {
347        self.data.metadata()
348    }
349
350    /// Returns the span's name,
351    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
358    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.
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    /// ```
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")))]
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")))]
489    pub fn extensions_mut(&self) -> ExtensionsMut<'_> {
490        self.data.extensions_mut()
491    }
492
493    #[cfg(all(feature = "registry", feature = "std"))]
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"))]
504    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"))]
510    fn with_filter(self, filter: FilterId) -> Self {
511        Self { filter, ..self }
512    }
513}
514
515#[cfg(all(test, feature = "registry", feature = "std"))]
516mod 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]
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]
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}