mirror of
https://github.com/tokio-rs/tracing.git
synced 2025-10-02 15:24:47 +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"]
|
env-filter = ["matchers", "regex", "lazy_static"]
|
||||||
fmt = ["owning_ref"]
|
fmt = ["owning_ref"]
|
||||||
ansi = ["fmt", "ansi_term"]
|
ansi = ["fmt", "ansi_term"]
|
||||||
|
registry_unstable = []
|
||||||
|
|
||||||
# Alias for `env-filter`; renamed in version 0.1.2, and will be removed in 0.2.
|
# Alias for `env-filter`; renamed in version 0.1.2, and will be removed in 0.2.
|
||||||
filter = ["env-filter"]
|
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" }
|
azure-devops = { project = "tracing/tracing", pipeline = "tokio-rs.tracing", build = "1" }
|
||||||
maintenance = { status = "experimental" }
|
maintenance = { status = "experimental" }
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "filter"
|
name = "filter"
|
||||||
harness = false
|
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 Formatter ===
|
||||||
|
|
||||||
impl<N, E, W> Formatter<N, E, W>
|
impl<N, E, W> Formatter<N, E, W>
|
||||||
where
|
where
|
||||||
N: for<'writer> FormatFields<'writer>,
|
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 Builder =====
|
||||||
|
|
||||||
impl Default for Builder {
|
impl Default for Builder {
|
||||||
@ -933,4 +952,11 @@ mod test {
|
|||||||
assert!(dispatch.downcast_ref::<LevelFilter>().is_some());
|
assert!(dispatch.downcast_ref::<LevelFilter>().is_some());
|
||||||
assert!(dispatch.downcast_ref::<format::Format>().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,
|
Event,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "registry_unstable")]
|
||||||
|
use crate::registry::LookupMetadata;
|
||||||
use std::{any::TypeId, marker::PhantomData};
|
use std::{any::TypeId, marker::PhantomData};
|
||||||
|
|
||||||
/// A composable handler for `tracing` events.
|
/// 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>
|
impl<L, S> Layered<L, S>
|
||||||
where
|
where
|
||||||
S: Subscriber,
|
S: Subscriber,
|
||||||
@ -678,6 +690,42 @@ impl<'a, S: Subscriber> Context<'a, S> {
|
|||||||
subscriber.event(event);
|
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> {
|
impl<'a, S> Context<'a, S> {
|
||||||
|
@ -25,7 +25,9 @@
|
|||||||
//! - `fmt`: Enables the [`fmt`] module, which provides a subscriber
|
//! - `fmt`: Enables the [`fmt`] module, which provides a subscriber
|
||||||
//! implementation for printing formatted representations of trace events.
|
//! implementation for printing formatted representations of trace events.
|
||||||
//! Enabled by default.
|
//! 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
|
//! ### Optional Dependencies
|
||||||
//!
|
//!
|
||||||
@ -47,6 +49,7 @@
|
|||||||
//! [`chrono`]: https://crates.io/crates/chrono
|
//! [`chrono`]: https://crates.io/crates/chrono
|
||||||
//! [`env_logger` crate]: https://crates.io/crates/env_logger
|
//! [`env_logger` crate]: https://crates.io/crates/env_logger
|
||||||
//! [`parking_lot`]: https://crates.io/crates/parking_lot
|
//! [`parking_lot`]: https://crates.io/crates/parking_lot
|
||||||
|
//! [`registry`]: registry/index.html
|
||||||
#![doc(html_root_url = "https://docs.rs/tracing-subscriber/0.1.5")]
|
#![doc(html_root_url = "https://docs.rs/tracing-subscriber/0.1.5")]
|
||||||
#![warn(
|
#![warn(
|
||||||
missing_debug_implementations,
|
missing_debug_implementations,
|
||||||
@ -105,6 +108,8 @@ pub mod filter;
|
|||||||
pub mod fmt;
|
pub mod fmt;
|
||||||
pub mod layer;
|
pub mod layer;
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
|
#[cfg(feature = "registry_unstable")]
|
||||||
|
pub mod registry;
|
||||||
pub mod reload;
|
pub mod reload;
|
||||||
pub(crate) mod sync;
|
pub(crate) mod sync;
|
||||||
pub(crate) mod thread;
|
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