1 //! Storage for span data shared by multiple [`Layer`]s.
3 //! ## Using the Span Registry
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.
14 //! For example, we might create a `Registry` and add multiple `Layer`s like so:
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 {}
23 //! # fn new() -> Self { Self {} }
26 //! # fn new() -> Self { Self {} }
29 //! let subscriber = Registry::default()
30 //! .with(FooLayer::new())
31 //! .with(BarLayer::new());
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:
39 //! use tracing_subscriber::{registry, Layer};
40 //! use tracing_core::Subscriber;
42 //! pub struct MyLayer {
46 //! impl<S> Layer<S> for MyLayer
48 //! S: Subscriber + for<'a> registry::LookupSpan<'a>,
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.
57 //! [`Layer`]: crate::layer::Layer
59 //! https://docs.rs/tracing-core/latest/tracing_core/subscriber/trait.Subscriber.html
60 //! [ctx]: crate::layer::Context
61 //! [lookup]: crate::layer::Context::span()
62 use tracing_core
::{field::FieldSet, span::Id, Metadata}
;
66 /// A module containing a type map of span extensions.
68 pub use extensions
::{Extensions, ExtensionsMut}
;
73 #![all(feature = "registry", feature = "std")]
78 pub use sharded
::Data
;
79 pub use sharded
::Registry
;
81 use crate::filter
::FilterId
;
84 /// Provides access to stored span data.
86 /// Subscribers which store span data and associate it with span IDs should
87 /// implement this trait; if they do, any [`Layer`]s wrapping them can look up
88 /// metadata via the [`Context`] type's [`span()`] method.
90 /// [`Layer`]: ../layer/trait.Layer.html
91 /// [`Context`]: ../layer/struct.Context.html
92 /// [`span()`]: ../layer/struct.Context.html#method.span
93 pub trait LookupSpan
<'a
> {
94 /// The type of span data stored in this registry.
95 type Data
: SpanData
<'a
>;
97 /// Returns the [`SpanData`] for a given `Id`, if it exists.
99 /// <pre class="ignore" style="white-space:normal;font:inherit;">
100 /// <strong>Note</strong>: users of the <code>LookupSpan</code> trait should
101 /// typically call the <a href="#method.span"><code>span</code></a> method rather
102 /// than this method. The <code>span</code> method is implemented by
103 /// <em>calling</em> <code>span_data</code>, but returns a reference which is
104 /// capable of performing more sophisiticated queries.
107 /// [`SpanData`]: trait.SpanData.html
108 fn span_data(&'a
self, id
: &Id
) -> Option
<Self::Data
>;
110 /// Returns a [`SpanRef`] for the span with the given `Id`, if it exists.
112 /// A `SpanRef` is similar to [`SpanData`], but it allows performing
113 /// additional lookups against the registryr that stores the wrapped data.
115 /// In general, _users_ of the `LookupSpan` trait should use this method
116 /// rather than the [`span_data`] method; while _implementors_ of this trait
117 /// should only implement `span_data`.
119 /// [`SpanRef`]: struct.SpanRef.html
120 /// [`SpanData`]: trait.SpanData.html
121 /// [`span_data`]: #method.span_data
122 fn span(&'a
self, id
: &Id
) -> Option
<SpanRef
<'_
, Self>>
126 let data
= self.span_data(id
)?
;
130 #[cfg(feature = "registry")]
131 filter
: FilterId
::none(),
135 /// Registers a [`Filter`] for [per-layer filtering] with this
138 /// The [`Filter`] can then use the returned [`FilterId`] to
139 /// [check if it previously enabled a span][check].
143 /// If this `Subscriber` does not support [per-layer filtering].
145 /// [`Filter`]: crate::layer::Filter
146 /// [per-layer filtering]: crate::layer::Layer#per-layer-filtering
147 /// [`Subscriber`]: tracing_core::Subscriber
148 /// [`FilterId`]: crate::filter::FilterId
149 /// [check]: SpanData::is_enabled_for
150 #[cfg(feature = "registry")]
151 #[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
152 fn register_filter(&mut self) -> FilterId
{
154 "{} does not currently support filters",
155 std
::any
::type_name
::<Self>()
160 /// A stored representation of data associated with a span.
161 pub trait SpanData
<'a
> {
162 /// Returns this span's ID.
165 /// Returns a reference to the span's `Metadata`.
166 fn metadata(&self) -> &'
static Metadata
<'
static>;
168 /// Returns a reference to the ID
169 fn parent(&self) -> Option
<&Id
>;
171 /// Returns a reference to this span's `Extensions`.
173 /// The extensions may be used by `Layer`s to store additional data
174 /// describing the span.
175 #[cfg(feature = "std")]
176 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
177 fn extensions(&self) -> Extensions
<'_
>;
179 /// Returns a mutable reference to this span's `Extensions`.
181 /// The extensions may be used by `Layer`s to store additional data
182 /// describing the span.
183 #[cfg(feature = "std")]
184 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
185 fn extensions_mut(&self) -> ExtensionsMut
<'_
>;
187 /// Returns `true` if this span is enabled for the [per-layer filter][plf]
188 /// corresponding to the provided [`FilterId`].
190 /// ## Default Implementation
192 /// By default, this method assumes that the [`LookupSpan`] implementation
193 /// does not support [per-layer filtering][plf], and always returns `true`.
195 /// [plf]: crate::layer::Layer#per-layer-filtering
196 /// [`FilterId`]: crate::filter::FilterId
197 #[cfg(feature = "registry")]
198 #[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
199 fn is_enabled_for(&self, filter
: FilterId
) -> bool
{
205 /// A reference to [span data] and the associated [registry].
207 /// This type implements all the same methods as [`SpanData`][span data], and
208 /// provides additional methods for querying the registry based on values from
211 /// [span data]: trait.SpanData.html
212 /// [registry]: trait.LookupSpan.html
214 pub struct SpanRef
<'a
, R
: LookupSpan
<'a
>> {
218 #[cfg(feature = "registry")]
222 /// An iterator over the parents of a span, ordered from leaf to root.
224 /// This is returned by the [`SpanRef::scope`] method.
226 pub struct Scope
<'a
, R
> {
230 #[cfg(all(feature = "registry", feature = "std"))]
235 #![any(feature = "alloc", feature = "std")]
237 #[cfg(not(feature = "smallvec"))]
238 use alloc
::vec
::{self, Vec}
;
240 use core
::{fmt,iter}
;
242 /// An iterator over the parents of a span, ordered from root to leaf.
244 /// This is returned by the [`Scope::from_root`] method.
245 pub struct ScopeFromRoot
<'a
, R
>
249 #[cfg(feature = "smallvec")]
250 spans
: iter
::Rev
<smallvec
::IntoIter
<SpanRefVecArray
<'a
, R
>>>,
251 #[cfg(not(feature = "smallvec"))]
252 spans
: iter
::Rev
<vec
::IntoIter
<SpanRef
<'a
, R
>>>,
255 #[cfg(feature = "smallvec")]
256 type SpanRefVecArray
<'span
, L
> = [SpanRef
<'span
, L
>; 16];
258 impl<'a
, R
> Scope
<'a
, R
>
262 /// Flips the order of the iterator, so that it is ordered from root to leaf.
264 /// The iterator will first return the root span, then that span's immediate child,
265 /// and so on until it finally returns the span that [`SpanRef::scope`] was called on.
267 /// If any items were consumed from the [`Scope`] before calling this method then they
268 /// will *not* be returned from the [`ScopeFromRoot`].
270 /// **Note**: this will allocate if there are many spans remaining, or if the
271 /// "smallvec" feature flag is not enabled.
272 #[allow(clippy::wrong_self_convention)]
273 pub fn from_root(self) -> ScopeFromRoot
<'a
, R
> {
274 #[cfg(feature = "smallvec")]
275 type Buf
<T
> = smallvec
::SmallVec
<T
>;
276 #[cfg(not(feature = "smallvec"))]
277 type Buf
<T
> = Vec
<T
>;
279 spans
: self.collect
::<Buf
<_
>>().into_iter().rev(),
284 impl<'a
, R
> Iterator
for ScopeFromRoot
<'a
, R
>
288 type Item
= SpanRef
<'a
, R
>;
291 fn next(&mut self) -> Option
<Self::Item
> {
296 fn size_hint(&self) -> (usize, Option
<usize>) {
297 self.spans
.size_hint()
301 impl<'a
, R
> fmt
::Debug
for ScopeFromRoot
<'a
, R
>
305 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
306 f
.pad("ScopeFromRoot { .. }")
311 impl<'a
, R
> Iterator
for Scope
<'a
, R
>
315 type Item
= SpanRef
<'a
, R
>;
317 fn next(&mut self) -> Option
<Self::Item
> {
319 let curr
= self.registry
.span(self.next
.as_ref()?
)?
;
321 #[cfg(all(feature = "registry", feature = "std"))]
322 let curr
= curr
.with_filter(self.filter
);
323 self.next
= curr
.data
.parent().cloned();
325 // If the `Scope` is filtered, check if the current span is enabled
326 // by the selected filter ID.
328 #[cfg(all(feature = "registry", feature = "std"))]
330 if !curr
.is_enabled_for(self.filter
) {
331 // The current span in the chain is disabled for this
332 // filter. Try its parent.
342 impl<'a
, R
> SpanRef
<'a
, R
>
346 /// Returns this span's ID.
347 pub fn id(&self) -> Id
{
351 /// Returns a static reference to the span's metadata.
352 pub fn metadata(&self) -> &'
static Metadata
<'
static> {
356 /// Returns the span's name,
357 pub fn name(&self) -> &'
static str {
358 self.data
.metadata().name()
361 /// Returns a list of [fields] defined by the span.
363 /// [fields]: https://docs.rs/tracing-core/latest/tracing_core/field/index.html
364 pub fn fields(&self) -> &FieldSet
{
365 self.data
.metadata().fields()
368 /// Returns a `SpanRef` describing this span's parent, or `None` if this
369 /// span is the root of its trace tree.
370 pub fn parent(&self) -> Option
<Self> {
371 let id
= self.data
.parent()?
;
372 let data
= self.registry
.span_data(id
)?
;
374 #[cfg(all(feature = "registry", feature = "std"))]
376 // move these into mut bindings if the registry feature is enabled,
377 // since they may be mutated in the loop.
380 // Is this parent enabled by our filter?
381 if data
.is_enabled_for(self.filter
) {
383 registry
: self.registry
,
389 // It's not enabled. If the disabled span has a parent, try that!
390 let id
= data
.parent()?
;
391 data
= self.registry
.span_data(id
)?
;
395 #[cfg(not(all(feature = "registry", feature = "std")))]
397 registry
: self.registry
,
402 /// Returns an iterator over all parents of this span, starting with this span,
403 /// ordered from leaf to root.
405 /// The iterator will first return the span, then the span's immediate parent,
406 /// followed by that span's parent, and so on, until it reaches a root span.
409 /// use tracing::{span, Subscriber};
410 /// use tracing_subscriber::{
411 /// layer::{Context, Layer},
413 /// registry::LookupSpan,
416 /// struct PrintingLayer;
417 /// impl<S> Layer<S> for PrintingLayer
419 /// S: Subscriber + for<'lookup> LookupSpan<'lookup>,
421 /// fn on_enter(&self, id: &span::Id, ctx: Context<S>) {
422 /// let span = ctx.span(id).unwrap();
423 /// let scope = span.scope().map(|span| span.name()).collect::<Vec<_>>();
424 /// println!("Entering span: {:?}", scope);
428 /// tracing::subscriber::with_default(tracing_subscriber::registry().with(PrintingLayer), || {
429 /// let _root = tracing::info_span!("root").entered();
430 /// // Prints: Entering span: ["root"]
431 /// let _child = tracing::info_span!("child").entered();
432 /// // Prints: Entering span: ["child", "root"]
433 /// let _leaf = tracing::info_span!("leaf").entered();
434 /// // Prints: Entering span: ["leaf", "child", "root"]
438 /// If the opposite order (from the root to this span) is desired, calling [`Scope::from_root`] on
439 /// the returned iterator reverses the order.
442 /// # use tracing::{span, Subscriber};
443 /// # use tracing_subscriber::{
444 /// # layer::{Context, Layer},
446 /// # registry::LookupSpan,
448 /// # struct PrintingLayer;
449 /// impl<S> Layer<S> for PrintingLayer
451 /// S: Subscriber + for<'lookup> LookupSpan<'lookup>,
453 /// fn on_enter(&self, id: &span::Id, ctx: Context<S>) {
454 /// let span = ctx.span(id).unwrap();
455 /// let scope = span.scope().from_root().map(|span| span.name()).collect::<Vec<_>>();
456 /// println!("Entering span: {:?}", scope);
460 /// tracing::subscriber::with_default(tracing_subscriber::registry().with(PrintingLayer), || {
461 /// let _root = tracing::info_span!("root").entered();
462 /// // Prints: Entering span: ["root"]
463 /// let _child = tracing::info_span!("child").entered();
464 /// // Prints: Entering span: ["root", "child"]
465 /// let _leaf = tracing::info_span!("leaf").entered();
466 /// // Prints: Entering span: ["root", "child", "leaf"]
469 pub fn scope(&self) -> Scope
<'a
, R
> {
471 registry
: self.registry
,
472 next
: Some(self.id()),
474 #[cfg(feature = "registry")]
479 /// Returns a reference to this span's `Extensions`.
481 /// The extensions may be used by `Layer`s to store additional data
482 /// describing the span.
483 #[cfg(feature = "std")]
484 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
485 pub fn extensions(&self) -> Extensions
<'_
> {
486 self.data
.extensions()
489 /// Returns a mutable reference to this span's `Extensions`.
491 /// The extensions may be used by `Layer`s to store additional data
492 /// describing the span.
493 #[cfg(feature = "std")]
494 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
495 pub fn extensions_mut(&self) -> ExtensionsMut
<'_
> {
496 self.data
.extensions_mut()
499 #[cfg(all(feature = "registry", feature = "std"))]
500 pub(crate) fn try_with_filter(self, filter
: FilterId
) -> Option
<Self> {
501 if self.is_enabled_for(filter
) {
502 return Some(self.with_filter(filter
));
509 #[cfg(all(feature = "registry", feature = "std"))]
510 pub(crate) fn is_enabled_for(&self, filter
: FilterId
) -> bool
{
511 self.data
.is_enabled_for(filter
)
515 #[cfg(all(feature = "registry", feature = "std"))]
516 fn with_filter(self, filter
: FilterId
) -> Self {
517 Self { filter, ..self }
521 #[cfg(all(test, feature = "registry", feature = "std"))]
524 layer
::{Context, Layer}
,
526 registry
::LookupSpan
,
528 use std
::sync
::{Arc, Mutex}
;
529 use tracing
::{span, Subscriber}
;
532 fn spanref_scope_iteration_order() {
533 let last_entered_scope
= Arc
::new(Mutex
::new(Vec
::new()));
536 struct PrintingLayer
{
537 last_entered_scope
: Arc
<Mutex
<Vec
<&'
static str>>>,
540 impl<S
> Layer
<S
> for PrintingLayer
542 S
: Subscriber
+ for<'lookup
> LookupSpan
<'lookup
>,
544 fn on_enter(&self, id
: &span
::Id
, ctx
: Context
<'_
, S
>) {
545 let span
= ctx
.span(id
).unwrap();
546 let scope
= span
.scope().map(|span
| span
.name()).collect
::<Vec
<_
>>();
547 *self.last_entered_scope
.lock().unwrap() = scope
;
551 let _guard
= tracing
::subscriber
::set_default(crate::registry().with(PrintingLayer
{
552 last_entered_scope
: last_entered_scope
.clone(),
555 let _root
= tracing
::info_span
!("root").entered();
556 assert_eq
!(&*last_entered_scope
.lock().unwrap(), &["root"]);
557 let _child
= tracing
::info_span
!("child").entered();
558 assert_eq
!(&*last_entered_scope
.lock().unwrap(), &["child", "root"]);
559 let _leaf
= tracing
::info_span
!("leaf").entered();
561 &*last_entered_scope
.lock().unwrap(),
562 &["leaf", "child", "root"]
567 fn spanref_scope_fromroot_iteration_order() {
568 let last_entered_scope
= Arc
::new(Mutex
::new(Vec
::new()));
571 struct PrintingLayer
{
572 last_entered_scope
: Arc
<Mutex
<Vec
<&'
static str>>>,
575 impl<S
> Layer
<S
> for PrintingLayer
577 S
: Subscriber
+ for<'lookup
> LookupSpan
<'lookup
>,
579 fn on_enter(&self, id
: &span
::Id
, ctx
: Context
<'_
, S
>) {
580 let span
= ctx
.span(id
).unwrap();
584 .map(|span
| span
.name())
585 .collect
::<Vec
<_
>>();
586 *self.last_entered_scope
.lock().unwrap() = scope
;
590 let _guard
= tracing
::subscriber
::set_default(crate::registry().with(PrintingLayer
{
591 last_entered_scope
: last_entered_scope
.clone(),
594 let _root
= tracing
::info_span
!("root").entered();
595 assert_eq
!(&*last_entered_scope
.lock().unwrap(), &["root"]);
596 let _child
= tracing
::info_span
!("child").entered();
597 assert_eq
!(&*last_entered_scope
.lock().unwrap(), &["root", "child",]);
598 let _leaf
= tracing
::info_span
!("leaf").entered();
600 &*last_entered_scope
.lock().unwrap(),
601 &["root", "child", "leaf"]