mirror of
https://github.com/tokio-rs/tracing.git
synced 2025-10-02 15:24:47 +00:00
subscriber: add Layer::boxed
method (#2026)
## Motivation PR #2023 made the `impl Layer` for boxed `dyn Layer` trait objects actually be useful. One minor annoyance when working with boxed trait objects is that, in some cases, in order to use `Box::new` to erase a `Layer`'s type, it's necessary to add a type annotation like this: ```rust let boxed_layer: Box<dyn Layer<_> + Send + Sync + 'static> = Box::new(some_layer); ``` Because the trait object includes `Send + Sync + 'static`, this is a bit wordy to type out. ## Solution This commit adds a `Layer::boxed` method that takes `Self` and boxes it as a type-erased `dyn Layer` trait object. This can then be chained after a a chain of layer builder methods. Because the `boxed` method _explicitly_ returns a `dyn Layer<_> + ...` trait object, it's not necessary to use a wordy type annotation when using this method.
This commit is contained in:
parent
b21d2369c8
commit
7921a3b466
@ -264,7 +264,9 @@
|
||||
//! .init();
|
||||
//! ```
|
||||
//!
|
||||
//! [prelude]: crate::prelude
|
||||
//! The [`Layer::boxed`] method is provided to make boxing a `Layer`
|
||||
//! more convenient, but [`Box::new`] may be used as well.
|
||||
//!
|
||||
//! [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
|
||||
//! [prelude]: crate::prelude
|
||||
@ -921,6 +923,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>() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user