Skip to content

Commit 4b2ccc7

Browse files
davidbarskyhawkw
andcommitted
subscriber: add example of Option<Subscribe> (#1596)
This PR contains two changes: 1. An example as how to use `Option<Subscribe>` to toggle subscribers at runtime, and... 2. A fix to an example writing to disk when doc tests are run. Co-authored-by: Eliza Weisman <eliza@buoyant.io>
1 parent 301a276 commit 4b2ccc7

File tree

2 files changed

+82
-2
lines changed

2 files changed

+82
-2
lines changed

tracing-subscriber/src/filter/targets.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//!
55
//! [target]: tracing_core::Metadata::target
66
//! [level]: tracing_core::Level
7-
//! [filter]: crate::layer#filtering-with-layers
7+
//! [filter]: crate::subscribe#filtering-with-subscribers
88
99
use crate::{
1010
filter::{
@@ -118,7 +118,7 @@ use tracing_core::{Collect, Interest, Metadata};
118118
/// };
119119
/// use tracing_core::Level;
120120
/// use std::fs::File;
121-
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
121+
/// # fn docs() -> Result<(), Box<dyn std::error::Error>> {
122122
///
123123
/// // A subscriber that logs events to stdout using the human-readable "pretty"
124124
/// // format.

tracing-subscriber/src/subscribe/mod.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,85 @@
396396
//! # Ok(()) }
397397
//! ```
398398
//!
399+
//!
400+
//! ## Runtime Configuration With Subscribers
401+
//!
402+
//! In some cases, a particular [subscriber] may be enabled or disabled based on
403+
//! runtime configuration. This can introduce challenges, because the type of a
404+
//! layered [collector] depends on which subscribers are added to it: if an `if`
405+
//! or `match` expression adds some [`Subscribe`] implementation in one branch,
406+
//! and other subscribers in another, the [collector] values returned by those
407+
//! branches will have different types. For example, the following _will not_
408+
//! work:
409+
//!
410+
//! ```compile_fail
411+
//! # fn docs() -> Result<(), Box<dyn std::error::Error + 'static>> {
412+
//! # struct Config {
413+
//! # is_prod: bool,
414+
//! # path: &'static str,
415+
//! # }
416+
//! # let cfg = Config { is_prod: false, path: "debug.log" };
417+
//! use std::fs::File;
418+
//! use tracing_subscriber::{Registry, prelude::*};
419+
//!
420+
//! let stdout_log = tracing_subscriber::fmt::subscriber().pretty();
421+
//! let collector = Registry::default().with(stdout_log);
422+
//!
423+
//! // The compile error will occur here because the if and else
424+
//! // branches have different (and therefore incompatible) types.
425+
//! let collector = if cfg.is_prod {
426+
//! let file = File::create(cfg.path)?;
427+
//! let collector = tracing_subscriber::fmt::subscriber()
428+
//! .json()
429+
//! .with_writer(Arc::new(file));
430+
//! collector.with(subscriber)
431+
//! } else {
432+
//! collector
433+
//! };
434+
//!
435+
//! tracing::collect::set_global_default(collector)
436+
//! .expect("Unable to set global collector");
437+
//! # Ok(()) }
438+
//! ```
439+
//!
440+
//! However, a [`Subscribe`] wrapped in an [`Option`] [also implements the `Subscribe`
441+
//! trait][option-impl]. This allows individual layers to be enabled or disabled at
442+
//! runtime while always producing a [`Collect`] of the same type. For
443+
//! example:
444+
//!
445+
//! ```
446+
//! # fn docs() -> Result<(), Box<dyn std::error::Error + 'static>> {
447+
//! # struct Config {
448+
//! # is_prod: bool,
449+
//! # path: &'static str,
450+
//! # }
451+
//! # let cfg = Config { is_prod: false, path: "debug.log" };
452+
//! use std::fs::File;
453+
//! use tracing_subscriber::{Registry, prelude::*};
454+
//!
455+
//! let stdout_log = tracing_subscriber::fmt::subscriber().pretty();
456+
//! let collector = Registry::default().with(stdout_log);
457+
//!
458+
//! // if `cfg.is_prod` is true, also log JSON-formatted logs to a file.
459+
//! let json_log = if cfg.is_prod {
460+
//! let file = File::create(cfg.path)?;
461+
//! let json_log = tracing_subscriber::fmt::subscriber()
462+
//! .json()
463+
//! .with_writer(file);
464+
//! Some(json_log)
465+
//! } else {
466+
//! None
467+
//! };
468+
//!
469+
//! // If `cfg.is_prod` is false, then `json` will be `None`, and this subscriber
470+
//! // will do nothing. However, the collector will still have the same type
471+
//! // regardless of whether the `Option`'s value is `None` or `Some`.
472+
//! let collector = collector.with(json_log);
473+
//!
474+
//! tracing::collect::set_global_default(collector)
475+
//! .expect("Unable to set global collector");
476+
//! # Ok(()) }
477+
//! ```
399478
//! [subscriber]: Subscribe
400479
//! [`Collect`]:tracing_core::Collect
401480
//! [collector]: tracing_core::Collect
@@ -407,6 +486,7 @@
407486
//! [`Subscribe::register_callsite`]: Subscribe::register_callsite
408487
//! [`Subscribe::enabled`]: Subscribe::enabled
409488
//! [`Interest::never()`]: tracing_core::collect::Interest::never
489+
//! [option-impl]: crate::subscribe::Subscribe#impl-Subscribe<C>-for-Option<S>
410490
//! [`Filtered`]: crate::filter::Filtered
411491
//! [`filter`]: crate::filter
412492
//! [`Targets`]: crate::filter::Targets

0 commit comments

Comments
 (0)