-
Notifications
You must be signed in to change notification settings - Fork 715
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Depends on #2028 ## Motivation In many cases, it is desirable to have a variable number of subscribers at runtime (such as when reading a logging configuration from a config file). The current approach, where types implementing `Subscribe` are composed at the type level into `Layered` subscribers, doesn't work well when the number of subscribers varies at runtime. ## Solution To solve this, this branch adds a `Subscribe` implementation for `Vec<S> where S: Subscribe`. This allows variable-length lists of subscribers to be added to a collector. Although the impl for `Vec<S>` requires all the subscribers to be the same type, it can also be used in conjunction with `Box<dyn Subscribe<C> + ...>` trait objects to implement a variable-length list of subscribers of multiple types. I also wrote a bunch of docs examples. ## Notes Alternatively, we could have a separate type defined in `tracing-subscriber` for a variable-length list of type-erased subscribers. This would have one primary usability benefit, which is that we could have a `push` operation that takes an `impl Subscribe` and boxes it automatically. However, I thought the approach used here is nicer, since it's based on composing together existing primitives such as `Vec` and `Box`, rather than adding a whole new API. Additionally, it allows avoiding the additional `Box`ing in the case where the list consists of subscribers that are all the same type. Closes #1708 Signed-off-by: Eliza Weisman <eliza@buoyant.io>
- Loading branch information
Showing
4 changed files
with
451 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
use super::*; | ||
use tracing::Collect; | ||
|
||
#[test] | ||
fn with_filters_unboxed() { | ||
let (trace_subscriber, trace_handle) = subscriber::named("trace") | ||
.event(event::mock().at_level(Level::TRACE)) | ||
.event(event::mock().at_level(Level::DEBUG)) | ||
.event(event::mock().at_level(Level::INFO)) | ||
.done() | ||
.run_with_handle(); | ||
let trace_subscriber = trace_subscriber.with_filter(LevelFilter::TRACE); | ||
|
||
let (debug_subscriber, debug_handle) = subscriber::named("debug") | ||
.event(event::mock().at_level(Level::DEBUG)) | ||
.event(event::mock().at_level(Level::INFO)) | ||
.done() | ||
.run_with_handle(); | ||
let debug_subscriber = debug_subscriber.with_filter(LevelFilter::DEBUG); | ||
|
||
let (info_subscriber, info_handle) = subscriber::named("info") | ||
.event(event::mock().at_level(Level::INFO)) | ||
.done() | ||
.run_with_handle(); | ||
let info_subscriber = info_subscriber.with_filter(LevelFilter::INFO); | ||
|
||
let _collector = tracing_subscriber::registry() | ||
.with(vec![trace_subscriber, debug_subscriber, info_subscriber]) | ||
.set_default(); | ||
|
||
tracing::trace!("hello trace"); | ||
tracing::debug!("hello debug"); | ||
tracing::info!("hello info"); | ||
|
||
trace_handle.assert_finished(); | ||
debug_handle.assert_finished(); | ||
info_handle.assert_finished(); | ||
} | ||
|
||
#[test] | ||
fn with_filters_boxed() { | ||
let (unfiltered_subscriber, unfiltered_handle) = subscriber::named("unfiltered") | ||
.event(event::mock().at_level(Level::TRACE)) | ||
.event(event::mock().at_level(Level::DEBUG)) | ||
.event(event::mock().at_level(Level::INFO)) | ||
.done() | ||
.run_with_handle(); | ||
let unfiltered_subscriber = unfiltered_subscriber.boxed(); | ||
|
||
let (debug_subscriber, debug_handle) = subscriber::named("debug") | ||
.event(event::mock().at_level(Level::DEBUG)) | ||
.event(event::mock().at_level(Level::INFO)) | ||
.done() | ||
.run_with_handle(); | ||
let debug_subscriber = debug_subscriber.with_filter(LevelFilter::DEBUG).boxed(); | ||
|
||
let (target_subscriber, target_handle) = subscriber::named("target") | ||
.event(event::mock().at_level(Level::INFO)) | ||
.done() | ||
.run_with_handle(); | ||
let target_subscriber = target_subscriber | ||
.with_filter(filter::filter_fn(|meta| meta.target() == "my_target")) | ||
.boxed(); | ||
|
||
let _collector = tracing_subscriber::registry() | ||
.with(vec![ | ||
unfiltered_subscriber, | ||
debug_subscriber, | ||
target_subscriber, | ||
]) | ||
.set_default(); | ||
|
||
tracing::trace!("hello trace"); | ||
tracing::debug!("hello debug"); | ||
tracing::info!(target: "my_target", "hello my target"); | ||
|
||
unfiltered_handle.assert_finished(); | ||
debug_handle.assert_finished(); | ||
target_handle.assert_finished(); | ||
} | ||
|
||
#[test] | ||
fn mixed_max_level_hint() { | ||
let unfiltered = subscriber::named("unfiltered").run().boxed(); | ||
let info = subscriber::named("info") | ||
.run() | ||
.with_filter(LevelFilter::INFO) | ||
.boxed(); | ||
let debug = subscriber::named("debug") | ||
.run() | ||
.with_filter(LevelFilter::DEBUG) | ||
.boxed(); | ||
|
||
let collector = tracing_subscriber::registry().with(vec![unfiltered, info, debug]); | ||
|
||
assert_eq!(collector.max_level_hint(), None); | ||
} | ||
|
||
#[test] | ||
fn all_filtered_max_level_hint() { | ||
let warn = subscriber::named("warn") | ||
.run() | ||
.with_filter(LevelFilter::WARN) | ||
.boxed(); | ||
let info = subscriber::named("info") | ||
.run() | ||
.with_filter(LevelFilter::INFO) | ||
.boxed(); | ||
let debug = subscriber::named("debug") | ||
.run() | ||
.with_filter(LevelFilter::DEBUG) | ||
.boxed(); | ||
|
||
let collector = tracing_subscriber::registry().with(vec![warn, info, debug]); | ||
|
||
assert_eq!(collector.max_level_hint(), Some(LevelFilter::DEBUG)); | ||
} |
Oops, something went wrong.