From 19c15f28402cd1320e26bc19cf65cc3ecc4c4420 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 25 Mar 2022 10:28:29 -0700 Subject: [PATCH 1/5] docs: reorganize "runtime configuration" section this moves the "runtime configuration with subscribers" section into a subsection of "composing subscribers". Signed-off-by: Eliza Weisman --- tracing-subscriber/src/subscribe/mod.rs | 168 ++++++++++++------------ 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/tracing-subscriber/src/subscribe/mod.rs b/tracing-subscriber/src/subscribe/mod.rs index c59f85d33d..9b377ba797 100644 --- a/tracing-subscriber/src/subscribe/mod.rs +++ b/tracing-subscriber/src/subscribe/mod.rs @@ -19,7 +19,7 @@ //! [`Collect`] behavior; it can _observe_ events and spans, but does not //! assign IDs. //! -//! ## Composing Subscribers +//! # Composing Subscribers //! //! Since a [subscriber] does not implement a complete strategy for collecting //! traces, it must be composed with a [collector] in order to be used. The @@ -137,9 +137,88 @@ //! [`Subscribe::with_collector`] as an implementation detail, as `with_collector` //! calls must be nested, leading to less clear code for the reader. //! +//! ## Runtime Configuration With Subscribers +//! +//! In some cases, a particular [subscriber] may be enabled or disabled based on +//! runtime configuration. This can introduce challenges, because the type of a +//! layered [collector] depends on which subscribers are added to it: if an `if` +//! or `match` expression adds some [`Subscribe`] implementation in one branch, +//! and other subscribers in another, the [collector] values returned by those +//! branches will have different types. For example, the following _will not_ +//! work: +//! +//! ```compile_fail +//! # fn docs() -> Result<(), Box> { +//! # 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::subscriber().pretty(); +//! let collector = Registry::default().with(stdout_log); +//! +//! // The compile error will occur here because the if and else +//! // branches have different (and therefore incompatible) types. +//! let collector = if cfg.is_prod { +//! let file = File::create(cfg.path)?; +//! let collector = tracing_subscriber::fmt::subscriber() +//! .json() +//! .with_writer(Arc::new(file)); +//! collector.with(subscriber) +//! } else { +//! collector +//! }; +//! +//! tracing::collect::set_global_default(collector) +//! .expect("Unable to set global collector"); +//! # Ok(()) } +//! ``` +//! +//! However, a [`Subscribe`] wrapped in an [`Option`] [also implements the `Subscribe` +//! trait][option-impl]. This allows individual layers to be enabled or disabled at +//! runtime while always producing a [`Collect`] of the same type. For +//! example: +//! +//! ``` +//! # fn docs() -> Result<(), Box> { +//! # 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::subscriber().pretty(); +//! let collector = 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::subscriber() +//! .json() +//! .with_writer(file); +//! Some(json_log) +//! } else { +//! None +//! }; +//! +//! // If `cfg.is_prod` is false, then `json` will be `None`, and this subscriber +//! // will do nothing. However, the collector will still have the same type +//! // regardless of whether the `Option`'s value is `None` or `Some`. +//! let collector = collector.with(json_log); +//! +//! tracing::collect::set_global_default(collector) +//! .expect("Unable to set global collector"); +//! # Ok(()) } +//! ``` +//! //! [prelude]: crate::prelude //! -//! ## Recording Traces +//! # Recording Traces //! //! The [`Subscribe`] trait defines a set of methods for consuming notifications from //! tracing instrumentation, which are generally equivalent to the similarly @@ -148,7 +227,7 @@ //! information provided by the wrapped subscriber (such as [the current span]) //! to the subscriber. //! -//! ## Filtering with `Subscribers`s +//! # Filtering with `Subscriber`s //! //! As well as strategies for handling trace events, the `Subscribe` trait may also //! be used to represent composable _filters_. This allows the determination of @@ -160,7 +239,7 @@ //! combined with _per-subscriber filters_ that control what spans and events are //! recorded by those subscribers. //! -//! ### Global Filtering +//! ## Global Filtering //! //! A `Subscribe` that implements a filtering strategy should override the //! [`register_callsite`] and/or [`enabled`] methods. It may also choose to implement @@ -181,7 +260,7 @@ //! [`Interest::never()`] from its [`register_callsite`] method, filter //! evaluation will short-circuit and the span or event will be disabled. //! -//! ### Per-Subscriber Filtering +//! ## Per-Subscriber Filtering //! //! **Note**: per-subscriber filtering APIs currently require the [`"registry"` crate //! feature flag][feat] to be enabled. @@ -396,85 +475,6 @@ //! # Ok(()) } //! ``` //! -//! -//! ## Runtime Configuration With Subscribers -//! -//! In some cases, a particular [subscriber] may be enabled or disabled based on -//! runtime configuration. This can introduce challenges, because the type of a -//! layered [collector] depends on which subscribers are added to it: if an `if` -//! or `match` expression adds some [`Subscribe`] implementation in one branch, -//! and other subscribers in another, the [collector] values returned by those -//! branches will have different types. For example, the following _will not_ -//! work: -//! -//! ```compile_fail -//! # fn docs() -> Result<(), Box> { -//! # 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::subscriber().pretty(); -//! let collector = Registry::default().with(stdout_log); -//! -//! // The compile error will occur here because the if and else -//! // branches have different (and therefore incompatible) types. -//! let collector = if cfg.is_prod { -//! let file = File::create(cfg.path)?; -//! let collector = tracing_subscriber::fmt::subscriber() -//! .json() -//! .with_writer(Arc::new(file)); -//! collector.with(subscriber) -//! } else { -//! collector -//! }; -//! -//! tracing::collect::set_global_default(collector) -//! .expect("Unable to set global collector"); -//! # Ok(()) } -//! ``` -//! -//! However, a [`Subscribe`] wrapped in an [`Option`] [also implements the `Subscribe` -//! trait][option-impl]. This allows individual layers to be enabled or disabled at -//! runtime while always producing a [`Collect`] of the same type. For -//! example: -//! -//! ``` -//! # fn docs() -> Result<(), Box> { -//! # 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::subscriber().pretty(); -//! let collector = 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::subscriber() -//! .json() -//! .with_writer(file); -//! Some(json_log) -//! } else { -//! None -//! }; -//! -//! // If `cfg.is_prod` is false, then `json` will be `None`, and this subscriber -//! // will do nothing. However, the collector will still have the same type -//! // regardless of whether the `Option`'s value is `None` or `Some`. -//! let collector = collector.with(json_log); -//! -//! tracing::collect::set_global_default(collector) -//! .expect("Unable to set global collector"); -//! # Ok(()) } -//! ``` //! [subscriber]: Subscribe //! [`Collect`]:tracing_core::Collect //! [collector]: tracing_core::Collect From a6e3574edf1fcd374a3c0e96a4bdc95efe61e5a6 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 25 Mar 2022 11:00:34 -0700 Subject: [PATCH 2/5] make `Subscribe` impl for `Box` not useless Signed-off-by: Eliza Weisman --- tracing-subscriber/src/subscribe/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tracing-subscriber/src/subscribe/mod.rs b/tracing-subscriber/src/subscribe/mod.rs index 9b377ba797..5cc69cef8f 100644 --- a/tracing-subscriber/src/subscribe/mod.rs +++ b/tracing-subscriber/src/subscribe/mod.rs @@ -1282,6 +1282,13 @@ feature! { subscriber_impl_body! {} } + impl Subscribe for Box + Send + Sync + 'static> + where + C: Collect, + { + subscriber_impl_body! {} + } + impl Subscribe for Box> where C: Collect, From 3413ef2a4d8f98429b18779fcfba0d08b7e40233 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 25 Mar 2022 11:03:27 -0700 Subject: [PATCH 3/5] add example using boxed erased subscriber Signed-off-by: Eliza Weisman --- tracing-subscriber/src/subscribe/mod.rs | 51 +++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tracing-subscriber/src/subscribe/mod.rs b/tracing-subscriber/src/subscribe/mod.rs index 5cc69cef8f..507f9bb1be 100644 --- a/tracing-subscriber/src/subscribe/mod.rs +++ b/tracing-subscriber/src/subscribe/mod.rs @@ -216,6 +216,57 @@ //! # Ok(()) } //! ``` //! +//! If a subscriber may be one of several different types, note that [`Box + Send + Sync + 'static>` implements `Subscribe`][box-impl]. +//! This may be used to erase the type of a subscriber. +//! +//! For example, a function that configures a subscriber to log to one of +//! several outputs might return a `Box + Send + Sync + 'static>`: +//! ``` +//! use tracing_subscriber::{ +//! Subscribe, +//! 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 subscriber(self) -> Box + Send + Sync + 'static> +//! where +//! C: tracing_core::Collect + Send + Sync, +//! for<'a> C: LookupSpan<'a>, +//! { +//! // Shared configuration regardless of where logs are output to. +//! let fmt = tracing_subscriber::fmt::subscriber() +//! .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.subscriber()) +//! .init(); +//! ``` +//! +//! [box-impl]: #impl-Subscribe-for-Box + Send + Sync + 'static> //! [prelude]: crate::prelude //! //! # Recording Traces From 039b9b54789e3701dcc3402c5f02581345f7c459 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 25 Mar 2022 11:14:15 -0700 Subject: [PATCH 4/5] remove useless impl Signed-off-by: Eliza Weisman --- tracing-subscriber/src/subscribe/mod.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tracing-subscriber/src/subscribe/mod.rs b/tracing-subscriber/src/subscribe/mod.rs index 507f9bb1be..3685beb513 100644 --- a/tracing-subscriber/src/subscribe/mod.rs +++ b/tracing-subscriber/src/subscribe/mod.rs @@ -1339,13 +1339,6 @@ feature! { { subscriber_impl_body! {} } - - impl Subscribe for Box> - where - C: Collect, - { - subscriber_impl_body! {} - } } // === impl CollectExt === From 35c0fb71bcc1aac3736998f02165b133b5a3156c Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Fri, 25 Mar 2022 11:27:02 -0700 Subject: [PATCH 5/5] hopefully fix prelude rustdoc link Signed-off-by: Eliza Weisman --- tracing-subscriber/src/subscribe/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracing-subscriber/src/subscribe/mod.rs b/tracing-subscriber/src/subscribe/mod.rs index 3685beb513..040ed52058 100644 --- a/tracing-subscriber/src/subscribe/mod.rs +++ b/tracing-subscriber/src/subscribe/mod.rs @@ -266,8 +266,8 @@ //! .init(); //! ``` //! -//! [box-impl]: #impl-Subscribe-for-Box + Send + Sync + 'static> //! [prelude]: crate::prelude +//! [box-impl]: #impl-Subscribe-for-Box + Send + Sync + 'static> //! //! # Recording Traces //!