Skip to content

Commit

Permalink
subscriber: add Filter and Reload layers (#223)
Browse files Browse the repository at this point in the history
## Motivation

Currently, `tracing-fmt` provides an implementation of `env_logger`-like
filtering directives. However, there are two issues:

1. The implementation is specific to `tracing-fmt` and does not work 
   with other subscribers.
2. Filtering dynamically based on field values is not supported.

Now that the `Layer` type has been added to `tracing-subscriber` (see 
#136), we can implement filtering generically, as a `Layer` that can
wrap other `Subscriber`s to provide a particular filtering strategy.

## Solution

This branch re-implements the `env_logger` style filtering in 
`tracing-fmt` as a `tracing-subscriber::Layer`. The new `Layer` type
implements dynamic filtering on span fields, in addition to the 
functionality of the `tracing-fmt` implementation. I've also added a 
wrapper type to support runtime reloading of a `Layer`, similarly to 
the `Reload` type in `tracing-fmt::filter`, but more general.

Finally, I've added some tests and an interactive demo for the new 
filtering. The example runs a simple web service with a load generator,
and allows users to explore the `tracing-fmt` output from the example 
service by dynamically reloading the filter settings.

## Notes

This is admittedly a pretty large branch, but I think it makes the 
most sense to merge everything together, since the example requires
both the filter implementation *and* the reload layer. I've tried to 
make sure the most complex bits of the filtering code has comments 
describing the implementation, but please let me know if anything 
is unclear.

Also, there is a lot of room for potential performance improvements
in the current filter implementation. I've left comments on some code
that I think could probably be made more efficient. Ideally, though, 
any future optimization work ought to be guided by benchmarks as well.

Signed-off-by: Eliza Weisman <[email protected]>

Signed-off-by: Eliza Weisman <[email protected]>
  • Loading branch information
hawkw authored Aug 1, 2019
1 parent 80a5f49 commit fe5c2e2
Show file tree
Hide file tree
Showing 21 changed files with 2,710 additions and 41 deletions.
2 changes: 1 addition & 1 deletion tracing-env-logger/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ tracing = "0.1"
tracing-fmt = { path = "../tracing-fmt" }
tracing-futures = { path = "../tracing-futures" }
tracing-subscriber = { path = "../tracing-subscriber" }
hyper = "=0.12.25"
hyper = "0.12.25"
futures = "0.1"
tokio = "0.1.22"

Expand Down
15 changes: 15 additions & 0 deletions tracing-fmt/src/filter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,18 @@ where
(self)(metadata, ctx)
}
}

pub fn none() -> NoFilter {
NoFilter { _p: () }
}

#[derive(Clone, Debug)]
pub struct NoFilter {
_p: (),
}

impl<N> Filter<N> for NoFilter {
fn enabled(&self, _: &Metadata, _: &span::Context<N>) -> bool {
true
}
}
27 changes: 26 additions & 1 deletion tracing-subscriber/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,37 @@ categories = [
]
keywords = ["logging", "tracing", "metrics", "subscriber"]

[features]
default = ["filter", "smallvec"]
filter = ["matchers", "regex", "lazy_static"]

[dependencies]
tracing-core = "0.1.2"
crossbeam-utils = "0.6"

# only required by the filter feature
matchers = { optional = true, git = "https://github.com/hawkw/matchers.git" }
regex = { optional = true, version = "1" }
smallvec = { optional = true, version = "0.6.10"}
lazy_static = { optional = true, version = "1" }

[dev-dependencies]
tracing-fmt = { path = "../tracing-fmt" }
tracing = "0.1"

# load generator demo
tracing-tower = { path = "../tracing-tower" }
tower = "0.1"
tower-hyper = "0.1"
tower-http-util = "0.1"
tracing-futures = { path = "../tracing-futures" }
futures = "0.1"
hyper = "0.12"
tokio = "0.1"
tokio-tcp = "0.1"
tokio-buf = "0.1"
rand = "0.6"

[badges]
azure-devops = { project = "tracing/tracing", pipeline = "tokio-rs.tracing", build = "1" }
maintenance = { status = "experimental" }
maintenance = { status = "experimental" }
56 changes: 56 additions & 0 deletions tracing-subscriber/examples/filter_yakshave.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use tracing::Level;
use tracing_subscriber::prelude::*;

fn shave(yak: usize) -> bool {
tracing::debug!(
message = "hello! I'm gonna shave a yak.",
excitement = "yay!"
);
if yak == 3 {
tracing::warn!(target: "yak_events", "could not locate yak!");
false
} else {
tracing::trace!(target: "yak_events", "yak shaved successfully");
true
}
}

fn main() {
let subscriber = tracing_fmt::FmtSubscriber::builder()
// Disable `tracing-fmt`'s filter implementation...
.with_filter(tracing_fmt::filter::none())
.finish()
// and use `tracing-subscriber`'s filter layer instead.
.with(tracing_subscriber::filter::Filter::from_default_env());

tracing::subscriber::with_default(subscriber, || {
let yaks_to_shave = 3;
let mut yaks_shaved = 0;
tracing::debug!("preparing to shave {} yaks", yaks_to_shave);

tracing::span!(Level::TRACE, "shaving_yaks", yaks_to_shave).in_scope(|| {
tracing::info!("shaving yaks");

for yak in 1..=yaks_to_shave {
let span = tracing::span!(Level::TRACE, "shave", yak);
let _e = span.enter();

let shaved = shave(yak);
tracing::trace!(shaved = shaved);

if !shaved {
tracing::error!(message = "failed to shave yak!");
} else {
yaks_shaved += 1;
}

tracing::trace!(yaks_shaved);
}
});

tracing::debug!(
message = "yak shaving completed.",
all_yaks_shaved = yaks_shaved == yaks_to_shave,
);
});
}
Loading

0 comments on commit fe5c2e2

Please sign in to comment.