Skip to content

Commit

Permalink
subscriber: add Targets::targets method to iterate directives
Browse files Browse the repository at this point in the history
There's currently no way to get the registered directives from a
`Targets` instance, which is a barrier to some use-cases such as
combining user-supplied directives with application-supplied defaults.

This commit adds a `Targets::targets` method, which returns an iterator
of `(&str, LevelFilter)` pairs, one for each directive (excluding the
default level, whose `target` is `None`).

Items are yielded as per the underlying `DirectiveSet::directives`,
which would yield itms in specifity order (as constructed by
`DirectiveSet::add`). However, the order has been left explicitly
undefined in the documentation for `Targets::targets` on the basis that
this is an implementation detail that may change.
  • Loading branch information
Chris Connelly committed Sep 17, 2021
1 parent a792aa8 commit b917104
Showing 1 changed file with 72 additions and 6 deletions.
78 changes: 72 additions & 6 deletions tracing-subscriber/src/filter/targets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,52 @@ impl Targets {
self
}

/// Returns an iterator over the [target]-[`LevelFilter`] pairs in this filter.
///
/// The order of iteration is undefined.
///
/// # Examples
///
/// ```
/// use tracing_subscriber::filter::{Targets, LevelFilter};
/// use tracing_core::Level;
///
/// let filter = Targets::new()
/// .with_target("my_crate", Level::INFO)
/// .with_target("my_crate::interesting_module", Level::DEBUG);
///
/// let mut targets: Vec<_> = filter.targets().collect();
/// targets.sort();
///
/// assert_eq!(targets, vec![
/// ("my_crate", LevelFilter::INFO),
/// ("my_crate::interesting_module", LevelFilter::DEBUG),
/// ]);
/// ```
///
/// This can be used to combine two [`Targets`]:
///
/// ```
/// use tracing_subscriber::filter::Targets;
/// use tracing_core::Level;
///
/// let mut filter = Targets::new().with_target("my_crate", Level::INFO);
/// let overrides = Targets::new().with_target("my_crate::interesting_module", Level::DEBUG);
///
/// filter.extend(overrides.targets());
/// # drop(filter);
/// ```
///
/// [target]: tracing_core::Metadata::target
pub fn targets(&self) -> impl Iterator<Item = (&str, LevelFilter)> + '_ {
self.0.directives().filter_map(|directive| {
directive
.target
.as_deref()
.map(|target| (target, directive.level))
})
}

#[inline]
fn interested(&self, metadata: &'static Metadata<'static>) -> Interest {
if self.0.enabled(metadata) {
Expand Down Expand Up @@ -347,17 +393,16 @@ impl<S> layer::Filter<S> for Targets {
#[cfg(test)]
mod tests {
use super::*;
use crate::filter::directive::FilterVec;

fn expect_parse(s: &str) -> FilterVec<StaticDirective> {
fn expect_parse(s: &str) -> Targets {
match dbg!(s).parse::<Targets>() {
Err(e) => panic!("string {:?} did not parse successfully: {}", s, e),
Ok(e) => e.0.into_vec(),
Ok(e) => e,
}
}

fn expect_parse_ralith(s: &str) {
let dirs = expect_parse(s);
let dirs = expect_parse(s).0.into_vec();
assert_eq!(dirs.len(), 2, "\nparsed: {:#?}", dirs);
assert_eq!(dirs[0].target, Some("server".to_string()));
assert_eq!(dirs[0].level, LevelFilter::DEBUG);
Expand All @@ -369,7 +414,7 @@ mod tests {
}

fn expect_parse_level_directives(s: &str) {
let dirs = expect_parse(s);
let dirs = expect_parse(s).0.into_vec();
assert_eq!(dirs.len(), 6, "\nparsed: {:#?}", dirs);

assert_eq!(dirs[0].target, Some("crate3::mod2::mod1".to_string()));
Expand Down Expand Up @@ -414,7 +459,9 @@ mod tests {

#[test]
fn expect_parse_valid() {
let dirs = expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off");
let dirs = expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off")
.0
.into_vec();
assert_eq!(dirs.len(), 4, "\nparsed: {:#?}", dirs);
assert_eq!(dirs[0].target, Some("crate1::mod2".to_string()));
assert_eq!(dirs[0].level, LevelFilter::TRACE);
Expand Down Expand Up @@ -457,6 +504,25 @@ mod tests {
)
}

#[test]
fn targets_iter() {
let filter = expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off")
.with_default(LevelFilter::WARN);

let mut targets: Vec<_> = filter.targets().collect();
targets.sort();

assert_eq!(
targets,
vec![
("crate1::mod1", LevelFilter::ERROR),
("crate1::mod2", LevelFilter::TRACE),
("crate2", LevelFilter::DEBUG),
("crate3", LevelFilter::OFF),
]
);
}

#[test]
fn size_of_filters() {
fn print_sz(s: &str) {
Expand Down

0 comments on commit b917104

Please sign in to comment.