summaryrefslogtreecommitdiffstats
path: root/vendor/tracing-subscriber/src/layer/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--vendor/tracing-subscriber/src/layer/mod.rs (renamed from vendor/tracing-subscriber-0.3.3/src/layer/mod.rs)820
1 files changed, 713 insertions, 107 deletions
diff --git a/vendor/tracing-subscriber-0.3.3/src/layer/mod.rs b/vendor/tracing-subscriber/src/layer/mod.rs
index f3f994490..bdc154301 100644
--- a/vendor/tracing-subscriber-0.3.3/src/layer/mod.rs
+++ b/vendor/tracing-subscriber/src/layer/mod.rs
@@ -19,7 +19,7 @@
//! [`Subscriber`] behavior; it can _observe_ events and spans, but does not
//! assign IDs.
//!
-//! ## Composing Layers
+//! # 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
@@ -135,9 +135,245 @@
//! [`Layer::with_subscriber`] as an implementation detail, as `with_subscriber`
//! calls must be nested, leading to less clear code for the reader.
//!
+//! ## Runtime Configuration With `Layer`s
+//!
+//! In some cases, a particular [`Layer`] may be enabled or disabled based on
+//! runtime configuration. This can introduce challenges, because the type of a
+//! layered [`Subscriber`] depends on which layers are added to it: if an `if`
+//! or `match` expression adds some [`Layer`] implementation in one branch,
+//! and other layers in another, the [`Subscriber`] values returned by those
+//! branches will have different types. For example, the following _will not_
+//! work:
+//!
+//! ```compile_fail
+//! # fn docs() -> Result<(), Box<dyn std::error::Error + 'static>> {
+//! # struct Config {
+//! # is_prod: bool,
+//! # path: &'static str,
+//! # }
+//! # let cfg = Config { is_prod: false, path: "debug.log" };
+//! use std::fs::File;
+//! use tracing_subscriber::{Registry, prelude::*};
+//!
+//! let stdout_log = tracing_subscriber::fmt::layer().pretty();
+//! let subscriber = Registry::default().with(stdout_log);
+//!
+//! // The compile error will occur here because the if and else
+//! // branches have different (and therefore incompatible) types.
+//! let subscriber = if cfg.is_prod {
+//! let file = File::create(cfg.path)?;
+//! let layer = tracing_subscriber::fmt::layer()
+//! .json()
+//! .with_writer(Arc::new(file));
+//! layer.with(subscriber)
+//! } else {
+//! layer
+//! };
+//!
+//! tracing::subscriber::set_global_default(subscriber)
+//! .expect("Unable to set global subscriber");
+//! # Ok(()) }
+//! ```
+//!
+//! However, a [`Layer`] wrapped in an [`Option`] [also implements the `Layer`
+//! trait][option-impl]. This allows individual layers to be enabled or disabled at
+//! runtime while always producing a [`Subscriber`] of the same type. For
+//! example:
+//!
+//! ```
+//! # fn docs() -> Result<(), Box<dyn std::error::Error + 'static>> {
+//! # struct Config {
+//! # is_prod: bool,
+//! # path: &'static str,
+//! # }
+//! # let cfg = Config { is_prod: false, path: "debug.log" };
+//! use std::fs::File;
+//! use tracing_subscriber::{Registry, prelude::*};
+//!
+//! let stdout_log = tracing_subscriber::fmt::layer().pretty();
+//! let subscriber = Registry::default().with(stdout_log);
+//!
+//! // if `cfg.is_prod` is true, also log JSON-formatted logs to a file.
+//! let json_log = if cfg.is_prod {
+//! let file = File::create(cfg.path)?;
+//! let json_log = tracing_subscriber::fmt::layer()
+//! .json()
+//! .with_writer(file);
+//! Some(json_log)
+//! } else {
+//! None
+//! };
+//!
+//! // If `cfg.is_prod` is false, then `json` will be `None`, and this layer
+//! // will do nothing. However, the subscriber will still have the same type
+//! // regardless of whether the `Option`'s value is `None` or `Some`.
+//! let subscriber = subscriber.with(json_log);
+//!
+//! tracing::subscriber::set_global_default(subscriber)
+//! .expect("Unable to set global subscriber");
+//! # Ok(()) }
+//! ```
+//!
+//! If a [`Layer`] may be one of several different types, note that [`Box<dyn
+//! Layer<S> + Send + Sync>` implements `Layer`][box-impl].
+//! This may be used to erase the type of a [`Layer`].
+//!
+//! For example, a function that configures a [`Layer`] to log to one of
+//! several outputs might return a `Box<dyn Layer<S> + Send + Sync + 'static>`:
+//! ```
+//! use tracing_subscriber::{
+//! Layer,
+//! registry::LookupSpan,
+//! prelude::*,
+//! };
+//! use std::{path::PathBuf, fs::File, io};
+//!
+//! /// Configures whether logs are emitted to a file, to stdout, or to stderr.
+//! pub enum LogConfig {
+//! File(PathBuf),
+//! Stdout,
+//! Stderr,
+//! }
+//!
+//! impl LogConfig {
+//! pub fn layer<S>(self) -> Box<dyn Layer<S> + Send + Sync + 'static>
+//! where
+//! S: tracing_core::Subscriber,
+//! for<'a> S: LookupSpan<'a>,
+//! {
+//! // Shared configuration regardless of where logs are output to.
+//! let fmt = tracing_subscriber::fmt::layer()
+//! .with_target(true)
+//! .with_thread_names(true);
+//!
+//! // Configure the writer based on the desired log target:
+//! match self {
+//! LogConfig::File(path) => {
+//! let file = File::create(path).expect("failed to create log file");
+//! Box::new(fmt.with_writer(file))
+//! },
+//! LogConfig::Stdout => Box::new(fmt.with_writer(io::stdout)),
+//! LogConfig::Stderr => Box::new(fmt.with_writer(io::stderr)),
+//! }
+//! }
+//! }
+//!
+//! let config = LogConfig::Stdout;
+//! tracing_subscriber::registry()
+//! .with(config.layer())
+//! .init();
+//! ```
+//!
+//! The [`Layer::boxed`] method is provided to make boxing a `Layer`
+//! more convenient, but [`Box::new`] may be used as well.
+//!
+//! When the number of `Layer`s varies at runtime, note that a
+//! [`Vec<L> where L: Layer` also implements `Layer`][vec-impl]. This
+//! can be used to add a variable number of `Layer`s to a `Subscriber`:
+//!
+//! ```
+//! use tracing_subscriber::{Layer, prelude::*};
+//! struct MyLayer {
+//! // ...
+//! }
+//! # impl MyLayer { fn new() -> Self { Self {} }}
+//!
+//! impl<S: tracing_core::Subscriber> Layer<S> for MyLayer {
+//! // ...
+//! }
+//!
+//! /// Returns how many layers we need
+//! fn how_many_layers() -> usize {
+//! // ...
+//! # 3
+//! }
+//!
+//! // Create a variable-length `Vec` of layers
+//! let mut layers = Vec::new();
+//! for _ in 0..how_many_layers() {
+//! layers.push(MyLayer::new());
+//! }
+//!
+//! tracing_subscriber::registry()
+//! .with(layers)
+//! .init();
+//! ```
+//!
+//! If a variable number of `Layer` is needed and those `Layer`s have
+//! different types, a `Vec` of [boxed `Layer` trait objects][box-impl] may
+//! be used. For example:
+//!
+//! ```
+//! use tracing_subscriber::{filter::LevelFilter, Layer, prelude::*};
+//! use std::fs::File;
+//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
+//! struct Config {
+//! enable_log_file: bool,
+//! enable_stdout: bool,
+//! enable_stderr: bool,
+//! // ...
+//! }
+//! # impl Config {
+//! # fn from_config_file()-> Result<Self, Box<dyn std::error::Error>> {
+//! # // don't enable the log file so that the example doesn't actually create it
+//! # Ok(Self { enable_log_file: false, enable_stdout: true, enable_stderr: true })
+//! # }
+//! # }
+//!
+//! let cfg = Config::from_config_file()?;
+//!
+//! // Based on our dynamically loaded config file, create any number of layers:
+//! let mut layers = Vec::new();
+//!
+//! if cfg.enable_log_file {
+//! let file = File::create("myapp.log")?;
+//! let layer = tracing_subscriber::fmt::layer()
+//! .with_thread_names(true)
+//! .with_target(true)
+//! .json()
+//! .with_writer(file)
+//! // Box the layer as a type-erased trait object, so that it can
+//! // be pushed to the `Vec`.
+//! .boxed();
+//! layers.push(layer);
+//! }
+//!
+//! if cfg.enable_stdout {
+//! let layer = tracing_subscriber::fmt::layer()
+//! .pretty()
+//! .with_filter(LevelFilter::INFO)
+//! // Box the layer as a type-erased trait object, so that it can
+//! // be pushed to the `Vec`.
+//! .boxed();
+//! layers.push(layer);
+//! }
+//!
+//! if cfg.enable_stdout {
+//! let layer = tracing_subscriber::fmt::layer()
+//! .with_target(false)
+//! .with_filter(LevelFilter::WARN)
+//! // Box the layer as a type-erased trait object, so that it can
+//! // be pushed to the `Vec`.
+//! .boxed();
+//! layers.push(layer);
+//! }
+//!
+//! tracing_subscriber::registry()
+//! .with(layers)
+//! .init();
+//!# Ok(()) }
+//! ```
+//!
+//! Finally, if the number of layers _changes_ at runtime, a `Vec` of
+//! subscribers can be used alongside the [`reload`](crate::reload) module to
+//! add or remove subscribers dynamically at runtime.
+//!
+//! [option-impl]: Layer#impl-Layer<S>-for-Option<L>
+//! [box-impl]: Layer#impl-Layer%3CS%3E-for-Box%3Cdyn%20Layer%3CS%3E%20+%20Send%20+%20Sync%3E
+//! [vec-impl]: Layer#impl-Layer<S>-for-Vec<L>
//! [prelude]: crate::prelude
//!
-//! ## Recording Traces
+//! # Recording Traces
//!
//! The [`Layer`] trait defines a set of methods for consuming notifications from
//! tracing instrumentation, which are generally equivalent to the similarly
@@ -146,7 +382,7 @@
//! information provided by the wrapped subscriber (such as [the current span])
//! to the layer.
//!
-//! ## Filtering with `Layer`s
+//! # Filtering with `Layer`s
//!
//! As well as strategies for handling trace events, the `Layer` trait may also
//! be used to represent composable _filters_. This allows the determination of
@@ -158,7 +394,7 @@
//! combined with _per-layer filters_ that control what spans and events are
//! recorded by those layers.
//!
-//! ### Global Filtering
+//! ## Global Filtering
//!
//! A `Layer` that implements a filtering strategy should override the
//! [`register_callsite`] and/or [`enabled`] methods. It may also choose to implement
@@ -179,7 +415,29 @@
//! [`Interest::never()`] from its [`register_callsite`] method, filter
//! evaluation will short-circuit and the span or event will be disabled.
//!
-//! ### Per-Layer Filtering
+//! ### Enabling Interest
+//!
+//! Whenever an tracing event (or span) is emitted, it goes through a number of
+//! steps to determine how and how much it should be processed. The earlier an
+//! event is disabled, the less work has to be done to process the event, so
+//! `Layer`s that implement filtering should attempt to disable unwanted
+//! events as early as possible. In order, each event checks:
+//!
+//! - [`register_callsite`], once per callsite (roughly: once per time that
+//! `event!` or `span!` is written in the source code; this is cached at the
+//! callsite). See [`Subscriber::register_callsite`] and
+//! [`tracing_core::callsite`] for a summary of how this behaves.
+//! - [`enabled`], once per emitted event (roughly: once per time that `event!`
+//! or `span!` is *executed*), and only if `register_callsite` regesters an
+//! [`Interest::sometimes`]. This is the main customization point to globally
+//! filter events based on their [`Metadata`]. If an event can be disabled
+//! based only on [`Metadata`], it should be, as this allows the construction
+//! of the actual `Event`/`Span` to be skipped.
+//! - For events only (and not spans), [`event_enabled`] is called just before
+//! processing the event. This gives layers one last chance to say that
+//! an event should be filtered out, now that the event's fields are known.
+//!
+//! ## Per-Layer Filtering
//!
//! **Note**: per-layer filtering APIs currently require the [`"registry"` crate
//! feature flag][feat] to be enabled.
@@ -393,94 +651,16 @@
//! # Ok(()) }
//! ```
//!
-//! ## Runtime Configuration With Layers
-//!
-//! In some cases, a particular [`Layer`] may be enabled or disabled based on
-//! runtime configuration. This can introduce challenges, because the type of a
-//! layered [`Subscriber`] depends on which layers are added to it: if an `if`
-//! or `match` expression adds some [`Layer`]s in one branch and other layers
-//! in another, the [`Subscriber`] values returned by those branches will have
-//! different types. For example, the following _will not_ work:
-//!
-//! ```compile_fail
-//! # fn docs() -> Result<(), Box<dyn std::error::Error + 'static>> {
-//! # struct Config {
-//! # is_prod: bool,
-//! # path: &'static str,
-//! # }
-//! # let cfg = Config { is_prod: false, path: "debug.log" };
-//! use std::{fs::File, sync::Arc};
-//! use tracing_subscriber::{Registry, prelude::*};
-//!
-//! let stdout_log = tracing_subscriber::fmt::layer().pretty();
-//! let subscriber = Registry::default().with(stdout_log);
-//!
-//! // The compile error will occur here because the if and else
-//! // branches have different (and therefore incompatible) types.
-//! let subscriber = if cfg.is_prod {
-//! let file = File::create(cfg.path)?;
-//! let layer = tracing_subscriber::fmt::layer()
-//! .json()
-//! .with_writer(Arc::new(file));
-//! subscriber.with(layer)
-//! } else {
-//! subscriber
-//! };
-//!
-//! tracing::subscriber::set_global_default(subscriber)
-//! .expect("Unable to set global subscriber");
-//! # Ok(()) }
-//! ```
-//!
-//! However, a [`Layer`] wrapped in an [`Option`] [also implements the `Layer`
-//! trait][option-impl]. This allows individual layers to be enabled or disabled at
-//! runtime while always producing a [`Subscriber`] of the same type. For
-//! example:
-//!
-//! ```
-//! # fn docs() -> Result<(), Box<dyn std::error::Error + 'static>> {
-//! # struct Config {
-//! # is_prod: bool,
-//! # path: &'static str,
-//! # }
-//! # let cfg = Config { is_prod: false, path: "debug.log" };
-//! use std::{fs::File, sync::Arc};
-//! use tracing_subscriber::{Registry, prelude::*};
-//!
-//! let stdout_log = tracing_subscriber::fmt::layer().pretty();
-//! let subscriber = Registry::default().with(stdout_log);
-//!
-//! // if `cfg.is_prod` is true, also log JSON-formatted logs to a file.
-//! let json_log = if cfg.is_prod {
-//! let file = File::create(cfg.path)?;
-//! let json_log = tracing_subscriber::fmt::layer()
-//! .json()
-//! .with_writer(Arc::new(file));
-//! Some(json_log)
-//! } else {
-//! None
-//! };
-//!
-//! // If `cfg.is_prod` is false, then `json` will be `None`, and this layer
-//! // will do nothing. However, the subscriber will still have the same type
-//! // regardless of whether the `Option`'s value is `None` or `Some`.
-//! let subscriber = subscriber.with(json_log);
-//!
-//! tracing::subscriber::set_global_default(subscriber)
-//! .expect("Unable to set global subscriber");
-//! # Ok(()) }
-//! ```
-//!
-//! [`Subscriber`]: https://docs.rs/tracing-core/latest/tracing_core/subscriber/trait.Subscriber.html
-//! [span IDs]: https://docs.rs/tracing-core/latest/tracing_core/span/struct.Id.html
+//! [`Subscriber`]: tracing_core::subscriber::Subscriber
+//! [span IDs]: tracing_core::span::Id
//! [the current span]: Context::current_span
//! [`register_callsite`]: Layer::register_callsite
//! [`enabled`]: Layer::enabled
+//! [`event_enabled`]: Layer::event_enabled
//! [`on_enter`]: Layer::on_enter
//! [`Layer::register_callsite`]: Layer::register_callsite
//! [`Layer::enabled`]: Layer::enabled
-//! [`Interest::never()`]: https://docs.rs/tracing-core/latest/tracing_core/subscriber/struct.Interest.html#method.never
-//! [option-impl]: crate::layer::Layer#impl-Layer<S>-for-Option<L>
+//! [`Interest::never()`]: tracing_core::subscriber::Interest::never()
//! [`Filtered`]: crate::filter::Filtered
//! [`filter`]: crate::filter
//! [`Targets`]: crate::filter::Targets
@@ -498,7 +678,7 @@ use tracing_core::{
metadata::Metadata,
span,
subscriber::{Interest, Subscriber},
- Event, LevelFilter,
+ Dispatch, Event, LevelFilter,
};
use core::any::TypeId;
@@ -531,6 +711,31 @@ where
S: Subscriber,
Self: 'static,
{
+ /// Performs late initialization when installing this layer as a
+ /// [`Subscriber`].
+ ///
+ /// ## Avoiding Memory Leaks
+ ///
+ /// `Layer`s should not store the [`Dispatch`] pointing to the [`Subscriber`]
+ /// that they are a part of. Because the `Dispatch` owns the `Subscriber`,
+ /// storing the `Dispatch` within the `Subscriber` will create a reference
+ /// count cycle, preventing the `Dispatch` from ever being dropped.
+ ///
+ /// Instead, when it is necessary to store a cyclical reference to the
+ /// `Dispatch` within a `Layer`, use [`Dispatch::downgrade`] to convert a
+ /// `Dispatch` into a [`WeakDispatch`]. This type is analogous to
+ /// [`std::sync::Weak`], and does not create a reference count cycle. A
+ /// [`WeakDispatch`] can be stored within a subscriber without causing a
+ /// memory leak, and can be [upgraded] into a `Dispatch` temporarily when
+ /// the `Dispatch` must be accessed by the subscriber.
+ ///
+ /// [`WeakDispatch`]: tracing_core::dispatcher::WeakDispatch
+ /// [upgraded]: tracing_core::dispatcher::WeakDispatch::upgrade
+ /// [`Subscriber`]: tracing_core::Subscriber
+ fn on_register_dispatch(&self, collector: &Dispatch) {
+ let _ = collector;
+ }
+
/// Performs late initialization when attaching a `Layer` to a
/// [`Subscriber`].
///
@@ -592,15 +797,15 @@ where
/// globally enable or disable those callsites, it should always return
/// [`Interest::always()`].
///
- /// [`Interest`]: https://docs.rs/tracing-core/latest/tracing_core/struct.Interest.html
- /// [`Subscriber::register_callsite`]: https://docs.rs/tracing-core/latest/tracing_core/trait.Subscriber.html#method.register_callsite
- /// [`Interest::never()`]: https://docs.rs/tracing-core/latest/tracing_core/subscriber/struct.Interest.html#method.never
- /// [`Interest::always()`]: https://docs.rs/tracing-core/latest/tracing_core/subscriber/struct.Interest.html#method.always
- /// [`self.enabled`]: #method.enabled
- /// [`Layer::enabled`]: #method.enabled
- /// [`on_event`]: #method.on_event
- /// [`on_enter`]: #method.on_enter
- /// [`on_exit`]: #method.on_exit
+ /// [`Interest`]: tracing_core::Interest
+ /// [`Subscriber::register_callsite`]: tracing_core::Subscriber::register_callsite()
+ /// [`Interest::never()`]: tracing_core::subscriber::Interest::never()
+ /// [`Interest::always()`]: tracing_core::subscriber::Interest::always()
+ /// [`self.enabled`]: Layer::enabled()
+ /// [`Layer::enabled`]: Layer::enabled()
+ /// [`on_event`]: Layer::on_event()
+ /// [`on_enter`]: Layer::on_enter()
+ /// [`on_exit`]: Layer::on_exit()
/// [the trait-level documentation]: #filtering-with-layers
fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
if self.enabled(metadata, Context::none()) {
@@ -635,13 +840,12 @@ where
/// See [the trait-level documentation] for more information on filtering
/// with `Layer`s.
///
- /// [`Interest`]: https://docs.rs/tracing-core/latest/tracing_core/struct.Interest.html
- /// [`Context`]: ../struct.Context.html
- /// [`Subscriber::enabled`]: https://docs.rs/tracing-core/latest/tracing_core/trait.Subscriber.html#method.enabled
- /// [`Layer::register_callsite`]: #method.register_callsite
- /// [`on_event`]: #method.on_event
- /// [`on_enter`]: #method.on_enter
- /// [`on_exit`]: #method.on_exit
+ /// [`Interest`]: tracing_core::Interest
+ /// [`Subscriber::enabled`]: tracing_core::Subscriber::enabled()
+ /// [`Layer::register_callsite`]: Layer::register_callsite()
+ /// [`on_event`]: Layer::on_event()
+ /// [`on_enter`]: Layer::on_enter()
+ /// [`on_exit`]: Layer::on_exit()
/// [the trait-level documentation]: #filtering-with-layers
fn enabled(&self, metadata: &Metadata<'_>, ctx: Context<'_, S>) -> bool {
let _ = (metadata, ctx);
@@ -676,6 +880,31 @@ where
// seems like a good future-proofing measure as it may grow other methods later...
fn on_follows_from(&self, _span: &span::Id, _follows: &span::Id, _ctx: Context<'_, S>) {}
+ /// Called before [`on_event`], to determine if `on_event` should be called.
+ ///
+ /// <div class="example-wrap" style="display:inline-block">
+ /// <pre class="ignore" style="white-space:normal;font:inherit;">
+ ///
+ /// **Note**: This method determines whether an event is globally enabled,
+ /// *not* whether the individual `Layer` will be notified about the
+ /// event. This is intended to be used by `Layer`s that implement
+ /// filtering for the entire stack. `Layer`s which do not wish to be
+ /// notified about certain events but do not wish to globally disable them
+ /// should ignore those events in their [on_event][Self::on_event].
+ ///
+ /// </pre></div>
+ ///
+ /// See [the trait-level documentation] for more information on filtering
+ /// with `Layer`s.
+ ///
+ /// [`on_event`]: Self::on_event
+ /// [`Interest`]: tracing_core::Interest
+ /// [the trait-level documentation]: #filtering-with-layers
+ #[inline] // collapse this to a constant please mrs optimizer
+ fn event_enabled(&self, _event: &Event<'_>, _ctx: Context<'_, S>) -> bool {
+ true
+ }
+
/// Notifies this layer that an event has occurred.
fn on_event(&self, _event: &Event<'_>, _ctx: Context<'_, S>) {}
@@ -840,7 +1069,7 @@ where
/// .with_subscriber(MySubscriber::new());
///```
///
- /// [`Subscriber`]: https://docs.rs/tracing-core/latest/tracing_core/trait.Subscriber.html
+ /// [`Subscriber`]: tracing_core::Subscriber
fn with_subscriber(mut self, mut inner: S) -> Layered<Self, S>
where
Self: Sized,
@@ -857,7 +1086,7 @@ where
/// per-layer filtering.
///
/// [`Filtered`]: crate::filter::Filtered
- /// [plf]: #per-layer-filtering
+ /// [plf]: crate::layer#per-layer-filtering
#[cfg(all(feature = "registry", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "registry", feature = "std"))))]
fn with_filter<F>(self, filter: F) -> filter::Filtered<Self, F, S>
@@ -868,6 +1097,131 @@ where
filter::Filtered::new(self, filter)
}
+ /// Erases the type of this [`Layer`], returning a [`Box`]ed `dyn
+ /// Layer` trait object.
+ ///
+ /// This can be used when a function returns a `Layer` which may be of
+ /// one of several types, or when a `Layer` subscriber has a very long type
+ /// signature.
+ ///
+ /// # Examples
+ ///
+ /// The following example will *not* compile, because the value assigned to
+ /// `log_layer` may have one of several different types:
+ ///
+ /// ```compile_fail
+ /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+ /// use tracing_subscriber::{Layer, filter::LevelFilter, prelude::*};
+ /// use std::{path::PathBuf, fs::File, io};
+ ///
+ /// /// Configures whether logs are emitted to a file, to stdout, or to stderr.
+ /// pub enum LogConfig {
+ /// File(PathBuf),
+ /// Stdout,
+ /// Stderr,
+ /// }
+ ///
+ /// let config = // ...
+ /// # LogConfig::Stdout;
+ ///
+ /// // Depending on the config, construct a layer of one of several types.
+ /// let log_layer = match config {
+ /// // If logging to a file, use a maximally-verbose configuration.
+ /// LogConfig::File(path) => {
+ /// let file = File::create(path)?;
+ /// tracing_subscriber::fmt::layer()
+ /// .with_thread_ids(true)
+ /// .with_thread_names(true)
+ /// // Selecting the JSON logging format changes the layer's
+ /// // type.
+ /// .json()
+ /// .with_span_list(true)
+ /// // Setting the writer to use our log file changes the
+ /// // layer's type again.
+ /// .with_writer(file)
+ /// },
+ ///
+ /// // If logging to stdout, use a pretty, human-readable configuration.
+ /// LogConfig::Stdout => tracing_subscriber::fmt::layer()
+ /// // Selecting the "pretty" logging format changes the
+ /// // layer's type!
+ /// .pretty()
+ /// .with_writer(io::stdout)
+ /// // Add a filter based on the RUST_LOG environment variable;
+ /// // this changes the type too!
+ /// .and_then(tracing_subscriber::EnvFilter::from_default_env()),
+ ///
+ /// // If logging to stdout, only log errors and warnings.
+ /// LogConfig::Stderr => tracing_subscriber::fmt::layer()
+ /// // Changing the writer changes the layer's type
+ /// .with_writer(io::stderr)
+ /// // Only log the `WARN` and `ERROR` levels. Adding a filter
+ /// // changes the layer's type to `Filtered<LevelFilter, ...>`.
+ /// .with_filter(LevelFilter::WARN),
+ /// };
+ ///
+ /// tracing_subscriber::registry()
+ /// .with(log_layer)
+ /// .init();
+ /// # Ok(()) }
+ /// ```
+ ///
+ /// However, adding a call to `.boxed()` after each match arm erases the
+ /// layer's type, so this code *does* compile:
+ ///
+ /// ```
+ /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+ /// # use tracing_subscriber::{Layer, filter::LevelFilter, prelude::*};
+ /// # use std::{path::PathBuf, fs::File, io};
+ /// # pub enum LogConfig {
+ /// # File(PathBuf),
+ /// # Stdout,
+ /// # Stderr,
+ /// # }
+ /// # let config = LogConfig::Stdout;
+ /// let log_layer = match config {
+ /// LogConfig::File(path) => {
+ /// let file = File::create(path)?;
+ /// tracing_subscriber::fmt::layer()
+ /// .with_thread_ids(true)
+ /// .with_thread_names(true)
+ /// .json()
+ /// .with_span_list(true)
+ /// .with_writer(file)
+ /// // Erase the type by boxing the layer
+ /// .boxed()
+ /// },
+ ///
+ /// LogConfig::Stdout => tracing_subscriber::fmt::layer()
+ /// .pretty()
+ /// .with_writer(io::stdout)
+ /// .and_then(tracing_subscriber::EnvFilter::from_default_env())
+ /// // Erase the type by boxing the layer
+ /// .boxed(),
+ ///
+ /// LogConfig::Stderr => tracing_subscriber::fmt::layer()
+ /// .with_writer(io::stderr)
+ /// .with_filter(LevelFilter::WARN)
+ /// // Erase the type by boxing the layer
+ /// .boxed(),
+ /// };
+ ///
+ /// tracing_subscriber::registry()
+ /// .with(log_layer)
+ /// .init();
+ /// # Ok(()) }
+ /// ```
+ #[cfg(any(feature = "alloc", feature = "std"))]
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
+ fn boxed(self) -> Box<dyn Layer<S> + Send + Sync + 'static>
+ where
+ Self: Sized,
+ Self: Layer<S> + Send + Sync + 'static,
+ S: Subscriber,
+ {
+ Box::new(self)
+ }
+
#[doc(hidden)]
unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
if id == TypeId::of::<Self>() {
@@ -880,6 +1234,7 @@ where
feature! {
#![all(feature = "registry", feature = "std")]
+
/// A per-[`Layer`] filter that determines whether a span or event is enabled
/// for an individual layer.
///
@@ -1022,6 +1377,26 @@ feature! {
Interest::sometimes()
}
+ /// Called before the filtered [`Layer]'s [`on_event`], to determine if
+ /// `on_event` should be called.
+ ///
+ /// This gives a chance to filter events based on their fields. Note,
+ /// however, that this *does not* override [`enabled`], and is not even
+ /// called if [`enabled`] returns `false`.
+ ///
+ /// ## Default Implementation
+ ///
+ /// By default, this method returns `true`, indicating that no events are
+ /// filtered out based on their fields.
+ ///
+ /// [`enabled`]: crate::layer::Filter::enabled
+ /// [`on_event`]: crate::layer::Layer::on_event
+ #[inline] // collapse this to a constant please mrs optimizer
+ fn event_enabled(&self, event: &Event<'_>, cx: &Context<'_, S>) -> bool {
+ let _ = (event, cx);
+ true
+ }
+
/// Returns an optional hint of the highest [verbosity level][level] that
/// this `Filter` will enable.
///
@@ -1054,6 +1429,51 @@ feature! {
fn max_level_hint(&self) -> Option<LevelFilter> {
None
}
+
+ /// Notifies this filter that a new span was constructed with the given
+ /// `Attributes` and `Id`.
+ ///
+ /// By default, this method does nothing. `Filter` implementations that
+ /// need to be notified when new spans are created can override this
+ /// method.
+ fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) {
+ let _ = (attrs, id, ctx);
+ }
+
+
+ /// Notifies this filter that a span with the given `Id` recorded the given
+ /// `values`.
+ ///
+ /// By default, this method does nothing. `Filter` implementations that
+ /// need to be notified when new spans are created can override this
+ /// method.
+ fn on_record(&self, id: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) {
+ let _ = (id, values, ctx);
+ }
+
+ /// Notifies this filter that a span with the given ID was entered.
+ ///
+ /// By default, this method does nothing. `Filter` implementations that
+ /// need to be notified when a span is entered can override this method.
+ fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
+ let _ = (id, ctx);
+ }
+
+ /// Notifies this filter that a span with the given ID was exited.
+ ///
+ /// By default, this method does nothing. `Filter` implementations that
+ /// need to be notified when a span is exited can override this method.
+ fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) {
+ let _ = (id, ctx);
+ }
+
+ /// Notifies this filter that a span with the given ID has been closed.
+ ///
+ /// By default, this method does nothing. `Filter` implementations that
+ /// need to be notified when a span is closed can override this method.
+ fn on_close(&self, id: span::Id, ctx: Context<'_, S>) {
+ let _ = (id, ctx);
+ }
}
}
@@ -1077,6 +1497,47 @@ pub struct Identity {
// === impl Layer ===
+#[derive(Clone, Copy)]
+pub(crate) struct NoneLayerMarker(());
+static NONE_LAYER_MARKER: NoneLayerMarker = NoneLayerMarker(());
+
+/// Is a type implementing `Layer` `Option::<_>::None`?
+pub(crate) fn layer_is_none<L, S>(layer: &L) -> bool
+where
+ L: Layer<S>,
+ S: Subscriber,
+{
+ unsafe {
+ // Safety: we're not actually *doing* anything with this pointer ---
+ // this only care about the `Option`, which is essentially being used
+ // as a bool. We can rely on the pointer being valid, because it is
+ // a crate-private type, and is only returned by the `Layer` impl
+ // for `Option`s. However, even if the layer *does* decide to be
+ // evil and give us an invalid pointer here, that's fine, because we'll
+ // never actually dereference it.
+ layer.downcast_raw(TypeId::of::<NoneLayerMarker>())
+ }
+ .is_some()
+}
+
+/// Is a type implementing `Subscriber` `Option::<_>::None`?
+pub(crate) fn subscriber_is_none<S>(subscriber: &S) -> bool
+where
+ S: Subscriber,
+{
+ unsafe {
+ // Safety: we're not actually *doing* anything with this pointer ---
+ // this only care about the `Option`, which is essentially being used
+ // as a bool. We can rely on the pointer being valid, because it is
+ // a crate-private type, and is only returned by the `Layer` impl
+ // for `Option`s. However, even if the subscriber *does* decide to be
+ // evil and give us an invalid pointer here, that's fine, because we'll
+ // never actually dereference it.
+ subscriber.downcast_raw(TypeId::of::<NoneLayerMarker>())
+ }
+ .is_some()
+}
+
impl<L, S> Layer<S> for Option<L>
where
L: Layer<S>,
@@ -1115,7 +1576,11 @@ where
fn max_level_hint(&self) -> Option<LevelFilter> {
match self {
Some(ref inner) => inner.max_level_hint(),
- None => None,
+ None => {
+ // There is no inner layer, so this layer will
+ // never enable anything.
+ Some(LevelFilter::OFF)
+ }
}
}
@@ -1134,6 +1599,14 @@ where
}
#[inline]
+ fn event_enabled(&self, event: &Event<'_>, ctx: Context<'_, S>) -> bool {
+ match self {
+ Some(ref inner) => inner.event_enabled(event, ctx),
+ None => true,
+ }
+ }
+
+ #[inline]
fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
if let Some(ref inner) = self {
inner.on_event(event, ctx);
@@ -1173,6 +1646,8 @@ where
unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
if id == TypeId::of::<Self>() {
Some(self as *const _ as *const ())
+ } else if id == TypeId::of::<NoneLayerMarker>() && self.is_none() {
+ Some(&NONE_LAYER_MARKER as *const _ as *const ())
} else {
self.as_ref().and_then(|inner| inner.downcast_raw(id))
}
@@ -1181,10 +1656,17 @@ where
feature! {
#![any(feature = "std", feature = "alloc")]
+ #[cfg(not(feature = "std"))]
+ use alloc::vec::Vec;
macro_rules! layer_impl_body {
() => {
#[inline]
+ fn on_register_dispatch(&self, subscriber: &Dispatch) {
+ self.deref().on_register_dispatch(subscriber);
+ }
+
+ #[inline]
fn on_layer(&mut self, subscriber: &mut S) {
self.deref_mut().on_layer(subscriber);
}
@@ -1220,6 +1702,11 @@ feature! {
}
#[inline]
+ fn event_enabled(&self, event: &Event<'_>, ctx: Context<'_, S>) -> bool {
+ self.deref().event_enabled(event, ctx)
+ }
+
+ #[inline]
fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
self.deref().on_event(event, ctx)
}
@@ -1266,6 +1753,125 @@ feature! {
{
layer_impl_body! {}
}
+
+
+
+ impl<S, L> Layer<S> for Vec<L>
+ where
+ L: Layer<S>,
+ S: Subscriber,
+ {
+
+ fn on_layer(&mut self, subscriber: &mut S) {
+ for l in self {
+ l.on_layer(subscriber);
+ }
+ }
+
+ fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
+ // Return highest level of interest.
+ let mut interest = Interest::never();
+ for l in self {
+ let new_interest = l.register_callsite(metadata);
+ if (interest.is_sometimes() && new_interest.is_always())
+ || (interest.is_never() && !new_interest.is_never())
+ {
+ interest = new_interest;
+ }
+ }
+
+ interest
+ }
+
+ fn enabled(&self, metadata: &Metadata<'_>, ctx: Context<'_, S>) -> bool {
+ self.iter().all(|l| l.enabled(metadata, ctx.clone()))
+ }
+
+ fn event_enabled(&self, event: &Event<'_>, ctx: Context<'_, S>) -> bool {
+ self.iter().all(|l| l.event_enabled(event, ctx.clone()))
+ }
+
+ fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, S>) {
+ for l in self {
+ l.on_new_span(attrs, id, ctx.clone());
+ }
+ }
+
+ fn max_level_hint(&self) -> Option<LevelFilter> {
+ // Default to `OFF` if there are no inner layers.
+ let mut max_level = LevelFilter::OFF;
+ for l in self {
+ // NOTE(eliza): this is slightly subtle: if *any* layer
+ // returns `None`, we have to return `None`, assuming there is
+ // no max level hint, since that particular layer cannot
+ // provide a hint.
+ let hint = l.max_level_hint()?;
+ max_level = core::cmp::max(hint, max_level);
+ }
+ Some(max_level)
+ }
+
+ fn on_record(&self, span: &span::Id, values: &span::Record<'_>, ctx: Context<'_, S>) {
+ for l in self {
+ l.on_record(span, values, ctx.clone())
+ }
+ }
+
+ fn on_follows_from(&self, span: &span::Id, follows: &span::Id, ctx: Context<'_, S>) {
+ for l in self {
+ l.on_follows_from(span, follows, ctx.clone());
+ }
+ }
+
+ fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
+ for l in self {
+ l.on_event(event, ctx.clone());
+ }
+ }
+
+ fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
+ for l in self {
+ l.on_enter(id, ctx.clone());
+ }
+ }
+
+ fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) {
+ for l in self {
+ l.on_exit(id, ctx.clone());
+ }
+ }
+
+ fn on_close(&self, id: span::Id, ctx: Context<'_, S>) {
+ for l in self {
+ l.on_close(id.clone(), ctx.clone());
+ }
+ }
+
+ #[doc(hidden)]
+ unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
+ // If downcasting to `Self`, return a pointer to `self`.
+ if id == TypeId::of::<Self>() {
+ return Some(self as *const _ as *const ());
+ }
+
+ // Someone is looking for per-layer filters. But, this `Vec`
+ // might contain layers with per-layer filters *and*
+ // layers without filters. It should only be treated as a
+ // per-layer-filtered layer if *all* its layers have
+ // per-layer filters.
+ // XXX(eliza): it's a bummer we have to do this linear search every
+ // time. It would be nice if this could be cached, but that would
+ // require replacing the `Vec` impl with an impl for a newtype...
+ if filter::is_plf_downcast_marker(id) && self.iter().any(|s| s.downcast_raw(id).is_none()) {
+ return None;
+ }
+
+ // Otherwise, return the first child of `self` that downcaasts to
+ // the selected type, if any.
+ // XXX(eliza): hope this is reasonable lol
+ self.iter().find_map(|l| l.downcast_raw(id))
+ }
+ }
}
// === impl SubscriberExt ===