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<'_, 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}
599