blob: faae7558bdac849e32456a01e52830db570d301f [file] [log] [blame]
//! Storage for span data shared by multiple [`Layer`]s.
//!
//! ## Using the Span Registry
//!
//! This module provides the [`Registry`] type, a [`Subscriber`] implementation
//! which tracks per-span data and exposes it to [`Layer`]s. When a `Registry`
//! is used as the base `Subscriber` of a `Layer` stack, the
//! [`layer::Context`][ctx] type will provide methods allowing `Layer`s to
//! [look up span data][lookup] stored in the registry. While [`Registry`] is a
//! reasonable default for storing spans and events, other stores that implement
//! [`LookupSpan`] and [`Subscriber`] themselves (with [`SpanData`] implemented
//! by the per-span data they store) can be used as a drop-in replacement.
//!
//! For example, we might create a `Registry` and add multiple `Layer`s like so:
//! ```rust
//! use tracing_subscriber::{registry::Registry, Layer, prelude::*};
//! # use tracing_core::Subscriber;
//! # pub struct FooLayer {}
//! # pub struct BarLayer {}
//! # impl<S: Subscriber> Layer<S> for FooLayer {}
//! # impl<S: Subscriber> Layer<S> for BarLayer {}
//! # impl FooLayer {
//! # fn new() -> Self { Self {} }
//! # }
//! # impl BarLayer {
//! # fn new() -> Self { Self {} }
//! # }
//!
//! let subscriber = Registry::default()
//! .with(FooLayer::new())
//! .with(BarLayer::new());
//! ```
//!
//! If a type implementing `Layer` depends on the functionality of a `Registry`
//! implementation, it should bound its `Subscriber` type parameter with the
//! [`LookupSpan`] trait, like so:
//!
//! ```rust
//! use tracing_subscriber::{registry, Layer};
//! use tracing_core::Subscriber;
//!
//! pub struct MyLayer {
//! // ...
//! }
//!
//! impl<S> Layer<S> for MyLayer
//! where
//! S: Subscriber + for<'a> registry::LookupSpan<'a>,
//! {
//! // ...
//! }
//! ```
//! When this bound is added, the `Layer` implementation will be guaranteed
//! access to the [`Context`][ctx] methods, such as [`Context::span`][lookup], that
//! require the root subscriber to be a registry.
//!
//! [`Layer`]: ../layer/trait.Layer.html
//! [`Subscriber`]:
//! https://docs.rs/tracing-core/latest/tracing_core/subscriber/trait.Subscriber.html
//! [`Registry`]: struct.Registry.html
//! [ctx]: ../layer/struct.Context.html
//! [lookup]: ../layer/struct.Context.html#method.span
//! [`LookupSpan`]: trait.LookupSpan.html
//! [`SpanData`]: trait.SpanData.html
use tracing_core::{field::FieldSet, span::Id, Metadata};
/// A module containing a type map of span extensions.
mod extensions;
#[cfg(feature = "registry")]
mod sharded;
#[cfg(feature = "registry")]
mod stack;
pub use extensions::{Extensions, ExtensionsMut};
#[cfg(feature = "registry")]
#[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
pub use sharded::Data;
#[cfg(feature = "registry")]
#[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
pub use sharded::Registry;
/// Provides access to stored span data.
///
/// Subscribers which store span data and associate it with span IDs should
/// implement this trait; if they do, any [`Layer`]s wrapping them can look up
/// metadata via the [`Context`] type's [`span()`] method.
///
/// [`Layer`]: ../layer/trait.Layer.html
/// [`Context`]: ../layer/struct.Context.html
/// [`span()`]: ../layer/struct.Context.html#method.metadata
pub trait LookupSpan<'a> {
/// The type of span data stored in this registry.
type Data: SpanData<'a>;
/// Returns the [`SpanData`] for a given `Id`, if it exists.
///
/// <div class="information">
/// <div class="tooltip ignore" style="">ⓘ<span class="tooltiptext">Note</span></div>
/// </div>
/// <div class="example-wrap" style="display:inline-block">
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: users of the <code>LookupSpan<code> trait should
/// typically call the <a href="#method.span"><code>span</code> method rather
/// than this method. The <code>span</code> method is implemented by
/// <em>calling</em> <code>span_data</code>, but returns a reference which is
/// capable of performing more sophisiticated queries.
/// </pre></div>
///
/// [`SpanData`]: trait.SpanData.html
fn span_data(&'a self, id: &Id) -> Option<Self::Data>;
/// Returns a [`SpanRef`] for the span with the given `Id`, if it exists.
///
/// A `SpanRef` is similar to [`SpanData`], but it allows performing
/// additional lookups against the registryr that stores the wrapped data.
///
/// In general, _users_ of the `LookupSpan` trait should use this method
/// rather than the [`span_data`] method; while _implementors_ of this trait
/// should only implement `span_data`.
///
/// [`SpanRef`]: struct.SpanRef.html
/// [`SpanData`]: trait.SpanData.html
/// [`span_data`]: #method.span_data
fn span(&'a self, id: &Id) -> Option<SpanRef<'_, Self>>
where
Self: Sized,
{
let data = self.span_data(&id)?;
Some(SpanRef {
registry: self,
data,
})
}
}
/// A stored representation of data associated with a span.
pub trait SpanData<'a> {
/// Returns this span's ID.
fn id(&self) -> Id;
/// Returns a reference to the span's `Metadata`.
fn metadata(&self) -> &'static Metadata<'static>;
/// Returns a reference to the ID
fn parent(&self) -> Option<&Id>;
/// Returns a reference to this span's `Extensions`.
///
/// The extensions may be used by `Layer`s to store additional data
/// describing the span.
fn extensions(&self) -> Extensions<'_>;
/// Returns a mutable reference to this span's `Extensions`.
///
/// The extensions may be used by `Layer`s to store additional data
/// describing the span.
fn extensions_mut(&self) -> ExtensionsMut<'_>;
}
/// A reference to [span data] and the associated [registry].
///
/// This type implements all the same methods as [`SpanData`][span data], and
/// provides additional methods for querying the registry based on values from
/// the span.
///
/// [span data]: trait.SpanData.html
/// [registry]: trait.LookupSpan.html
#[derive(Debug)]
pub struct SpanRef<'a, R: LookupSpan<'a>> {
registry: &'a R,
data: R::Data,
}
/// An iterator over the parents of a span.
///
/// This is returned by the [`SpanRef::parents`] method.
///
/// [`SpanRef::parents`]: struct.SpanRef.html#method.parents
#[derive(Debug)]
pub struct Parents<'a, R> {
registry: &'a R,
next: Option<Id>,
}
/// An iterator over a span's parents, starting with the root of the trace
/// tree.
///
/// For additonal details, see [`SpanRef::from_root`].
///
/// [`Span::from_root`]: struct.SpanRef.html#method.from_root
pub struct FromRoot<'a, R: LookupSpan<'a>> {
#[cfg(feature = "smallvec")]
inner: std::iter::Rev<smallvec::IntoIter<SpanRefVecArray<'a, R>>>,
#[cfg(not(feature = "smallvec"))]
inner: std::iter::Rev<std::vec::IntoIter<SpanRef<'a, R>>>,
}
#[cfg(feature = "smallvec")]
type SpanRefVecArray<'span, L> = [SpanRef<'span, L>; 16];
impl<'a, R> SpanRef<'a, R>
where
R: LookupSpan<'a>,
{
/// Returns this span's ID.
pub fn id(&self) -> Id {
self.data.id()
}
/// Returns a static reference to the span's metadata.
pub fn metadata(&self) -> &'static Metadata<'static> {
self.data.metadata()
}
/// Returns the span's name,
pub fn name(&self) -> &'static str {
self.data.metadata().name()
}
/// Returns a list of [fields] defined by the span.
///
/// [fields]: https://docs.rs/tracing-core/latest/tracing_core/field/index.html
pub fn fields(&self) -> &FieldSet {
self.data.metadata().fields()
}
/// Returns the ID of this span's parent, or `None` if this span is the root
/// of its trace tree.
pub fn parent_id(&self) -> Option<&Id> {
self.data.parent()
}
/// Returns a `SpanRef` describing this span's parent, or `None` if this
/// span is the root of its trace tree.
pub fn parent(&self) -> Option<Self> {
let id = self.data.parent()?;
let data = self.registry.span_data(id)?;
Some(Self {
registry: self.registry,
data,
})
}
/// Returns an iterator over all parents of this span, starting with the
/// immediate parent.
///
/// The iterator will first return the span's immediate parent, followed by
/// that span's parent, followed by _that_ span's parent, and so on, until a
/// it reaches a root span.
pub fn parents(&self) -> Parents<'a, R> {
Parents {
registry: self.registry,
next: self.parent().map(|parent| parent.id()),
}
}
/// Returns an iterator over all parents of this span, starting with the
/// root of the trace tree.
///
/// The iterator will return the root of the trace tree, followed by the
/// next span, and then the next, until this span's immediate parent is
/// returned.
///
/// **Note**: if the "smallvec" feature flag is not enabled, this may
/// allocate.
pub fn from_root(&self) -> FromRoot<'a, R> {
#[cfg(feature = "smallvec")]
type SpanRefVec<'span, L> = smallvec::SmallVec<SpanRefVecArray<'span, L>>;
#[cfg(not(feature = "smallvec"))]
type SpanRefVec<'span, L> = Vec<SpanRef<'span, L>>;
// an alternative way to handle this would be to the recursive approach that
// `fmt` uses that _does not_ entail any allocation in this fmt'ing
// spans path.
let parents = self.parents().collect::<SpanRefVec<'a, _>>();
let inner = parents.into_iter().rev();
FromRoot { inner }
}
/// Returns a reference to this span's `Extensions`.
///
/// The extensions may be used by `Layer`s to store additional data
/// describing the span.
pub fn extensions(&self) -> Extensions<'_> {
self.data.extensions()
}
/// Returns a mutable reference to this span's `Extensions`.
///
/// The extensions may be used by `Layer`s to store additional data
/// describing the span.
pub fn extensions_mut(&self) -> ExtensionsMut<'_> {
self.data.extensions_mut()
}
}
impl<'a, R> Iterator for Parents<'a, R>
where
R: LookupSpan<'a>,
{
type Item = SpanRef<'a, R>;
fn next(&mut self) -> Option<Self::Item> {
let id = self.next.take()?;
let span = self.registry.span(&id)?;
self.next = span.parent().map(|parent| parent.id());
Some(span)
}
}
// === impl FromRoot ===
impl<'span, R> Iterator for FromRoot<'span, R>
where
R: LookupSpan<'span>,
{
type Item = SpanRef<'span, R>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl<'span, R> std::fmt::Debug for FromRoot<'span, R>
where
R: LookupSpan<'span>,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.pad("FromRoot { .. }")
}
}