Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

View File

@@ -0,0 +1,274 @@
// taken from https://github.com/hyperium/http/blob/master/src/extensions.rs.
use crate::sync::{RwLockReadGuard, RwLockWriteGuard};
use std::{
any::{Any, TypeId},
collections::HashMap,
fmt,
hash::{BuildHasherDefault, Hasher},
};
#[allow(warnings)]
type AnyMap = HashMap<TypeId, Box<dyn Any + Send + Sync>, BuildHasherDefault<IdHasher>>;
/// With TypeIds as keys, there's no need to hash them. They are already hashes
/// themselves, coming from the compiler. The IdHasher holds the u64 of
/// the TypeId, and then returns it, instead of doing any bit fiddling.
#[derive(Default, Debug)]
struct IdHasher(u64);
impl Hasher for IdHasher {
fn write(&mut self, _: &[u8]) {
unreachable!("TypeId calls write_u64");
}
#[inline]
fn write_u64(&mut self, id: u64) {
self.0 = id;
}
#[inline]
fn finish(&self) -> u64 {
self.0
}
}
/// An immutable, read-only reference to a Span's extensions.
#[derive(Debug)]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub struct Extensions<'a> {
inner: RwLockReadGuard<'a, ExtensionsInner>,
}
impl<'a> Extensions<'a> {
#[cfg(feature = "registry")]
pub(crate) fn new(inner: RwLockReadGuard<'a, ExtensionsInner>) -> Self {
Self { inner }
}
/// Immutably borrows a type previously inserted into this `Extensions`.
pub fn get<T: 'static>(&self) -> Option<&T> {
self.inner.get::<T>()
}
}
/// An mutable reference to a Span's extensions.
#[derive(Debug)]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub struct ExtensionsMut<'a> {
inner: RwLockWriteGuard<'a, ExtensionsInner>,
}
impl<'a> ExtensionsMut<'a> {
#[cfg(feature = "registry")]
pub(crate) fn new(inner: RwLockWriteGuard<'a, ExtensionsInner>) -> Self {
Self { inner }
}
/// Insert a type into this `Extensions`.
///
/// Note that extensions are _not_
/// `Layer`-specific—they are _span_-specific. This means that
/// other layers can access and mutate extensions that
/// a different Layer recorded. For example, an application might
/// have a layer that records execution timings, alongside a layer
/// that reports spans and events to a distributed
/// tracing system that requires timestamps for spans.
/// Ideally, if one layer records a timestamp _x_, the other layer
/// should be able to reuse timestamp _x_.
///
/// Therefore, extensions should generally be newtypes, rather than common
/// types like [`String`](std::string::String), to avoid accidental
/// cross-`Layer` clobbering.
///
/// ## Panics
///
/// If `T` is already present in `Extensions`, then this method will panic.
pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) {
assert!(self.replace(val).is_none())
}
/// Replaces an existing `T` into this extensions.
///
/// If `T` is not present, `Option::None` will be returned.
pub fn replace<T: Send + Sync + 'static>(&mut self, val: T) -> Option<T> {
self.inner.insert(val)
}
/// Get a mutable reference to a type previously inserted on this `ExtensionsMut`.
pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
self.inner.get_mut::<T>()
}
/// Remove a type from this `Extensions`.
///
/// If a extension of this type existed, it will be returned.
pub fn remove<T: Send + Sync + 'static>(&mut self) -> Option<T> {
self.inner.remove::<T>()
}
}
/// A type map of span extensions.
///
/// [ExtensionsInner] is used by `SpanData` to store and
/// span-specific data. A given `Layer` can read and write
/// data that it is interested in recording and emitting.
#[derive(Default)]
pub(crate) struct ExtensionsInner {
map: AnyMap,
}
impl ExtensionsInner {
/// Create an empty `Extensions`.
#[cfg(any(test, feature = "registry"))]
#[inline]
#[cfg(any(test, feature = "registry"))]
pub(crate) fn new() -> ExtensionsInner {
ExtensionsInner {
map: AnyMap::default(),
}
}
/// Insert a type into this `Extensions`.
///
/// If a extension of this type already existed, it will
/// be returned.
pub(crate) fn insert<T: Send + Sync + 'static>(&mut self, val: T) -> Option<T> {
self.map
.insert(TypeId::of::<T>(), Box::new(val))
.and_then(|boxed| {
#[allow(warnings)]
{
(boxed as Box<Any + 'static>)
.downcast()
.ok()
.map(|boxed| *boxed)
}
})
}
/// Get a reference to a type previously inserted on this `Extensions`.
pub(crate) fn get<T: 'static>(&self) -> Option<&T> {
self.map
.get(&TypeId::of::<T>())
.and_then(|boxed| (&**boxed as &(dyn Any + 'static)).downcast_ref())
}
/// Get a mutable reference to a type previously inserted on this `Extensions`.
pub(crate) fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
self.map
.get_mut(&TypeId::of::<T>())
.and_then(|boxed| (&mut **boxed as &mut (dyn Any + 'static)).downcast_mut())
}
/// Remove a type from this `Extensions`.
///
/// If a extension of this type existed, it will be returned.
pub(crate) fn remove<T: Send + Sync + 'static>(&mut self) -> Option<T> {
self.map.remove(&TypeId::of::<T>()).and_then(|boxed| {
#[allow(warnings)]
{
(boxed as Box<Any + 'static>)
.downcast()
.ok()
.map(|boxed| *boxed)
}
})
}
/// Clear the `ExtensionsInner` in-place, dropping any elements in the map but
/// retaining allocated capacity.
///
/// This permits the hash map allocation to be pooled by the registry so
/// that future spans will not need to allocate new hashmaps.
#[cfg(any(test, feature = "registry"))]
pub(crate) fn clear(&mut self) {
self.map.clear();
}
}
impl fmt::Debug for ExtensionsInner {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Extensions")
.field("len", &self.map.len())
.field("capacity", &self.map.capacity())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, PartialEq)]
struct MyType(i32);
#[test]
fn test_extensions() {
let mut extensions = ExtensionsInner::new();
extensions.insert(5i32);
extensions.insert(MyType(10));
assert_eq!(extensions.get(), Some(&5i32));
assert_eq!(extensions.get_mut(), Some(&mut 5i32));
assert_eq!(extensions.remove::<i32>(), Some(5i32));
assert!(extensions.get::<i32>().is_none());
assert_eq!(extensions.get::<bool>(), None);
assert_eq!(extensions.get(), Some(&MyType(10)));
}
#[test]
fn clear_retains_capacity() {
let mut extensions = ExtensionsInner::new();
extensions.insert(5i32);
extensions.insert(MyType(10));
extensions.insert(true);
assert_eq!(extensions.map.len(), 3);
let prev_capacity = extensions.map.capacity();
extensions.clear();
assert_eq!(
extensions.map.len(),
0,
"after clear(), extensions map should have length 0"
);
assert_eq!(
extensions.map.capacity(),
prev_capacity,
"after clear(), extensions map should retain prior capacity"
);
}
#[test]
fn clear_drops_elements() {
use std::sync::Arc;
struct DropMePlease(Arc<()>);
struct DropMeTooPlease(Arc<()>);
let mut extensions = ExtensionsInner::new();
let val1 = DropMePlease(Arc::new(()));
let val2 = DropMeTooPlease(Arc::new(()));
let val1_dropped = Arc::downgrade(&val1.0);
let val2_dropped = Arc::downgrade(&val2.0);
extensions.insert(val1);
extensions.insert(val2);
assert!(val1_dropped.upgrade().is_some());
assert!(val2_dropped.upgrade().is_some());
extensions.clear();
assert!(
val1_dropped.upgrade().is_none(),
"after clear(), val1 should be dropped"
);
assert!(
val2_dropped.upgrade().is_none(),
"after clear(), val2 should be dropped"
);
}
}

View File

@@ -0,0 +1,598 @@
//! 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`]: crate::layer::Layer
//! [`Subscriber`]: tracing_core::Subscriber
//! [ctx]: crate::layer::Context
//! [lookup]: crate::layer::Context::span()
use tracing_core::{field::FieldSet, span::Id, Metadata};
feature! {
#![feature = "std"]
/// A module containing a type map of span extensions.
mod extensions;
pub use extensions::{Extensions, ExtensionsMut};
}
feature! {
#![all(feature = "registry", feature = "std")]
mod sharded;
mod stack;
pub use sharded::Data;
pub use sharded::Registry;
use crate::filter::FilterId;
}
/// 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`]: super::layer::Layer
/// [`Context`]: super::layer::Context
/// [`span()`]: super::layer::Context::span
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.
///
/// <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></a> 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>
///
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`.
///
/// [`span_data`]: LookupSpan::span_data()
fn span(&'a self, id: &Id) -> Option<SpanRef<'a, Self>>
where
Self: Sized,
{
let data = self.span_data(id)?;
Some(SpanRef {
registry: self,
data,
#[cfg(feature = "registry")]
filter: FilterId::none(),
})
}
/// Registers a [`Filter`] for [per-layer filtering] with this
/// [`Subscriber`].
///
/// The [`Filter`] can then use the returned [`FilterId`] to
/// [check if it previously enabled a span][check].
///
/// # Panics
///
/// If this `Subscriber` does not support [per-layer filtering].
///
/// [`Filter`]: crate::layer::Filter
/// [per-layer filtering]: crate::layer::Layer#per-layer-filtering
/// [`Subscriber`]: tracing_core::Subscriber
/// [`FilterId`]: crate::filter::FilterId
/// [check]: SpanData::is_enabled_for
#[cfg(feature = "registry")]
#[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
fn register_filter(&mut self) -> FilterId {
panic!(
"{} does not currently support filters",
std::any::type_name::<Self>()
)
}
}
/// 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.
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
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.
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
fn extensions_mut(&self) -> ExtensionsMut<'_>;
/// Returns `true` if this span is enabled for the [per-layer filter][plf]
/// corresponding to the provided [`FilterId`].
///
/// ## Default Implementation
///
/// By default, this method assumes that the [`LookupSpan`] implementation
/// does not support [per-layer filtering][plf], and always returns `true`.
///
/// [plf]: crate::layer::Layer#per-layer-filtering
/// [`FilterId`]: crate::filter::FilterId
#[cfg(feature = "registry")]
#[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
fn is_enabled_for(&self, filter: FilterId) -> bool {
let _ = filter;
true
}
}
/// A reference to [span data] and the associated [registry].
///
/// This type implements all the same methods as [`SpanData`], and provides
/// additional methods for querying the registry based on values from the span.
///
/// [registry]: LookupSpan
#[derive(Debug)]
pub struct SpanRef<'a, R: LookupSpan<'a>> {
registry: &'a R,
data: R::Data,
#[cfg(feature = "registry")]
filter: FilterId,
}
/// An iterator over the parents of a span, ordered from leaf to root.
///
/// This is returned by the [`SpanRef::scope`] method.
#[derive(Debug)]
pub struct Scope<'a, R> {
registry: &'a R,
next: Option<Id>,
#[cfg(all(feature = "registry", feature = "std"))]
filter: FilterId,
}
feature! {
#![any(feature = "alloc", feature = "std")]
#[cfg(not(feature = "smallvec"))]
use alloc::vec::{self, Vec};
use core::{fmt,iter};
/// An iterator over the parents of a span, ordered from root to leaf.
///
/// This is returned by the [`Scope::from_root`] method.
pub struct ScopeFromRoot<'a, R>
where
R: LookupSpan<'a>,
{
#[cfg(feature = "smallvec")]
spans: iter::Rev<smallvec::IntoIter<SpanRefVecArray<'a, R>>>,
#[cfg(not(feature = "smallvec"))]
spans: iter::Rev<vec::IntoIter<SpanRef<'a, R>>>,
}
#[cfg(feature = "smallvec")]
type SpanRefVecArray<'span, L> = [SpanRef<'span, L>; 16];
impl<'a, R> Scope<'a, R>
where
R: LookupSpan<'a>,
{
/// Flips the order of the iterator, so that it is ordered from root to leaf.
///
/// The iterator will first return the root span, then that span's immediate child,
/// and so on until it finally returns the span that [`SpanRef::scope`] was called on.
///
/// If any items were consumed from the [`Scope`] before calling this method then they
/// will *not* be returned from the [`ScopeFromRoot`].
///
/// **Note**: this will allocate if there are many spans remaining, or if the
/// "smallvec" feature flag is not enabled.
#[allow(clippy::wrong_self_convention)]
pub fn from_root(self) -> ScopeFromRoot<'a, R> {
#[cfg(feature = "smallvec")]
type Buf<T> = smallvec::SmallVec<T>;
#[cfg(not(feature = "smallvec"))]
type Buf<T> = Vec<T>;
ScopeFromRoot {
spans: self.collect::<Buf<_>>().into_iter().rev(),
}
}
}
impl<'a, R> Iterator for ScopeFromRoot<'a, R>
where
R: LookupSpan<'a>,
{
type Item = SpanRef<'a, R>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.spans.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.spans.size_hint()
}
}
impl<'a, R> fmt::Debug for ScopeFromRoot<'a, R>
where
R: LookupSpan<'a>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad("ScopeFromRoot { .. }")
}
}
}
impl<'a, R> Iterator for Scope<'a, R>
where
R: LookupSpan<'a>,
{
type Item = SpanRef<'a, R>;
fn next(&mut self) -> Option<Self::Item> {
loop {
let curr = self.registry.span(self.next.as_ref()?)?;
#[cfg(all(feature = "registry", feature = "std"))]
let curr = curr.with_filter(self.filter);
self.next = curr.data.parent().cloned();
// If the `Scope` is filtered, check if the current span is enabled
// by the selected filter ID.
#[cfg(all(feature = "registry", feature = "std"))]
{
if !curr.is_enabled_for(self.filter) {
// The current span in the chain is disabled for this
// filter. Try its parent.
continue;
}
}
return Some(curr);
}
}
}
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]: tracing_core::field
pub fn fields(&self) -> &FieldSet {
self.data.metadata().fields()
}
/// 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)?;
#[cfg(all(feature = "registry", feature = "std"))]
{
// move these into mut bindings if the registry feature is enabled,
// since they may be mutated in the loop.
let mut data = data;
loop {
// Is this parent enabled by our filter?
if data.is_enabled_for(self.filter) {
return Some(Self {
registry: self.registry,
filter: self.filter,
data,
});
}
// It's not enabled. If the disabled span has a parent, try that!
let id = data.parent()?;
data = self.registry.span_data(id)?;
}
}
#[cfg(not(all(feature = "registry", feature = "std")))]
Some(Self {
registry: self.registry,
data,
})
}
/// Returns an iterator over all parents of this span, starting with this span,
/// ordered from leaf to root.
///
/// The iterator will first return the span, then the span's immediate parent,
/// followed by that span's parent, and so on, until it reaches a root span.
///
/// ```rust
/// use tracing::{span, Subscriber};
/// use tracing_subscriber::{
/// layer::{Context, Layer},
/// prelude::*,
/// registry::LookupSpan,
/// };
///
/// struct PrintingLayer;
/// impl<S> Layer<S> for PrintingLayer
/// where
/// S: Subscriber + for<'lookup> LookupSpan<'lookup>,
/// {
/// fn on_enter(&self, id: &span::Id, ctx: Context<S>) {
/// let span = ctx.span(id).unwrap();
/// let scope = span.scope().map(|span| span.name()).collect::<Vec<_>>();
/// println!("Entering span: {:?}", scope);
/// }
/// }
///
/// tracing::subscriber::with_default(tracing_subscriber::registry().with(PrintingLayer), || {
/// let _root = tracing::info_span!("root").entered();
/// // Prints: Entering span: ["root"]
/// let _child = tracing::info_span!("child").entered();
/// // Prints: Entering span: ["child", "root"]
/// let _leaf = tracing::info_span!("leaf").entered();
/// // Prints: Entering span: ["leaf", "child", "root"]
/// });
/// ```
///
/// If the opposite order (from the root to this span) is desired, calling [`Scope::from_root`] on
/// the returned iterator reverses the order.
///
/// ```rust
/// # use tracing::{span, Subscriber};
/// # use tracing_subscriber::{
/// # layer::{Context, Layer},
/// # prelude::*,
/// # registry::LookupSpan,
/// # };
/// # struct PrintingLayer;
/// impl<S> Layer<S> for PrintingLayer
/// where
/// S: Subscriber + for<'lookup> LookupSpan<'lookup>,
/// {
/// fn on_enter(&self, id: &span::Id, ctx: Context<S>) {
/// let span = ctx.span(id).unwrap();
/// let scope = span.scope().from_root().map(|span| span.name()).collect::<Vec<_>>();
/// println!("Entering span: {:?}", scope);
/// }
/// }
///
/// tracing::subscriber::with_default(tracing_subscriber::registry().with(PrintingLayer), || {
/// let _root = tracing::info_span!("root").entered();
/// // Prints: Entering span: ["root"]
/// let _child = tracing::info_span!("child").entered();
/// // Prints: Entering span: ["root", "child"]
/// let _leaf = tracing::info_span!("leaf").entered();
/// // Prints: Entering span: ["root", "child", "leaf"]
/// });
/// ```
pub fn scope(&self) -> Scope<'a, R> {
Scope {
registry: self.registry,
next: Some(self.id()),
#[cfg(feature = "registry")]
filter: self.filter,
}
}
/// Returns a reference to this span's `Extensions`.
///
/// The extensions may be used by `Layer`s to store additional data
/// describing the span.
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
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.
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn extensions_mut(&self) -> ExtensionsMut<'_> {
self.data.extensions_mut()
}
#[cfg(all(feature = "registry", feature = "std"))]
pub(crate) fn try_with_filter(self, filter: FilterId) -> Option<Self> {
if self.is_enabled_for(filter) {
return Some(self.with_filter(filter));
}
None
}
#[inline]
#[cfg(all(feature = "registry", feature = "std"))]
pub(crate) fn is_enabled_for(&self, filter: FilterId) -> bool {
self.data.is_enabled_for(filter)
}
#[inline]
#[cfg(all(feature = "registry", feature = "std"))]
fn with_filter(self, filter: FilterId) -> Self {
Self { filter, ..self }
}
}
#[cfg(all(test, feature = "registry", feature = "std"))]
mod tests {
use crate::{
layer::{Context, Layer},
prelude::*,
registry::LookupSpan,
};
use std::sync::{Arc, Mutex};
use tracing::{span, Subscriber};
#[test]
fn spanref_scope_iteration_order() {
let last_entered_scope = Arc::new(Mutex::new(Vec::new()));
#[derive(Default)]
struct PrintingLayer {
last_entered_scope: Arc<Mutex<Vec<&'static str>>>,
}
impl<S> Layer<S> for PrintingLayer
where
S: Subscriber + for<'lookup> LookupSpan<'lookup>,
{
fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
let span = ctx.span(id).unwrap();
let scope = span.scope().map(|span| span.name()).collect::<Vec<_>>();
*self.last_entered_scope.lock().unwrap() = scope;
}
}
let _guard = tracing::subscriber::set_default(crate::registry().with(PrintingLayer {
last_entered_scope: last_entered_scope.clone(),
}));
let _root = tracing::info_span!("root").entered();
assert_eq!(&*last_entered_scope.lock().unwrap(), &["root"]);
let _child = tracing::info_span!("child").entered();
assert_eq!(&*last_entered_scope.lock().unwrap(), &["child", "root"]);
let _leaf = tracing::info_span!("leaf").entered();
assert_eq!(
&*last_entered_scope.lock().unwrap(),
&["leaf", "child", "root"]
);
}
#[test]
fn spanref_scope_fromroot_iteration_order() {
let last_entered_scope = Arc::new(Mutex::new(Vec::new()));
#[derive(Default)]
struct PrintingLayer {
last_entered_scope: Arc<Mutex<Vec<&'static str>>>,
}
impl<S> Layer<S> for PrintingLayer
where
S: Subscriber + for<'lookup> LookupSpan<'lookup>,
{
fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
let span = ctx.span(id).unwrap();
let scope = span
.scope()
.from_root()
.map(|span| span.name())
.collect::<Vec<_>>();
*self.last_entered_scope.lock().unwrap() = scope;
}
}
let _guard = tracing::subscriber::set_default(crate::registry().with(PrintingLayer {
last_entered_scope: last_entered_scope.clone(),
}));
let _root = tracing::info_span!("root").entered();
assert_eq!(&*last_entered_scope.lock().unwrap(), &["root"]);
let _child = tracing::info_span!("child").entered();
assert_eq!(&*last_entered_scope.lock().unwrap(), &["root", "child",]);
let _leaf = tracing::info_span!("leaf").entered();
assert_eq!(
&*last_entered_scope.lock().unwrap(),
&["root", "child", "leaf"]
);
}
}

