mirror of
https://github.com/tokio-rs/tracing.git
synced 2025-10-01 15:00:33 +00:00
subscriber: allow subscribers to expose stored metadata to layers (#382)
## Motivation Currently, when using `tracing-subscriber`'s `Layer` API, it is necessary for each layer to manage its own storage for per-span data. Since subscribers are shared concurrently, this means that `Layer`s must also manage synchronization on this storage. This is easy to get wrong, and even when it's implemented correctly, having every layer synchronize separately adds a lot of overhead. Ideally, it should be possible for state stored by the subscriber to be exposed to `Layer`s. ## Solution: This branch *starts* on the project of a general-purpose span registry by adding a new trait, `LookupMetadata`. Subscribers may implement this trait to allow looking up a span's `Metadata` by ID. If a subscriber implements this trait, the `layer::Context` type will then allow any layers wrapping that subscriber to look up metadata by ID. The `FmtSubscriber` implements this trait. Future work will be able to an interface for `Subscriber`s to expose more span data, such as parents, children, and arbitrarily-typed extensions, to `Layer`s as well. Signed-off-by: Eliza Weisman <eliza@buoyant.io>
This commit is contained in:
parent
f19f63f83d
commit
97a8681fb9
@ -24,6 +24,7 @@ default = ["env-filter", "smallvec", "fmt", "ansi", "chrono", "tracing-log"]
|
||||
env-filter = ["matchers", "regex", "lazy_static"]
|
||||
fmt = ["owning_ref"]
|
||||
ansi = ["fmt", "ansi_term"]
|
||||
registry_unstable = []
|
||||
|
||||
# Alias for `env-filter`; renamed in version 0.1.2, and will be removed in 0.2.
|
||||
filter = ["env-filter"]
|
||||
@ -56,6 +57,9 @@ criterion = { version = "0.3", default_features = false }
|
||||
azure-devops = { project = "tracing/tracing", pipeline = "tokio-rs.tracing", build = "1" }
|
||||
maintenance = { status = "experimental" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
[[bench]]
|
||||
name = "filter"
|
||||
harness = false
|
||||
|
@ -271,7 +271,19 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "registry_unstable")]
|
||||
impl<N, E, F, W> crate::registry::LookupMetadata for Subscriber<N, E, F, W>
|
||||
where
|
||||
layer::Layered<F, Formatter<N, E, W>>: crate::registry::LookupMetadata,
|
||||
{
|
||||
#[inline]
|
||||
fn metadata(&self, id: &span::Id) -> Option<&'static Metadata<'static>> {
|
||||
self.inner.metadata(id)
|
||||
}
|
||||
}
|
||||
|
||||
// === impl Formatter ===
|
||||
|
||||
impl<N, E, W> Formatter<N, E, W>
|
||||
where
|
||||
N: for<'writer> FormatFields<'writer>,
|
||||
@ -378,6 +390,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "registry_unstable")]
|
||||
impl<N, E, W> crate::registry::LookupMetadata for Formatter<N, E, W> {
|
||||
fn metadata(&self, id: &span::Id) -> Option<&'static Metadata<'static>> {
|
||||
self.spans.get(&id).map(|span| span.metadata())
|
||||
}
|
||||
}
|
||||
|
||||
// ===== impl Builder =====
|
||||
|
||||
impl Default for Builder {
|
||||
@ -933,4 +952,11 @@ mod test {
|
||||
assert!(dispatch.downcast_ref::<LevelFilter>().is_some());
|
||||
assert!(dispatch.downcast_ref::<format::Format>().is_some())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "registry_unstable")]
|
||||
fn is_lookup_meta() {
|
||||
fn assert_lookup_meta<T: crate::registry::LookupMetadata>(_: T) {}
|
||||
assert_lookup_meta(Subscriber::builder().finish())
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ use tracing_core::{
|
||||
Event,
|
||||
};
|
||||
|
||||
#[cfg(feature = "registry_unstable")]
|
||||
use crate::registry::LookupMetadata;
|
||||
use std::{any::TypeId, marker::PhantomData};
|
||||
|
||||
/// A composable handler for `tracing` events.
|
||||
@ -605,6 +607,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "registry_unstable")]
|
||||
impl<L, S> LookupMetadata for Layered<L, S>
|
||||
where
|
||||
S: Subscriber + LookupMetadata,
|
||||
{
|
||||
fn metadata(&self, span: &span::Id) -> Option<&'static Metadata<'static>> {
|
||||
self.inner.metadata(span)
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, S> Layered<L, S>
|
||||
where
|
||||
S: Subscriber,
|
||||
@ -678,6 +690,42 @@ impl<'a, S: Subscriber> Context<'a, S> {
|
||||
subscriber.event(event);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns metadata for tne span with the given `id`, if it exists.
|
||||
///
|
||||
/// If this returns `None`, then no span exists for that ID (either it has
|
||||
/// closed or the ID is invalid).
|
||||
///
|
||||
/// **Note**: This requires the wrapped subscriber to implement the
|
||||
/// [`LookupMetadata`] trait. `Layer` implementations that wish to use this
|
||||
/// function can bound their `Subscriber` type parameter with
|
||||
/// ```rust,ignore
|
||||
/// where S: Subscriber + LookupMetadata,
|
||||
/// ```
|
||||
/// or similar.
|
||||
///
|
||||
/// [`LookupMetadata`]: ../registry/trait.LookupMetadata.html
|
||||
#[inline]
|
||||
#[cfg(feature = "registry_unstable")]
|
||||
pub fn metadata(&self, id: &span::Id) -> Option<&'static Metadata<'static>>
|
||||
where
|
||||
S: LookupMetadata,
|
||||
{
|
||||
self.subscriber.as_ref()?.metadata(id)
|
||||
}
|
||||
|
||||
/// Returns `true` if an active span exists for the given `Id`.
|
||||
#[inline]
|
||||
#[cfg(feature = "registry_unstable")]
|
||||
pub fn exists(&self, id: &span::Id) -> bool
|
||||
where
|
||||
S: LookupMetadata,
|
||||
{
|
||||
self.subscriber
|
||||
.as_ref()
|
||||
.map(|s| s.exists(id))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S> Context<'a, S> {
|
||||
|
@ -25,7 +25,9 @@
|
||||
//! - `fmt`: Enables the [`fmt`] module, which provides a subscriber
|
||||
//! implementation for printing formatted representations of trace events.
|
||||
//! Enabled by default.
|
||||
//! - `ansi`: Enables `fmt` support for ANSI terminal colors. Enabled by default.
|
||||
//! - `ansi`: Enables `fmt` support for ANSI terminal colors. Enabled by
|
||||
//! default.
|
||||
//! - `registry_unstable`: enables the experimental [`registry`] module.
|
||||
//!
|
||||
//! ### Optional Dependencies
|
||||
//!
|
||||
@ -47,6 +49,7 @@
|
||||
//! [`chrono`]: https://crates.io/crates/chrono
|
||||
//! [`env_logger` crate]: https://crates.io/crates/env_logger
|
||||
//! [`parking_lot`]: https://crates.io/crates/parking_lot
|
||||
//! [`registry`]: registry/index.html
|
||||
#![doc(html_root_url = "https://docs.rs/tracing-subscriber/0.1.5")]
|
||||
#![warn(
|
||||
missing_debug_implementations,
|
||||
@ -105,6 +108,8 @@ pub mod filter;
|
||||
pub mod fmt;
|
||||
pub mod layer;
|
||||
pub mod prelude;
|
||||
#[cfg(feature = "registry_unstable")]
|
||||
pub mod registry;
|
||||
pub mod reload;
|
||||
pub(crate) mod sync;
|
||||
pub(crate) mod thread;
|
||||
|
47
tracing-subscriber/src/registry/mod.rs
Normal file
47
tracing-subscriber/src/registry/mod.rs
Normal file
@ -0,0 +1,47 @@
|
||||
//! **EXPERIMENTAL**: Storage for span data shared by multiple [`Layer`]s.
|
||||
//!
|
||||
//! This module is experimental. Although potential breaking changes will be
|
||||
//! avoided when possible, we reserve the right to make breaking changes to this
|
||||
//! module until it is no longer experimental.
|
||||
//!
|
||||
//! Add the `registry_unstable` feature to your `Cargo.toml` to enable
|
||||
//! this module:
|
||||
//!
|
||||
//! ```toml
|
||||
//! [dependencies.tracing-subscriber]
|
||||
//! features = ["registry_unstable"]
|
||||
//! ```
|
||||
//!
|
||||
//! [`Layer`]: ../layer/struct.Layer.html
|
||||
use tracing_core::{span::Id, Metadata};
|
||||
/// Provides access to stored span metadata.
|
||||
///
|
||||
/// Subscribers which store span metadata 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 [`metadata()`] method.
|
||||
///
|
||||
/// [`Layer`]: ../layer/struct.Layer.html
|
||||
/// [`Context`]: ../layer/struct.Context.html
|
||||
/// [`metadata()`]: ../layer/struct.Context.html#method.metadata
|
||||
pub trait LookupMetadata {
|
||||
/// Returns metadata for tne span with the given `id`, if it exists.
|
||||
///
|
||||
/// If no span exists for the provided ID (e.g. the span has closed and been
|
||||
/// removed from the registry, or the ID is invalid), this should return `None`.
|
||||
fn metadata(&self, id: &Id) -> Option<&'static Metadata<'static>>;
|
||||
|
||||
/// Returns `true` if a span with the given `id` exists, false otherwise.
|
||||
///
|
||||
/// **Note**: The default implementation of this method is simply:
|
||||
///```rust,ignore
|
||||
/// fn exists(&self, id: &span::Id) -> bool {
|
||||
/// self.metadata(id).is_some()
|
||||
/// }
|
||||
///```
|
||||
/// If the subscriber has a faster way of determining whether a span exists
|
||||
/// for a given ID (e.g., if the ID is greater than the current value of an
|
||||
/// increasing ID counter, etc), this method may be overridden as an optimization.
|
||||
fn exists(&self, id: &Id) -> bool {
|
||||
self.metadata(id).is_some()
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user