|
19 | 19 | //! [`Collect`] behavior; it can _observe_ events and spans, but does not |
20 | 20 | //! assign IDs. |
21 | 21 | //! |
22 | | -//! ## Composing Subscribers |
| 22 | +//! # Composing Subscribers |
23 | 23 | //! |
24 | 24 | //! Since a [subscriber] does not implement a complete strategy for collecting |
25 | 25 | //! traces, it must be composed with a [collector] in order to be used. The |
|
137 | 137 | //! [`Subscribe::with_collector`] as an implementation detail, as `with_collector` |
138 | 138 | //! calls must be nested, leading to less clear code for the reader. |
139 | 139 | //! |
| 140 | +//! ## Runtime Configuration With Subscribers |
| 141 | +//! |
| 142 | +//! In some cases, a particular [subscriber] may be enabled or disabled based on |
| 143 | +//! runtime configuration. This can introduce challenges, because the type of a |
| 144 | +//! layered [collector] depends on which subscribers are added to it: if an `if` |
| 145 | +//! or `match` expression adds some [`Subscribe`] implementation in one branch, |
| 146 | +//! and other subscribers in another, the [collector] values returned by those |
| 147 | +//! branches will have different types. For example, the following _will not_ |
| 148 | +//! work: |
| 149 | +//! |
| 150 | +//! ```compile_fail |
| 151 | +//! # fn docs() -> Result<(), Box<dyn std::error::Error + 'static>> { |
| 152 | +//! # struct Config { |
| 153 | +//! # is_prod: bool, |
| 154 | +//! # path: &'static str, |
| 155 | +//! # } |
| 156 | +//! # let cfg = Config { is_prod: false, path: "debug.log" }; |
| 157 | +//! use std::fs::File; |
| 158 | +//! use tracing_subscriber::{Registry, prelude::*}; |
| 159 | +//! |
| 160 | +//! let stdout_log = tracing_subscriber::fmt::subscriber().pretty(); |
| 161 | +//! let collector = Registry::default().with(stdout_log); |
| 162 | +//! |
| 163 | +//! // The compile error will occur here because the if and else |
| 164 | +//! // branches have different (and therefore incompatible) types. |
| 165 | +//! let collector = if cfg.is_prod { |
| 166 | +//! let file = File::create(cfg.path)?; |
| 167 | +//! let collector = tracing_subscriber::fmt::subscriber() |
| 168 | +//! .json() |
| 169 | +//! .with_writer(Arc::new(file)); |
| 170 | +//! collector.with(subscriber) |
| 171 | +//! } else { |
| 172 | +//! collector |
| 173 | +//! }; |
| 174 | +//! |
| 175 | +//! tracing::collect::set_global_default(collector) |
| 176 | +//! .expect("Unable to set global collector"); |
| 177 | +//! # Ok(()) } |
| 178 | +//! ``` |
| 179 | +//! |
| 180 | +//! However, a [`Subscribe`] wrapped in an [`Option`] [also implements the `Subscribe` |
| 181 | +//! trait][option-impl]. This allows individual layers to be enabled or disabled at |
| 182 | +//! runtime while always producing a [`Collect`] of the same type. For |
| 183 | +//! example: |
| 184 | +//! |
| 185 | +//! ``` |
| 186 | +//! # fn docs() -> Result<(), Box<dyn std::error::Error + 'static>> { |
| 187 | +//! # struct Config { |
| 188 | +//! # is_prod: bool, |
| 189 | +//! # path: &'static str, |
| 190 | +//! # } |
| 191 | +//! # let cfg = Config { is_prod: false, path: "debug.log" }; |
| 192 | +//! use std::fs::File; |
| 193 | +//! use tracing_subscriber::{Registry, prelude::*}; |
| 194 | +//! |
| 195 | +//! let stdout_log = tracing_subscriber::fmt::subscriber().pretty(); |
| 196 | +//! let collector = Registry::default().with(stdout_log); |
| 197 | +//! |
| 198 | +//! // if `cfg.is_prod` is true, also log JSON-formatted logs to a file. |
| 199 | +//! let json_log = if cfg.is_prod { |
| 200 | +//! let file = File::create(cfg.path)?; |
| 201 | +//! let json_log = tracing_subscriber::fmt::subscriber() |
| 202 | +//! .json() |
| 203 | +//! .with_writer(file); |
| 204 | +//! Some(json_log) |
| 205 | +//! } else { |
| 206 | +//! None |
| 207 | +//! }; |
| 208 | +//! |
| 209 | +//! // If `cfg.is_prod` is false, then `json` will be `None`, and this subscriber |
| 210 | +//! // will do nothing. However, the collector will still have the same type |
| 211 | +//! // regardless of whether the `Option`'s value is `None` or `Some`. |
| 212 | +//! let collector = collector.with(json_log); |
| 213 | +//! |
| 214 | +//! tracing::collect::set_global_default(collector) |
| 215 | +//! .expect("Unable to set global collector"); |
| 216 | +//! # Ok(()) } |
| 217 | +//! ``` |
| 218 | +//! |
| 219 | +//! If a subscriber may be one of several different types, note that [`Box<dyn |
| 220 | +//! Subscribe<C> + Send + Sync + 'static>` implements `Subscribe`][box-impl]. |
| 221 | +//! This may be used to erase the type of a subscriber. |
| 222 | +//! |
| 223 | +//! For example, a function that configures a subscriber to log to one of |
| 224 | +//! several outputs might return a `Box<dyn Subscribe<C> + Send + Sync + 'static>`: |
| 225 | +//! ``` |
| 226 | +//! use tracing_subscriber::{ |
| 227 | +//! Subscribe, |
| 228 | +//! registry::LookupSpan, |
| 229 | +//! prelude::*, |
| 230 | +//! }; |
| 231 | +//! use std::{path::PathBuf, fs::File, io}; |
| 232 | +//! |
| 233 | +//! /// Configures whether logs are emitted to a file, to stdout, or to stderr. |
| 234 | +//! pub enum LogConfig { |
| 235 | +//! File(PathBuf), |
| 236 | +//! Stdout, |
| 237 | +//! Stderr, |
| 238 | +//! } |
| 239 | +//! |
| 240 | +//! impl LogConfig { |
| 241 | +//! pub fn subscriber<C>(self) -> Box<dyn Subscribe<C> + Send + Sync + 'static> |
| 242 | +//! where |
| 243 | +//! C: tracing_core::Collect + Send + Sync, |
| 244 | +//! for<'a> C: LookupSpan<'a>, |
| 245 | +//! { |
| 246 | +//! // Shared configuration regardless of where logs are output to. |
| 247 | +//! let fmt = tracing_subscriber::fmt::subscriber() |
| 248 | +//! .with_target(true) |
| 249 | +//! .with_thread_names(true); |
| 250 | +//! |
| 251 | +//! // Configure the writer based on the desired log target: |
| 252 | +//! match self { |
| 253 | +//! LogConfig::File(path) => { |
| 254 | +//! let file = File::create(path).expect("failed to create log file"); |
| 255 | +//! Box::new(fmt.with_writer(file)) |
| 256 | +//! }, |
| 257 | +//! LogConfig::Stdout => Box::new(fmt.with_writer(io::stdout)), |
| 258 | +//! LogConfig::Stderr => Box::new(fmt.with_writer(io::stderr)), |
| 259 | +//! } |
| 260 | +//! } |
| 261 | +//! } |
| 262 | +//! |
| 263 | +//! let config = LogConfig::Stdout; |
| 264 | +//! tracing_subscriber::registry() |
| 265 | +//! .with(config.subscriber()) |
| 266 | +//! .init(); |
| 267 | +//! ``` |
| 268 | +//! |
140 | 269 | //! [prelude]: crate::prelude |
| 270 | +//! [box-impl]: #impl-Subscribe<C>-for-Box<dyn Subscribe<C> + Send + Sync + 'static> |
141 | 271 | //! |
142 | | -//! ## Recording Traces |
| 272 | +//! # Recording Traces |
143 | 273 | //! |
144 | 274 | //! The [`Subscribe`] trait defines a set of methods for consuming notifications from |
145 | 275 | //! tracing instrumentation, which are generally equivalent to the similarly |
|
148 | 278 | //! information provided by the wrapped subscriber (such as [the current span]) |
149 | 279 | //! to the subscriber. |
150 | 280 | //! |
151 | | -//! ## Filtering with `Subscribers`s |
| 281 | +//! # Filtering with `Subscriber`s |
152 | 282 | //! |
153 | 283 | //! As well as strategies for handling trace events, the `Subscribe` trait may also |
154 | 284 | //! be used to represent composable _filters_. This allows the determination of |
|
160 | 290 | //! combined with _per-subscriber filters_ that control what spans and events are |
161 | 291 | //! recorded by those subscribers. |
162 | 292 | //! |
163 | | -//! ### Global Filtering |
| 293 | +//! ## Global Filtering |
164 | 294 | //! |
165 | 295 | //! A `Subscribe` that implements a filtering strategy should override the |
166 | 296 | //! [`register_callsite`] and/or [`enabled`] methods. It may also choose to implement |
|
181 | 311 | //! [`Interest::never()`] from its [`register_callsite`] method, filter |
182 | 312 | //! evaluation will short-circuit and the span or event will be disabled. |
183 | 313 | //! |
184 | | -//! ### Per-Subscriber Filtering |
| 314 | +//! ## Per-Subscriber Filtering |
185 | 315 | //! |
186 | 316 | //! **Note**: per-subscriber filtering APIs currently require the [`"registry"` crate |
187 | 317 | //! feature flag][feat] to be enabled. |
|
396 | 526 | //! # Ok(()) } |
397 | 527 | //! ``` |
398 | 528 | //! |
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 | | -//! ``` |
478 | 529 | //! [subscriber]: Subscribe |
479 | 530 | //! [`Collect`]:tracing_core::Collect |
480 | 531 | //! [collector]: tracing_core::Collect |
@@ -1282,7 +1333,7 @@ feature! { |
1282 | 1333 | subscriber_impl_body! {} |
1283 | 1334 | } |
1284 | 1335 |
|
1285 | | - impl<C> Subscribe<C> for Box<dyn Subscribe<C>> |
| 1336 | + impl<C> Subscribe<C> for Box<dyn Subscribe<C> + Send + Sync + 'static> |
1286 | 1337 | where |
1287 | 1338 | C: Collect, |
1288 | 1339 | { |
|
0 commit comments