diff --git a/tracing-subscriber/src/fmt/fmt_layer.rs b/tracing-subscriber/src/fmt/fmt_layer.rs index 054ac36aa5..71113dc67a 100644 --- a/tracing-subscriber/src/fmt/fmt_layer.rs +++ b/tracing-subscriber/src/fmt/fmt_layer.rs @@ -20,8 +20,8 @@ use tracing_core::{ /// use tracing_subscriber::{fmt, registry::Registry}; /// use tracing_subscriber::prelude::*; /// -/// let subscriber = fmt::Layer::default() -/// .with_subscriber(Registry::default()); +/// let subscriber = Registry::default() +/// .with(fmt::Layer::default()); /// /// tracing::subscriber::set_global_default(subscriber).unwrap(); /// ``` diff --git a/tracing-subscriber/src/fmt/mod.rs b/tracing-subscriber/src/fmt/mod.rs index f0d7520da0..452a184e01 100644 --- a/tracing-subscriber/src/fmt/mod.rs +++ b/tracing-subscriber/src/fmt/mod.rs @@ -101,16 +101,18 @@ //! //! ```rust //! use tracing_subscriber::{fmt, Layer, registry::Registry, EnvFilter}; +//! use tracing_subscriber::prelude::*; //! //! let fmt_layer = fmt::Layer::builder() //! .with_target(false) //! .finish(); -//! -//! let subscriber = EnvFilter::try_from_default_env() +//! let filter_layer = EnvFilter::try_from_default_env() //! .or_else(|_| EnvFilter::try_new("info")) -//! .unwrap() -//! .and_then(fmt_layer) -//! .with_subscriber(Registry::default()); +//! .unwrap(); +//! +//! let subscriber = Registry::default() +//! .with(filter_layer) +//! .with(fmt_layer); //! //! tracing::subscriber::set_global_default(subscriber).unwrap(); //! ``` diff --git a/tracing-subscriber/src/layer.rs b/tracing-subscriber/src/layer.rs index 34aa670ec4..8a10e443b1 100644 --- a/tracing-subscriber/src/layer.rs +++ b/tracing-subscriber/src/layer.rs @@ -31,6 +31,131 @@ use std::{any::TypeId, marker::PhantomData}; /// [`Subscriber`] behavior; it can _observe_ events and spans, but does not /// assign IDs. /// +/// ## Composing Layers +/// +/// Since a `Layer` does not implement a complete strategy for collecting +/// traces, it must be composed with a `Subscriber` in order to be used. The +/// `Layer` trait is generic over a type parameter (called `S` in the trait +/// definition), representing the types of `Subscriber` they can be composed +/// with. Thus, a `Layer` may be implemented that will only compose with a +/// particular `Subscriber` implementation, or additional trait bounds may be +/// added to constrain what types implementing `Subscriber` a `Layer` can wrap. +/// +/// `Layer`s may be added to a `Subscriber` by using the [`SubscriberExt::with`] +/// method, which is provided by `tracing-subscriber`'s [prelude]. This method +/// returns a [`Layered`] struct that implements `Subscriber` by composing the +/// `Layer` with the `Subscriber`. +/// +/// For example: +/// ```rust +/// use tracing_subscriber::Layer; +/// use tracing_subscriber::prelude::*; +/// use tracing::Subscriber; +/// +/// pub struct MyLayer { +/// // ... +/// } +/// +/// impl Layer for MyLayer { +/// // ... +/// } +/// +/// pub struct MySubscriber { +/// // ... +/// } +/// +/// # use tracing_core::{span::{Id, Attributes, Record}, Metadata, Event}; +/// impl Subscriber for MySubscriber { +/// // ... +/// # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(1) } +/// # fn record(&self, _: &Id, _: &Record) {} +/// # fn event(&self, _: &Event) {} +/// # fn record_follows_from(&self, _: &Id, _: &Id) {} +/// # fn enabled(&self, _: &Metadata) -> bool { false } +/// # fn enter(&self, _: &Id) {} +/// # fn exit(&self, _: &Id) {} +/// } +/// # impl MyLayer { +/// # fn new() -> Self { Self {} } +/// # } +/// # impl MySubscriber { +/// # fn new() -> Self { Self { }} +/// # } +/// +/// let subscriber = MySubscriber::new() +/// .with(MyLayer::new()); +/// +/// tracing::subscriber::set_global_default(subscriber); +/// ``` +/// +/// Multiple `Layer`s may be composed in the same manner: +/// ```rust +/// # use tracing_subscriber::Layer; +/// # use tracing_subscriber::prelude::*; +/// # use tracing::Subscriber; +/// pub struct MyOtherLayer { +/// // ... +/// } +/// +/// impl Layer for MyOtherLayer { +/// // ... +/// } +/// +/// pub struct MyThirdLayer { +/// // ... +/// } +/// +/// impl Layer for MyThirdLayer { +/// // ... +/// } +/// # pub struct MyLayer {} +/// # impl Layer for MyLayer {} +/// # pub struct MySubscriber { } +/// # use tracing_core::{span::{Id, Attributes, Record}, Metadata, Event}; +/// # impl Subscriber for MySubscriber { +/// # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(1) } +/// # fn record(&self, _: &Id, _: &Record) {} +/// # fn event(&self, _: &Event) {} +/// # fn record_follows_from(&self, _: &Id, _: &Id) {} +/// # fn enabled(&self, _: &Metadata) -> bool { false } +/// # fn enter(&self, _: &Id) {} +/// # fn exit(&self, _: &Id) {} +/// } +/// # impl MyLayer { +/// # fn new() -> Self { Self {} } +/// # } +/// # impl MyOtherLayer { +/// # fn new() -> Self { Self {} } +/// # } +/// # impl MyThirdLayer { +/// # fn new() -> Self { Self {} } +/// # } +/// # impl MySubscriber { +/// # fn new() -> Self { Self { }} +/// # } +/// +/// let subscriber = MySubscriber::new() +/// .with(MyLayer::new()) +/// .with(MyOtherLayer::new()) +/// .with(MyThirdLayer::new()); +/// +/// tracing::subscriber::set_global_default(subscriber); +/// ``` +/// +/// The [`Layer::with_subscriber` method][with-sub] constructs the `Layered` +/// type from a `Layer` and `Subscriber`, and is called by +/// [`SubscriberExt::with`]. In general, it is more idiomatic to use +/// `SubscriberExt::with`, and treat `Layer::with_subscriber` as an +/// implementation detail, as `with_subscriber` calls must be nested, leading to +/// less clear code for the reader. However, `Layer`s which wish to perform +/// additional behavior when composed with a subscriber may provide their own +/// implementations of `SubscriberExt::with`. +/// +/// [`SubscriberExt::with`]: trait.SubscriberExt.html#method.with +/// [`Layered`]: struct.Layered.html +/// [prelude]: ../prelude/index.html +/// [with-sub]: #method.with_subscriber +/// /// ## Recording Traces /// /// The `Layer` trait defines a set of methods for consuming notifications from @@ -371,11 +496,7 @@ pub trait SubscriberExt: Subscriber + crate::sealed::Sealed { L: Layer, Self: Sized, { - Layered { - layer, - inner: self, - _s: PhantomData, - } + layer.with_subscriber(self) } } diff --git a/tracing-subscriber/src/registry/mod.rs b/tracing-subscriber/src/registry/mod.rs index e58804892d..f8671437a7 100644 --- a/tracing-subscriber/src/registry/mod.rs +++ b/tracing-subscriber/src/registry/mod.rs @@ -13,7 +13,7 @@ //! //! For example, we might create a `Registry` and add multiple `Layer`s like so: //! ```rust -//! use tracing_subscriber::{registry::Registry, Layer}; +//! use tracing_subscriber::{registry::Registry, Layer, prelude::*}; //! # use tracing_core::Subscriber; //! # pub struct FooLayer {} //! # pub struct BarLayer {} @@ -23,12 +23,12 @@ //! # fn new() -> Self { Self {} } //! # } //! # impl BarLayer { -//! # fn new() -> Self { Self { }} +//! # fn new() -> Self { Self {} } //! # } //! -//! let subscriber = FooLayer::new() -//! .and_then(BarLayer::new()) -//! .with_subscriber(Registry::default()); +//! let subscriber = Registry::default() +//! .with(FooLayer::new()) +//! .with(BarLayer::new()); //! ``` //! //! If a type implementing `Layer` depends on the functionality of a `Registry`