subscriber: improve docs on Layer composition (#566)

Depends on #564 

This commit adds a new section to the `Layer` docs on how `Layer`s and
`Subscriber`s are composed. Additionally, it updates the docs to prefer
the use of `SubscriberExt::with` over `Layer::with_subscriber`.

Additionally, I've fixed how `SubscriberExt::with` is implemented, so
that `Layer`s may use `with_subscriber` as a callback for composition.

Closes  #452
Closes #505 (IMO)
This commit is contained in:
Eliza Weisman 2020-02-04 14:03:48 -08:00 committed by GitHub
parent a661155590
commit e32012a64a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 140 additions and 17 deletions

View File

@ -20,8 +20,8 @@ use tracing_core::{
/// use tracing_subscriber::{fmt, registry::Registry}; /// use tracing_subscriber::{fmt, registry::Registry};
/// use tracing_subscriber::prelude::*; /// use tracing_subscriber::prelude::*;
/// ///
/// let subscriber = fmt::Layer::default() /// let subscriber = Registry::default()
/// .with_subscriber(Registry::default()); /// .with(fmt::Layer::default());
/// ///
/// tracing::subscriber::set_global_default(subscriber).unwrap(); /// tracing::subscriber::set_global_default(subscriber).unwrap();
/// ``` /// ```

View File

@ -101,16 +101,18 @@
//! //!
//! ```rust //! ```rust
//! use tracing_subscriber::{fmt, Layer, registry::Registry, EnvFilter}; //! use tracing_subscriber::{fmt, Layer, registry::Registry, EnvFilter};
//! use tracing_subscriber::prelude::*;
//! //!
//! let fmt_layer = fmt::Layer::builder() //! let fmt_layer = fmt::Layer::builder()
//! .with_target(false) //! .with_target(false)
//! .finish(); //! .finish();
//! //! let filter_layer = EnvFilter::try_from_default_env()
//! let subscriber = EnvFilter::try_from_default_env()
//! .or_else(|_| EnvFilter::try_new("info")) //! .or_else(|_| EnvFilter::try_new("info"))
//! .unwrap() //! .unwrap();
//! .and_then(fmt_layer) //!
//! .with_subscriber(Registry::default()); //! let subscriber = Registry::default()
//! .with(filter_layer)
//! .with(fmt_layer);
//! //!
//! tracing::subscriber::set_global_default(subscriber).unwrap(); //! tracing::subscriber::set_global_default(subscriber).unwrap();
//! ``` //! ```

View File

@ -31,6 +31,131 @@ use std::{any::TypeId, marker::PhantomData};
/// [`Subscriber`] behavior; it can _observe_ events and spans, but does not /// [`Subscriber`] behavior; it can _observe_ events and spans, but does not
/// assign IDs. /// 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<S: Subscriber> Layer<S> 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<S: Subscriber> Layer<S> for MyOtherLayer {
/// // ...
/// }
///
/// pub struct MyThirdLayer {
/// // ...
/// }
///
/// impl<S: Subscriber> Layer<S> for MyThirdLayer {
/// // ...
/// }
/// # pub struct MyLayer {}
/// # impl<S: Subscriber> Layer<S> 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 /// ## Recording Traces
/// ///
/// The `Layer` trait defines a set of methods for consuming notifications from /// 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>, L: Layer<Self>,
Self: Sized, Self: Sized,
{ {
Layered { layer.with_subscriber(self)
layer,
inner: self,
_s: PhantomData,
}
} }
} }

View File

@ -13,7 +13,7 @@
//! //!
//! For example, we might create a `Registry` and add multiple `Layer`s like so: //! For example, we might create a `Registry` and add multiple `Layer`s like so:
//! ```rust //! ```rust
//! use tracing_subscriber::{registry::Registry, Layer}; //! use tracing_subscriber::{registry::Registry, Layer, prelude::*};
//! # use tracing_core::Subscriber; //! # use tracing_core::Subscriber;
//! # pub struct FooLayer {} //! # pub struct FooLayer {}
//! # pub struct BarLayer {} //! # pub struct BarLayer {}
@ -23,12 +23,12 @@
//! # fn new() -> Self { Self {} } //! # fn new() -> Self { Self {} }
//! # } //! # }
//! # impl BarLayer { //! # impl BarLayer {
//! # fn new() -> Self { Self { }} //! # fn new() -> Self { Self {} }
//! # } //! # }
//! //!
//! let subscriber = FooLayer::new() //! let subscriber = Registry::default()
//! .and_then(BarLayer::new()) //! .with(FooLayer::new())
//! .with_subscriber(Registry::default()); //! .with(BarLayer::new());
//! ``` //! ```
//! //!
//! If a type implementing `Layer` depends on the functionality of a `Registry` //! If a type implementing `Layer` depends on the functionality of a `Registry`