View File

@@ -0,0 +1,905 @@
use sharded_slab::{pool::Ref, Clear, Pool};
use thread_local::ThreadLocal;
use super::stack::SpanStack;
use crate::{
filter::{FilterId, FilterMap, FilterState},
registry::{
extensions::{Extensions, ExtensionsInner, ExtensionsMut},
LookupSpan, SpanData,
},
sync::RwLock,
};
use std::{
cell::{self, Cell, RefCell},
sync::atomic::{fence, AtomicUsize, Ordering},
};
use tracing_core::{
dispatcher::{self, Dispatch},
span::{self, Current, Id},
Event, Interest, Metadata, Subscriber,
};
/// A shared, reusable store for spans.
///
/// A `Registry` is a [`Subscriber`] around which multiple [`Layer`]s
/// implementing various behaviors may be [added]. Unlike other types
/// implementing `Subscriber`, `Registry` does not actually record traces itself:
/// instead, it collects and stores span data that is exposed to any [`Layer`]s
/// wrapping it through implementations of the [`LookupSpan`] trait.
/// The `Registry` is responsible for storing span metadata, recording
/// relationships between spans, and tracking which spans are active and which
/// are closed. In addition, it provides a mechanism for [`Layer`]s to store
/// user-defined per-span data, called [extensions], in the registry. This
/// allows [`Layer`]-specific data to benefit from the `Registry`'s
/// high-performance concurrent storage.
///
/// This registry is implemented using a [lock-free sharded slab][slab], and is
/// highly optimized for concurrent access.
///
/// # Span ID Generation
///
/// Span IDs are not globally unique, but the registry ensures that
/// no two currently active spans have the same ID within a process.
///
/// One of the primary responsibilities of the registry is to generate [span
/// IDs]. Therefore, it's important for other code that interacts with the
/// registry, such as [`Layer`]s, to understand the guarantees of the
/// span IDs that are generated.
///
/// The registry's span IDs are guaranteed to be unique **at a given point
/// in time**. This means that an active span will never be assigned the
/// same ID as another **currently active** span. However, the registry
/// **will** eventually reuse the IDs of [closed] spans, although an ID
/// will never be reassigned immediately after a span has closed.
///
/// Spans are not [considered closed] by the `Registry` until *every*
/// [`Span`] reference with that ID has been dropped.
///
/// Thus: span IDs generated by the registry should be considered unique
/// only at a given point in time, and only relative to other spans
/// generated by the same process. Two spans with the same ID will not exist
/// in the same process concurrently. However, if historical span data is
/// being stored, the same ID may occur for multiple spans times in that
/// data. If spans must be uniquely identified in historical data, the user
/// code storing this data must assign its own unique identifiers to those
/// spans. A counter is generally sufficient for this.
///
/// Similarly, span IDs generated by the registry are not unique outside of
/// a given process. Distributed tracing systems may require identifiers
/// that are unique across multiple processes on multiple machines (for
/// example, [OpenTelemetry's `SpanId`s and `TraceId`s][ot]). `tracing` span
/// IDs generated by the registry should **not** be used for this purpose.
/// Instead, code which integrates with a distributed tracing system should
/// generate and propagate its own IDs according to the rules specified by
/// the distributed tracing system. These IDs can be associated with
/// `tracing` spans using [fields] and/or [stored span data].
///
/// [span IDs]: tracing_core::span::Id
/// [slab]: sharded_slab
/// [`Layer`]: crate::Layer
/// [added]: crate::layer::Layer#composing-layers
/// [extensions]: super::Extensions
/// [closed]: https://docs.rs/tracing/latest/tracing/span/index.html#closing-spans
/// [considered closed]: tracing_core::subscriber::Subscriber::try_close()
/// [`Span`]: https://docs.rs/tracing/latest/tracing/span/struct.Span.html
/// [ot]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#spancontext
/// [fields]: tracing_core::field
/// [stored span data]: crate::registry::SpanData::extensions_mut
#[cfg(feature = "registry")]
#[cfg_attr(docsrs, doc(cfg(all(feature = "registry", feature = "std"))))]
#[derive(Debug)]
pub struct Registry {
spans: Pool<DataInner>,
current_spans: ThreadLocal<RefCell<SpanStack>>,
next_filter_id: u8,
}
/// Span data stored in a [`Registry`].
///
/// The registry stores well-known data defined by tracing: span relationships,
/// metadata and reference counts. Additional user-defined data provided by
/// [`Layer`s], such as formatted fields, metrics, or distributed traces should
/// be stored in the [extensions] typemap.
///
/// [`Layer`s]: crate::layer::Layer
/// [extensions]: Extensions
#[cfg(feature = "registry")]
#[cfg_attr(docsrs, doc(cfg(all(feature = "registry", feature = "std"))))]
#[derive(Debug)]
pub struct Data<'a> {
/// Immutable reference to the pooled `DataInner` entry.
inner: Ref<'a, DataInner>,
}
/// Stored data associated with a span.
///
/// This type is pooled using [`sharded_slab::Pool`]; when a span is
/// dropped, the `DataInner` entry at that span's slab index is cleared
/// in place and reused by a future span. Thus, the `Default` and
/// [`sharded_slab::Clear`] implementations for this type are
/// load-bearing.
#[derive(Debug)]
struct DataInner {
filter_map: FilterMap,
metadata: &'static Metadata<'static>,
parent: Option<Id>,
ref_count: AtomicUsize,
// The span's `Extensions` typemap. Allocations for the `HashMap` backing
// this are pooled and reused in place.
pub(crate) extensions: RwLock<ExtensionsInner>,
}
// === impl Registry ===
impl Default for Registry {
fn default() -> Self {
Self {
spans: Pool::new(),
current_spans: ThreadLocal::new(),
next_filter_id: 0,
}
}
}
#[inline]
fn idx_to_id(idx: usize) -> Id {
Id::from_u64(idx as u64 + 1)
}
#[inline]
fn id_to_idx(id: &Id) -> usize {
id.into_u64() as usize - 1
}
/// A guard that tracks how many [`Registry`]-backed `Layer`s have
/// processed an `on_close` event.
///
/// This is needed to enable a [`Registry`]-backed Layer to access span
/// data after the `Layer` has recieved the `on_close` callback.
///
/// Once all `Layer`s have processed this event, the [`Registry`] knows
/// that is able to safely remove the span tracked by `id`. `CloseGuard`
/// accomplishes this through a two-step process:
/// 1. Whenever a [`Registry`]-backed `Layer::on_close` method is
/// called, `Registry::start_close` is closed.
/// `Registry::start_close` increments a thread-local `CLOSE_COUNT`
/// by 1 and returns a `CloseGuard`.
/// 2. The `CloseGuard` is dropped at the end of `Layer::on_close`. On
/// drop, `CloseGuard` checks thread-local `CLOSE_COUNT`. If
/// `CLOSE_COUNT` is 0, the `CloseGuard` removes the span with the
/// `id` from the registry, as all `Layers` that might have seen the
/// `on_close` notification have processed it. If `CLOSE_COUNT` is
/// greater than 0, `CloseGuard` decrements the counter by one and
/// _does not_ remove the span from the [`Registry`].
///
pub(crate) struct CloseGuard<'a> {
id: Id,
registry: &'a Registry,
is_closing: bool,
}
impl Registry {
fn get(&self, id: &Id) -> Option<Ref<'_, DataInner>> {
self.spans.get(id_to_idx(id))
}
/// Returns a guard which tracks how many `Layer`s have
/// processed an `on_close` notification via the `CLOSE_COUNT` thread-local.
/// For additional details, see [`CloseGuard`].
///
pub(crate) fn start_close(&self, id: Id) -> CloseGuard<'_> {
CLOSE_COUNT.with(|count| {
let c = count.get();
count.set(c + 1);
});
CloseGuard {
id,
registry: self,
is_closing: false,
}
}
pub(crate) fn has_per_layer_filters(&self) -> bool {
self.next_filter_id > 0
}
pub(crate) fn span_stack(&self) -> cell::Ref<'_, SpanStack> {
self.current_spans.get_or_default().borrow()
}
}
thread_local! {
/// `CLOSE_COUNT` is the thread-local counter used by `CloseGuard` to
/// track how many layers have processed the close.
/// For additional details, see [`CloseGuard`].
///
static CLOSE_COUNT: Cell<usize> = const { Cell::new(0) };
}
impl Subscriber for Registry {
fn register_callsite(&self, _: &'static Metadata<'static>) -> Interest {
if self.has_per_layer_filters() {
return FilterState::take_interest().unwrap_or_else(Interest::always);
}
Interest::always()
}
fn enabled(&self, _: &Metadata<'_>) -> bool {
if self.has_per_layer_filters() {
return FilterState::event_enabled();
}
true
}
#[inline]
fn new_span(&self, attrs: &span::Attributes<'_>) -> span::Id {
let parent = if attrs.is_root() {
None
} else if attrs.is_contextual() {
self.current_span().id().map(|id| self.clone_span(id))
} else {
attrs.parent().map(|id| self.clone_span(id))
};
let id = self
.spans
// Check out a `DataInner` entry from the pool for the new span. If
// there are free entries already allocated in the pool, this will
// preferentially reuse one; otherwise, a new `DataInner` is
// allocated and added to the pool.
.create_with(|data| {
data.metadata = attrs.metadata();
data.parent = parent;
data.filter_map = crate::filter::FILTERING.with(|filtering| filtering.filter_map());
#[cfg(debug_assertions)]
{
if data.filter_map != FilterMap::new() {
debug_assert!(self.has_per_layer_filters());
}
}
let refs = data.ref_count.get_mut();
debug_assert_eq!(*refs, 0);
*refs = 1;
})
.expect("Unable to allocate another span");
idx_to_id(id)
}
/// This is intentionally not implemented, as recording fields
/// on a span is the responsibility of layers atop of this registry.
#[inline]
fn record(&self, _: &span::Id, _: &span::Record<'_>) {}
fn record_follows_from(&self, _span: &span::Id, _follows: &span::Id) {}
fn event_enabled(&self, _event: &Event<'_>) -> bool {
if self.has_per_layer_filters() {
return FilterState::event_enabled();
}
true
}
/// This is intentionally not implemented, as recording events
/// is the responsibility of layers atop of this registry.
fn event(&self, _: &Event<'_>) {}
fn enter(&self, id: &span::Id) {
if self
.current_spans
.get_or_default()
.borrow_mut()
.push(id.clone())
{
self.clone_span(id);
}
}
fn exit(&self, id: &span::Id) {
if let Some(spans) = self.current_spans.get() {
if spans.borrow_mut().pop(id) {
dispatcher::get_default(|dispatch| dispatch.try_close(id.clone()));
}
}
}
fn clone_span(&self, id: &span::Id) -> span::Id {
let span = self
.get(id)
.unwrap_or_else(|| panic!(
"tried to clone {:?}, but no span exists with that ID\n\
This may be caused by consuming a parent span (`parent: span`) rather than borrowing it (`parent: &span`).",
id,
));
// Like `std::sync::Arc`, adds to the ref count (on clone) don't require
// a strong ordering; if we call` clone_span`, the reference count must
// always at least 1. The only synchronization necessary is between
// calls to `try_close`: we have to ensure that all threads have
// dropped their refs to the span before the span is closed.
let refs = span.ref_count.fetch_add(1, Ordering::Relaxed);
assert_ne!(
refs, 0,
"tried to clone a span ({:?}) that already closed",
id
);
id.clone()
}
fn current_span(&self) -> Current {
self.current_spans
.get()
.and_then(|spans| {
let spans = spans.borrow();
let id = spans.current()?;
let span = self.get(id)?;
Some(Current::new(id.clone(), span.metadata))
})
.unwrap_or_else(Current::none)
}
/// Decrements the reference count of the span with the given `id`, and
/// removes the span if it is zero.
///
/// The allocated span slot will be reused when a new span is created.
fn try_close(&self, id: span::Id) -> bool {
let span = match self.get(&id) {
Some(span) => span,
None if std::thread::panicking() => return false,
None => panic!("tried to drop a ref to {:?}, but no such span exists!", id),
};
let refs = span.ref_count.fetch_sub(1, Ordering::Release);
if !std::thread::panicking() {
assert!(refs < usize::MAX, "reference count overflow!");
}
if refs > 1 {
return false;
}
// Synchronize if we are actually removing the span (stolen
// from std::Arc); this ensures that all other `try_close` calls on
// other threads happen-before we actually remove the span.
fence(Ordering::Acquire);
true
}
}
impl<'a> LookupSpan<'a> for Registry {
type Data = Data<'a>;
fn span_data(&'a self, id: &Id) -> Option<Self::Data> {
let inner = self.get(id)?;
Some(Data { inner })
}
fn register_filter(&mut self) -> FilterId {
let id = FilterId::new(self.next_filter_id);
self.next_filter_id += 1;
id
}
}
// === impl CloseGuard ===
impl CloseGuard<'_> {
pub(crate) fn set_closing(&mut self) {
self.is_closing = true;
}
}
impl Drop for CloseGuard<'_> {
fn drop(&mut self) {
// If this returns with an error, we are already panicking. At
// this point, there's nothing we can really do to recover
// except by avoiding a double-panic.
let _ = CLOSE_COUNT.try_with(|count| {
let c = count.get();
// Decrement the count to indicate that _this_ guard's
// `on_close` callback has completed.
//
// Note that we *must* do this before we actually remove the span
// from the registry, since dropping the `DataInner` may trigger a
// new close, if this span is the last reference to a parent span.
count.set(c - 1);
// If the current close count is 1, this stack frame is the last
// `on_close` call. If the span is closing, it's okay to remove the
// span.
if c == 1 && self.is_closing {
self.registry.spans.clear(id_to_idx(&self.id));
}
});
}
}
// === impl Data ===
impl<'a> SpanData<'a> for Data<'a> {
fn id(&self) -> Id {
idx_to_id(self.inner.key())
}
fn metadata(&self) -> &'static Metadata<'static> {
self.inner.metadata
}
fn parent(&self) -> Option<&Id> {
self.inner.parent.as_ref()
}
fn extensions(&self) -> Extensions<'_> {
Extensions::new(self.inner.extensions.read().expect("Mutex poisoned"))
}
fn extensions_mut(&self) -> ExtensionsMut<'_> {
ExtensionsMut::new(self.inner.extensions.write().expect("Mutex poisoned"))
}
#[inline]
fn is_enabled_for(&self, filter: FilterId) -> bool {
self.inner.filter_map.is_enabled(filter)
}
}
// === impl DataInner ===
impl Default for DataInner {
fn default() -> Self {
// Since `DataInner` owns a `&'static Callsite` pointer, we need
// something to use as the initial default value for that callsite.
// Since we can't access a `DataInner` until it has had actual span data
// inserted into it, the null metadata will never actually be accessed.
struct NullCallsite;
impl tracing_core::callsite::Callsite for NullCallsite {
fn set_interest(&self, _: Interest) {
unreachable!(
"/!\\ Tried to register the null callsite /!\\\n \
This should never have happened and is definitely a bug. \
A `tracing` bug report would be appreciated."
)
}
fn metadata(&self) -> &Metadata<'_> {
unreachable!(
"/!\\ Tried to access the null callsite's metadata /!\\\n \
This should never have happened and is definitely a bug. \
A `tracing` bug report would be appreciated."
)
}
}
static NULL_CALLSITE: NullCallsite = NullCallsite;
static NULL_METADATA: Metadata<'static> = tracing_core::metadata! {
name: "",
target: "",
level: tracing_core::Level::TRACE,
fields: &[],
callsite: &NULL_CALLSITE,
kind: tracing_core::metadata::Kind::SPAN,
};
Self {
filter_map: FilterMap::new(),
metadata: &NULL_METADATA,
parent: None,
ref_count: AtomicUsize::new(0),
extensions: RwLock::new(ExtensionsInner::new()),
}
}
}
impl Clear for DataInner {
/// Clears the span's data in place, dropping the parent's reference count.
fn clear(&mut self) {
// A span is not considered closed until all of its children have closed.
// Therefore, each span's `DataInner` holds a "reference" to the parent
// span, keeping the parent span open until all its children have closed.
// When we close a span, we must then decrement the parent's ref count
// (potentially, allowing it to close, if this child is the last reference
// to that span).
// We have to actually unpack the option inside the `get_default`
// closure, since it is a `FnMut`, but testing that there _is_ a value
// here lets us avoid the thread-local access if we don't need the
// dispatcher at all.
if self.parent.is_some() {
// Note that --- because `Layered::try_close` works by calling
// `try_close` on the inner subscriber and using the return value to
// determine whether to call the `Layer`'s `on_close` callback ---
// we must call `try_close` on the entire subscriber stack, rather
// than just on the registry. If the registry called `try_close` on
// itself directly, the layers wouldn't see the close notification.
let subscriber = dispatcher::get_default(Dispatch::clone);
if let Some(parent) = self.parent.take() {
let _ = subscriber.try_close(parent);
}
}
// Clear (but do not deallocate!) the pooled `HashMap` for the span's extensions.
self.extensions
.get_mut()
.unwrap_or_else(|l| {
// This function can be called in a `Drop` impl, such as while
// panicking, so ignore lock poisoning.
l.into_inner()
})
.clear();
self.filter_map = FilterMap::new();
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{layer::Context, registry::LookupSpan, Layer};
use std::{
collections::HashMap,
sync::{Arc, Mutex, Weak},
};
use tracing::{self, subscriber::with_default};
use tracing_core::{
dispatcher,
span::{Attributes, Id},
Subscriber,
};
struct AssertionLayer;
impl<S> Layer<S> for AssertionLayer
where
S: Subscriber + for<'a> LookupSpan<'a>,
{
fn on_close(&self, id: Id, ctx: Context<'_, S>) {
dbg!(format_args!("closing {:?}", id));
assert!(&ctx.span(&id).is_some());
}
}
#[test]
fn single_layer_can_access_closed_span() {
let subscriber = AssertionLayer.with_subscriber(Registry::default());
with_default(subscriber, || {
let span = tracing::debug_span!("span");
drop(span);
});
}
#[test]
fn multiple_layers_can_access_closed_span() {
let subscriber = AssertionLayer
.and_then(AssertionLayer)
.with_subscriber(Registry::default());
with_default(subscriber, || {
let span = tracing::debug_span!("span");
drop(span);
});
}
struct CloseLayer {
inner: Arc<Mutex<CloseState>>,
}
struct CloseHandle {
state: Arc<Mutex<CloseState>>,
}
#[derive(Default)]
struct CloseState {
open: HashMap<&'static str, Weak<()>>,
closed: Vec<(&'static str, Weak<()>)>,
}
#[allow(dead_code)] // Field is exercised via checking `Arc::downgrade()`
struct SetRemoved(Arc<()>);
impl<S> Layer<S> for CloseLayer
where
S: Subscriber + for<'a> LookupSpan<'a>,
{
fn on_new_span(&self, _: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
let span = ctx.span(id).expect("Missing span; this is a bug");
let mut lock = self.inner.lock().unwrap();
let is_removed = Arc::new(());
assert!(
lock.open
.insert(span.name(), Arc::downgrade(&is_removed))
.is_none(),
"test layer saw multiple spans with the same name, the test is probably messed up"
);
let mut extensions = span.extensions_mut();
extensions.insert(SetRemoved(is_removed));
}
fn on_close(&self, id: Id, ctx: Context<'_, S>) {
let span = if let Some(span) = ctx.span(&id) {
span
} else {
println!(
"span {:?} did not exist in `on_close`, are we panicking?",
id
);
return;
};
let name = span.name();
println!("close {} ({:?})", name, id);
if let Ok(mut lock) = self.inner.lock() {
if let Some(is_removed) = lock.open.remove(name) {
assert!(is_removed.upgrade().is_some());
lock.closed.push((name, is_removed));
}
}
}
}
impl CloseLayer {
fn new() -> (Self, CloseHandle) {
let state = Arc::new(Mutex::new(CloseState::default()));
(
Self {
inner: state.clone(),
},
CloseHandle { state },
)
}
}
impl CloseState {
fn is_open(&self, span: &str) -> bool {
self.open.contains_key(span)
}
fn is_closed(&self, span: &str) -> bool {
self.closed.iter().any(|(name, _)| name == &span)
}
}
impl CloseHandle {
fn assert_closed(&self, span: &str) {
let lock = self.state.lock().unwrap();
assert!(
lock.is_closed(span),
"expected {} to be closed{}",
span,
if lock.is_open(span) {
" (it was still open)"
} else {
", but it never existed (is there a problem with the test?)"
}
)
}
fn assert_open(&self, span: &str) {
let lock = self.state.lock().unwrap();
assert!(
lock.is_open(span),
"expected {} to be open{}",
span,
if lock.is_closed(span) {
" (it was still open)"
} else {
", but it never existed (is there a problem with the test?)"
}
)
}
fn assert_removed(&self, span: &str) {
let lock = self.state.lock().unwrap();
let is_removed = match lock.closed.iter().find(|(name, _)| name == &span) {
Some((_, is_removed)) => is_removed,
None => panic!(
"expected {} to be removed from the registry, but it was not closed {}",
span,
if lock.is_closed(span) {
" (it was still open)"
} else {
", but it never existed (is there a problem with the test?)"
}
),
};
assert!(
is_removed.upgrade().is_none(),
"expected {} to have been removed from the registry",
span
)
}
fn assert_not_removed(&self, span: &str) {
let lock = self.state.lock().unwrap();
let is_removed = match lock.closed.iter().find(|(name, _)| name == &span) {
Some((_, is_removed)) => is_removed,
None if lock.is_open(span) => return,
None => unreachable!(),
};
assert!(
is_removed.upgrade().is_some(),
"expected {} to have been removed from the registry",
span
)
}
#[allow(unused)] // may want this for future tests
fn assert_last_closed(&self, span: Option<&str>) {
let lock = self.state.lock().unwrap();
let last = lock.closed.last().map(|(span, _)| span);
assert_eq!(
last,
span.as_ref(),
"expected {:?} to have closed last",
span
);
}
fn assert_closed_in_order(&self, order: impl AsRef<[&'static str]>) {
let lock = self.state.lock().unwrap();
let order = order.as_ref();
for (i, name) in order.iter().enumerate() {
assert_eq!(
lock.closed.get(i).map(|(span, _)| span),
Some(name),
"expected close order: {:?}, actual: {:?}",
order,
lock.closed.iter().map(|(name, _)| name).collect::<Vec<_>>()
);
}
}
}
#[test]
fn spans_are_removed_from_registry() {
let (close_layer, state) = CloseLayer::new();
let subscriber = AssertionLayer
.and_then(close_layer)
.with_subscriber(Registry::default());
// Create a `Dispatch` (which is internally reference counted) so that
// the subscriber lives to the end of the test. Otherwise, if we just
// passed the subscriber itself to `with_default`, we could see the span
// be dropped when the subscriber itself is dropped, destroying the
// registry.
let dispatch = dispatcher::Dispatch::new(subscriber);
dispatcher::with_default(&dispatch, || {
let span = tracing::debug_span!("span1");
drop(span);
let span = tracing::info_span!("span2");
drop(span);
});
state.assert_removed("span1");
state.assert_removed("span2");
// Ensure the registry itself outlives the span.
drop(dispatch);
}
#[test]
fn spans_are_only_closed_when_the_last_ref_drops() {
let (close_layer, state) = CloseLayer::new();
let subscriber = AssertionLayer
.and_then(close_layer)
.with_subscriber(Registry::default());
// Create a `Dispatch` (which is internally reference counted) so that
// the subscriber lives to the end of the test. Otherwise, if we just
// passed the subscriber itself to `with_default`, we could see the span
// be dropped when the subscriber itself is dropped, destroying the
// registry.
let dispatch = dispatcher::Dispatch::new(subscriber);
let span2 = dispatcher::with_default(&dispatch, || {
let span = tracing::debug_span!("span1");
drop(span);
let span2 = tracing::info_span!("span2");
let span2_clone = span2.clone();
drop(span2);
span2_clone
});
state.assert_removed("span1");
state.assert_not_removed("span2");
drop(span2);
state.assert_removed("span1");
// Ensure the registry itself outlives the span.
drop(dispatch);
}
#[test]
fn span_enter_guards_are_dropped_out_of_order() {
let (close_layer, state) = CloseLayer::new();
let subscriber = AssertionLayer
.and_then(close_layer)
.with_subscriber(Registry::default());
// Create a `Dispatch` (which is internally reference counted) so that
// the subscriber lives to the end of the test. Otherwise, if we just
// passed the subscriber itself to `with_default`, we could see the span
// be dropped when the subscriber itself is dropped, destroying the
// registry.
let dispatch = dispatcher::Dispatch::new(subscriber);
dispatcher::with_default(&dispatch, || {
let span1 = tracing::debug_span!("span1");
let span2 = tracing::info_span!("span2");
let enter1 = span1.enter();
let enter2 = span2.enter();
drop(enter1);
drop(span1);
state.assert_removed("span1");
state.assert_not_removed("span2");
drop(enter2);
state.assert_not_removed("span2");
drop(span2);
state.assert_removed("span1");
state.assert_removed("span2");
});
}
#[test]
fn child_closes_parent() {
// This test asserts that if a parent span's handle is dropped before
// a child span's handle, the parent will remain open until child
// closes, and will then be closed.
let (close_layer, state) = CloseLayer::new();
let subscriber = close_layer.with_subscriber(Registry::default());
let dispatch = dispatcher::Dispatch::new(subscriber);
dispatcher::with_default(&dispatch, || {
let span1 = tracing::info_span!("parent");
let span2 = tracing::info_span!(parent: &span1, "child");
state.assert_open("parent");
state.assert_open("child");
drop(span1);
state.assert_open("parent");
state.assert_open("child");
drop(span2);
state.assert_closed("parent");
state.assert_closed("child");
});
}
#[test]
fn child_closes_grandparent() {
// This test asserts that, when a span is kept open by a child which
// is *itself* kept open by a child, closing the grandchild will close
// both the parent *and* the grandparent.
let (close_layer, state) = CloseLayer::new();
let subscriber = close_layer.with_subscriber(Registry::default());
let dispatch = dispatcher::Dispatch::new(subscriber);
dispatcher::with_default(&dispatch, || {
let span1 = tracing::info_span!("grandparent");
let span2 = tracing::info_span!(parent: &span1, "parent");
let span3 = tracing::info_span!(parent: &span2, "child");
state.assert_open("grandparent");
state.assert_open("parent");
state.assert_open("child");
drop(span1);
drop(span2);
state.assert_open("grandparent");
state.assert_open("parent");
state.assert_open("child");
drop(span3);
state.assert_closed_in_order(["child", "parent", "grandparent"]);
});
}
}

View File

@@ -0,0 +1,77 @@
pub(crate) use tracing_core::span::Id;
#[derive(Debug)]
struct ContextId {
id: Id,
duplicate: bool,
}
/// `SpanStack` tracks what spans are currently executing on a thread-local basis.
///
/// A "separate current span" for each thread is a semantic choice, as each span
/// can be executing in a different thread.
#[derive(Debug, Default)]
pub(crate) struct SpanStack {
stack: Vec<ContextId>,
}
impl SpanStack {
#[inline]
pub(super) fn push(&mut self, id: Id) -> bool {
let duplicate = self.stack.iter().any(|i| i.id == id);
self.stack.push(ContextId { id, duplicate });
!duplicate
}
#[inline]
pub(super) fn pop(&mut self, expected_id: &Id) -> bool {
if let Some((idx, _)) = self
.stack
.iter()
.enumerate()
.rev()
.find(|(_, ctx_id)| ctx_id.id == *expected_id)
{
let ContextId { id: _, duplicate } = self.stack.remove(idx);
return !duplicate;
}
false
}
#[inline]
pub(crate) fn iter(&self) -> impl Iterator<Item = &Id> {
self.stack
.iter()
.rev()
.filter_map(|ContextId { id, duplicate }| if !*duplicate { Some(id) } else { None })
}
#[inline]
pub(crate) fn current(&self) -> Option<&Id> {
self.iter().next()
}
}
#[cfg(test)]
mod tests {
use super::{Id, SpanStack};
#[test]
fn pop_last_span() {
let mut stack = SpanStack::default();
let id = Id::from_u64(1);
stack.push(id.clone());
assert!(stack.pop(&id));
}
#[test]
fn pop_first_span() {
let mut stack = SpanStack::default();
stack.push(Id::from_u64(1));
stack.push(Id::from_u64(2));
let id = Id::from_u64(1);
assert!(stack.pop(&id));
}
}