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`][span data], and
204/// provides additional methods for querying the registry based on values from
205/// the span.
206///
207/// [span data]: SpanData
208/// [registry]: LookupSpan
209#[derive(Debug)]
210pub struct SpanRef<'a, R: LookupSpan<'a>> {
211 registry: &'a R,
212 data: R::Data,
213
214 #[cfg(feature = "registry")]
215 filter: FilterId,
216}
217
218/// An iterator over the parents of a span, ordered from leaf to root.
219///
220/// This is returned by the [`SpanRef::scope`] method.
221#[derive(Debug)]
222pub struct Scope<'a, R> {
223 registry: &'a R,
224 next: Option<Id>,
225
226 #[cfg(all(feature = "registry", feature = "std"))]
227 filter: FilterId,
228}
229
230feature! {
231 #![any(feature = "alloc", feature = "std")]
232
233 #[cfg(not(feature = "smallvec"))]
234 use alloc::vec::{self, Vec};
235
236 use core::{fmt,iter};
237
238 /// An iterator over the parents of a span, ordered from root to leaf.
239 ///
240 /// This is returned by the [`Scope::from_root`] method.
241 pub struct ScopeFromRoot<'a, R>
242 where
243 R: LookupSpan<'a>,
244 {
245 #[cfg(feature = "smallvec")]
246 spans: iter::Rev<smallvec::IntoIter<SpanRefVecArray<'a, R>>>,
247 #[cfg(not(feature = "smallvec"))]
248 spans: iter::Rev<vec::IntoIter<SpanRef<'a, R>>>,
249 }
250
251 #[cfg(feature = "smallvec")]
252 type SpanRefVecArray<'span, L> = [SpanRef<'span, L>; 16];
253
254 impl<'a, R> Scope<'a, R>
255 where
256 R: LookupSpan<'a>,
257 {
258 /// Flips the order of the iterator, so that it is ordered from root to leaf.
259 ///
260 /// The iterator will first return the root span, then that span's immediate child,
261 /// and so on until it finally returns the span that [`SpanRef::scope`] was called on.
262 ///
263 /// If any items were consumed from the [`Scope`] before calling this method then they
264 /// will *not* be returned from the [`ScopeFromRoot`].
265 ///
266 /// **Note**: this will allocate if there are many spans remaining, or if the
267 /// "smallvec" feature flag is not enabled.
268 #[allow(clippy::wrong_self_convention)]
269 pub fn from_root(self) -> ScopeFromRoot<'a, R> {
270 #[cfg(feature = "smallvec")]
271 type Buf<T> = smallvec::SmallVec<T>;
272 #[cfg(not(feature = "smallvec"))]
273 type Buf<T> = Vec<T>;
274 ScopeFromRoot {
275 spans: self.collect::<Buf<_>>().into_iter().rev(),
276 }
277 }
278 }
279
280 impl<'a, R> Iterator for ScopeFromRoot<'a, R>
281 where
282 R: LookupSpan<'a>,
283 {
284 type Item = SpanRef<'a, R>;
285
286 #[inline]
287 fn next(&mut self) -> Option<Self::Item> {
288 self.spans.next()
289 }
290
291 #[inline]
292 fn size_hint(&self) -> (usize, Option<usize>) {
293 self.spans.size_hint()
294 }
295 }
296
297 impl<'a, R> fmt::Debug for ScopeFromRoot<'a, R>
298 where
299 R: LookupSpan<'a>,
300 {
301 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
302 f.pad("ScopeFromRoot { .. }")
303 }
304 }
305}
306
307impl<'a, R> Iterator for Scope<'a, R>
308where
309 R: LookupSpan<'a>,
310{
311 type Item = SpanRef<'a, R>;
312
313 fn next(&mut self) -> Option<Self::Item> {
314 loop {
315 let curr = self.registry.span(self.next.as_ref()?)?;
316
317 #[cfg(all(feature = "registry", feature = "std"))]
318 let curr = curr.with_filter(self.filter);
319 self.next = curr.data.parent().cloned();
320
321 // If the `Scope` is filtered, check if the current span is enabled
322 // by the selected filter ID.
323
324 #[cfg(all(feature = "registry", feature = "std"))]
325 {
326 if !curr.is_enabled_for(self.filter) {
327 // The current span in the chain is disabled for this
328 // filter. Try its parent.
329 continue;
330 }
331 }
332
333 return Some(curr);
334 }
335 }
336}
337
338impl<'a, R> SpanRef<'a, R>
339where
340 R: LookupSpan<'a>,
341{
342 /// Returns this span's ID.
343 pub fn id(&self) -> Id {
344 self.data.id()
345 }
346
347 /// Returns a static reference to the span's metadata.
348 pub fn metadata(&self) -> &'static Metadata<'static> {
349 self.data.metadata()
350 }
351
352 /// Returns the span's name,
353 pub fn name(&self) -> &'static str {
354 self.data.metadata().name()
355 }
356
357 /// Returns a list of [fields] defined by the span.
358 ///
359 /// [fields]: tracing_core::field
360 pub fn fields(&self) -> &FieldSet {
361 self.data.metadata().fields()
362 }
363
364 /// Returns a `SpanRef` describing this span's parent, or `None` if this
365 /// span is the root of its trace tree.
366 pub fn parent(&self) -> Option<Self> {
367 let id = self.data.parent()?;
368 let data = self.registry.span_data(id)?;
369
370 #[cfg(all(feature = "registry", feature = "std"))]
371 {
372 // move these into mut bindings if the registry feature is enabled,
373 // since they may be mutated in the loop.
374 let mut data = data;
375 loop {
376 // Is this parent enabled by our filter?
377 if data.is_enabled_for(self.filter) {
378 return Some(Self {
379 registry: self.registry,
380 filter: self.filter,
381 data,
382 });
383 }
384
385 // It's not enabled. If the disabled span has a parent, try that!
386 let id = data.parent()?;
387 data = self.registry.span_data(id)?;
388 }
389 }
390
391 #[cfg(not(all(feature = "registry", feature = "std")))]
392 Some(Self {
393 registry: self.registry,
394 data,
395 })
396 }
397
398 /// Returns an iterator over all parents of this span, starting with this span,
399 /// ordered from leaf to root.
400 ///
401 /// The iterator will first return the span, then the span's immediate parent,
402 /// followed by that span's parent, and so on, until it reaches a root span.
403 ///
404 /// ```rust
405 /// use tracing::{span, Subscriber};
406 /// use tracing_subscriber::{
407 /// layer::{Context, Layer},
408 /// prelude::*,
409 /// registry::LookupSpan,
410 /// };
411 ///
412 /// struct PrintingLayer;
413 /// impl<S> Layer<S> for PrintingLayer
414 /// where
415 /// S: Subscriber + for<'lookup> LookupSpan<'lookup>,
416 /// {
417 /// fn on_enter(&self, id: &span::Id, ctx: Context<S>) {
418 /// let span = ctx.span(id).unwrap();
419 /// let scope = span.scope().map(|span| span.name()).collect::<Vec<_>>();
420 /// println!("Entering span: {:?}", scope);
421 /// }
422 /// }
423 ///
424 /// tracing::subscriber::with_default(tracing_subscriber::registry().with(PrintingLayer), || {
425 /// let _root = tracing::info_span!("root").entered();
426 /// // Prints: Entering span: ["root"]
427 /// let _child = tracing::info_span!("child").entered();
428 /// // Prints: Entering span: ["child", "root"]
429 /// let _leaf = tracing::info_span!("leaf").entered();
430 /// // Prints: Entering span: ["leaf", "child", "root"]
431 /// });
432 /// ```
433 ///
434 /// If the opposite order (from the root to this span) is desired, calling [`Scope::from_root`] on
435 /// the returned iterator reverses the order.
436 ///
437 /// ```rust
438 /// # use tracing::{span, Subscriber};
439 /// # use tracing_subscriber::{
440 /// # layer::{Context, Layer},
441 /// # prelude::*,
442 /// # registry::LookupSpan,
443 /// # };
444 /// # struct PrintingLayer;
445 /// impl<S> Layer<S> for PrintingLayer
446 /// where
447 /// S: Subscriber + for<'lookup> LookupSpan<'lookup>,
448 /// {
449 /// fn on_enter(&self, id: &span::Id, ctx: Context<S>) {
450 /// let span = ctx.span(id).unwrap();
451 /// let scope = span.scope().from_root().map(|span| span.name()).collect::<Vec<_>>();
452 /// println!("Entering span: {:?}", scope);
453 /// }
454 /// }
455 ///
456 /// tracing::subscriber::with_default(tracing_subscriber::registry().with(PrintingLayer), || {
457 /// let _root = tracing::info_span!("root").entered();
458 /// // Prints: Entering span: ["root"]
459 /// let _child = tracing::info_span!("child").entered();
460 /// // Prints: Entering span: ["root", "child"]
461 /// let _leaf = tracing::info_span!("leaf").entered();
462 /// // Prints: Entering span: ["root", "child", "leaf"]
463 /// });
464 /// ```
465 pub fn scope(&self) -> Scope<'a, R> {
466 Scope {
467 registry: self.registry,
468 next: Some(self.id()),
469
470 #[cfg(feature = "registry")]
471 filter: self.filter,
472 }
473 }
474
475 /// Returns a reference to this span's `Extensions`.
476 ///
477 /// The extensions may be used by `Layer`s to store additional data
478 /// describing the span.
479 #[cfg(feature = "std")]
480 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
481 pub fn extensions(&self) -> Extensions<'_> {
482 self.data.extensions()
483 }
484
485 /// Returns a mutable reference to this span's `Extensions`.
486 ///
487 /// The extensions may be used by `Layer`s to store additional data
488 /// describing the span.
489 #[cfg(feature = "std")]
490 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
491 pub fn extensions_mut(&self) -> ExtensionsMut<'_> {
492 self.data.extensions_mut()
493 }
494
495 #[cfg(all(feature = "registry", feature = "std"))]
496 pub(crate) fn try_with_filter(self, filter: FilterId) -> Option<Self> {
497 if self.is_enabled_for(filter) {
498 return Some(self.with_filter(filter));
499 }
500
501 None
502 }
503
504 #[inline]
505 #[cfg(all(feature = "registry", feature = "std"))]
506 pub(crate) fn is_enabled_for(&self, filter: FilterId) -> bool {
507 self.data.is_enabled_for(filter)
508 }
509
510 #[inline]
511 #[cfg(all(feature = "registry", feature = "std"))]
512 fn with_filter(self, filter: FilterId) -> Self {
513 Self { filter, ..self }
514 }
515}
516
517#[cfg(all(test, feature = "registry", feature = "std"))]
518mod tests {
519 use crate::{
520 layer::{Context, Layer},
521 prelude::*,
522 registry::LookupSpan,
523 };
524 use std::sync::{Arc, Mutex};
525 use tracing::{span, Subscriber};
526
527 #[test]
528 fn spanref_scope_iteration_order() {
529 let last_entered_scope = Arc::new(Mutex::new(Vec::new()));
530
531 #[derive(Default)]
532 struct PrintingLayer {
533 last_entered_scope: Arc<Mutex<Vec<&'static str>>>,
534 }
535
536 impl<S> Layer<S> for PrintingLayer
537 where
538 S: Subscriber + for<'lookup> LookupSpan<'lookup>,
539 {
540 fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
541 let span = ctx.span(id).unwrap();
542 let scope = span.scope().map(|span| span.name()).collect::<Vec<_>>();
543 *self.last_entered_scope.lock().unwrap() = scope;
544 }
545 }
546
547 let _guard = tracing::subscriber::set_default(crate::registry().with(PrintingLayer {
548 last_entered_scope: last_entered_scope.clone(),
549 }));
550
551 let _root = tracing::info_span!("root").entered();
552 assert_eq!(&*last_entered_scope.lock().unwrap(), &["root"]);
553 let _child = tracing::info_span!("child").entered();
554 assert_eq!(&*last_entered_scope.lock().unwrap(), &["child", "root"]);
555 let _leaf = tracing::info_span!("leaf").entered();
556 assert_eq!(
557 &*last_entered_scope.lock().unwrap(),
558 &["leaf", "child", "root"]
559 );
560 }
561
562 #[test]
563 fn spanref_scope_fromroot_iteration_order() {
564 let last_entered_scope = Arc::new(Mutex::new(Vec::new()));
565
566 #[derive(Default)]
567 struct PrintingLayer {
568 last_entered_scope: Arc<Mutex<Vec<&'static str>>>,
569 }
570
571 impl<S> Layer<S> for PrintingLayer
572 where
573 S: Subscriber + for<'lookup> LookupSpan<'lookup>,
574 {
575 fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
576 let span = ctx.span(id).unwrap();
577 let scope = span
578 .scope()
579 .from_root()
580 .map(|span| span.name())
581 .collect::<Vec<_>>();
582 *self.last_entered_scope.lock().unwrap() = scope;
583 }
584 }
585
586 let _guard = tracing::subscriber::set_default(crate::registry().with(PrintingLayer {
587 last_entered_scope: last_entered_scope.clone(),
588 }));
589
590 let _root = tracing::info_span!("root").entered();
591 assert_eq!(&*last_entered_scope.lock().unwrap(), &["root"]);
592 let _child = tracing::info_span!("child").entered();
593 assert_eq!(&*last_entered_scope.lock().unwrap(), &["root", "child",]);
594 let _leaf = tracing::info_span!("leaf").entered();
595 assert_eq!(
596 &*last_entered_scope.lock().unwrap(),
597 &["root", "child", "leaf"]
598 );
599 }
600}
601