From 15ea12641618fff50fc00652fb5d571f7cf6a5b7 Mon Sep 17 00:00:00 2001 From: Gus Wynn Date: Fri, 4 Feb 2022 11:04:30 -0800 Subject: [PATCH] subscriber: add `Targets::would_enable` (#1903 ## Motivation As discussed on discord, this API + `Targets` being `: Clone` makes it easier to solve the original problem I had tried to solve in https://github.com/tokio-rs/tracing/pull/1889. My plan on how to use this is in https://github.com/MaterializeInc/materialize/issues/10441 if you are interested! ## Solution I considered doing some macro magic to create a `Metadata` with a callsite and empty fields and everything, to be able to called `DirectiveSet::enabled`, but it felt cleaner and easier to reason about the special-case-ness (`Targets` never having field filters) using a new set of methods that do a similar thing. For testing I opted for just a doc-test, let me know if thats fine! --- tracing-subscriber/src/filter/directive.rs | 34 +++++++++++++++++++++- tracing-subscriber/src/filter/targets.rs | 31 +++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/tracing-subscriber/src/filter/directive.rs b/tracing-subscriber/src/filter/directive.rs index a402633923..ef6b5bb9e9 100644 --- a/tracing-subscriber/src/filter/directive.rs +++ b/tracing-subscriber/src/filter/directive.rs @@ -4,7 +4,7 @@ use alloc::{ vec::{self, Vec}, }; use core::{cmp::Ordering, fmt, iter::FromIterator, slice, str::FromStr}; -use tracing_core::Metadata; +use tracing_core::{Level, Metadata}; /// Indicates that a string could not be parsed as a filtering directive. #[derive(Debug)] pub struct ParseError { @@ -141,6 +141,22 @@ impl DirectiveSet { None => false, } } + + /// Same as `enabled` above, but skips `Directive`'s with fields. + pub(crate) fn target_enabled(&self, target: &str, level: &Level) -> bool { + match self.directives_for_target(target).next() { + Some(d) => d.level >= *level, + None => false, + } + } + + pub(crate) fn directives_for_target<'a>( + &'a self, + target: &'a str, + ) -> impl Iterator + 'a { + self.directives() + .filter(move |d| d.cares_about_target(target)) + } } // === impl StaticDirective === @@ -157,6 +173,22 @@ impl StaticDirective { level, } } + + pub(in crate::filter) fn cares_about_target(&self, to_check: &str) -> bool { + // Does this directive have a target filter, and does it match the + // metadata's target? + if let Some(ref target) = self.target { + if !to_check.starts_with(&target[..]) { + return false; + } + } + + if !self.field_names.is_empty() { + return false; + } + + true + } } impl Ord for StaticDirective { diff --git a/tracing-subscriber/src/filter/targets.rs b/tracing-subscriber/src/filter/targets.rs index efe1cd8db8..0e34f26ffc 100644 --- a/tracing-subscriber/src/filter/targets.rs +++ b/tracing-subscriber/src/filter/targets.rs @@ -20,7 +20,7 @@ use core::{ slice, str::FromStr, }; -use tracing_core::{Collect, Interest, Metadata}; +use tracing_core::{Collect, Interest, Level, Metadata}; /// A filter that enables or disables spans and events based on their [target] /// and [level]. @@ -313,6 +313,35 @@ impl Targets { Interest::never() } } + + /// Returns whether a [target]-[`Level`] pair would be enabled + /// by this `Targets`. + /// + /// This method can be used with [`module_path!`] from `std` as the target + /// in order to emulate the behavior of the [`tracing::event!`] and [`tracing::span!`] + /// macros. + /// + /// # 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); + /// + /// assert!(filter.would_enable("my_crate", &Level::INFO)); + /// assert!(!filter.would_enable("my_crate::interesting_module", &Level::TRACE)); + /// ``` + /// + /// [target]: tracing_core::Metadata::target + /// [`module_path!`]: std::module_path! + pub fn would_enable(&self, target: &str, level: &Level) -> bool { + // "Correct" to call because `Targets` only produces `StaticDirective`'s with NO + // fields + self.0.target_enabled(target, level) + } } impl Extend<(T, L)> for Targets