-
Notifications
You must be signed in to change notification settings - Fork 734
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 `Layer`s at runtime (such as when reading a logging configuration from a config file). The current approach, where types implementing `Layer` are composed at the type level into `Layered` layers, doesn't work well when the number of layers varies at runtime. ## Solution To solve this, this branch adds a `Layer` implementation for `Vec<L> where L: Layer`. This allows variable-length lists of layers to be added to a subscriber. Although the impl for `Vec<L>` requires all the layers to be the same type, it can also be used in onjunction with `Box<dyn Layer<S> + ...>` trait objects to implement a variable-length list of layers 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 `Layer`s. This would have one primary usability benefit, which is that we could have a `push` operation that takes an `impl Layer` 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 layers that are all the same type. Closes #1708 Signed-off-by: Eliza Weisman <[email protected]>
- Loading branch information
Showing
4 changed files
with
451 additions
and
3 deletions.
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,113 @@ | ||
use super::*; | ||
use tracing::Subscriber; | ||
|
||
#[test] | ||
fn with_filters_unboxed() { | ||
let (trace_layer, trace_handle) = layer::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_layer = trace_layer.with_filter(LevelFilter::TRACE); | ||
|
||
let (debug_layer, debug_handle) = layer::named("debug") | ||
.event(event::mock().at_level(Level::DEBUG)) | ||
.event(event::mock().at_level(Level::INFO)) | ||
.done() | ||
.run_with_handle(); | ||
let debug_layer = debug_layer.with_filter(LevelFilter::DEBUG); | ||
|
||
let (info_layer, info_handle) = layer::named("info") | ||
.event(event::mock().at_level(Level::INFO)) | ||
.done() | ||
.run_with_handle(); | ||
let info_layer = info_layer.with_filter(LevelFilter::INFO); | ||
|
||
let _subscriber = tracing_subscriber::registry() | ||
.with(vec![trace_layer, debug_layer, info_layer]) | ||
.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_layer, unfiltered_handle) = layer::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_layer = unfiltered_layer.boxed(); | ||
|
||
let (debug_layer, debug_handle) = layer::named("debug") | ||
.event(event::mock().at_level(Level::DEBUG)) | ||
.event(event::mock().at_level(Level::INFO)) | ||
.done() | ||
.run_with_handle(); | ||
let debug_layer = debug_layer.with_filter(LevelFilter::DEBUG).boxed(); | ||
|
||
let (target_layer, target_handle) = layer::named("target") | ||
.event(event::mock().at_level(Level::INFO)) | ||
.done() | ||
.run_with_handle(); | ||
let target_layer = target_layer | ||
.with_filter(filter::filter_fn(|meta| meta.target() == "my_target")) | ||
.boxed(); | ||
|
||
let _subscriber = tracing_subscriber::registry() | ||
.with(vec![unfiltered_layer, debug_layer, target_layer]) | ||
.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 = layer::named("unfiltered").run().boxed(); | ||
let info = layer::named("info") | ||
.run() | ||
.with_filter(LevelFilter::INFO) | ||
.boxed(); | ||
let debug = layer::named("debug") | ||
.run() | ||
.with_filter(LevelFilter::DEBUG) | ||
.boxed(); | ||
|
||
let subscriber = tracing_subscriber::registry().with(vec![unfiltered, info, debug]); | ||
|
||
assert_eq!(subscriber.max_level_hint(), None); | ||
} | ||
|
||
#[test] | ||
fn all_filtered_max_level_hint() { | ||
let warn = layer::named("warn") | ||
.run() | ||
.with_filter(LevelFilter::WARN) | ||
.boxed(); | ||
let info = layer::named("info") | ||
.run() | ||
.with_filter(LevelFilter::INFO) | ||
.boxed(); | ||
let debug = layer::named("debug") | ||
.run() | ||
.with_filter(LevelFilter::DEBUG) | ||
.boxed(); | ||
|
||
let subscriber = tracing_subscriber::registry().with(vec![warn, info, debug]); | ||
|
||
assert_eq!(subscriber.max_level_hint(), Some(LevelFilter::DEBUG)); | ||
} |
Oops, something went wrong.