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