Skip to content

Commit d2ad8ab

Browse files
connechawkw
authored andcommitted
subscriber: add Targets::default_level method (#2242)
## Motivation This makes it possible to fully "override" some base `Targets` filter with another (e.g. user-supplied) filter. Without some way to obtain the default, only explicit targets can be overridden (via `IntoIter` and friends). See also #1790 (comment) ## Solution We can add a method to `Targets` that filters the underlying `DirectiveSet` for the default directive. This works because `DirectiveSet::add` will replace directives with the same `target`/`field_names`, which is always `None`/`vec![]` for the directive added by `with_default` (and in fact we are only concerned with `target`, since no other `Targets` API allows adding directives with a `None` target). Ideally the method would be named `default`, corresponding to `with_default`, however this conflicts with `Default::default` and so would be a breaking change (and harm ergonomics). `default_level` seemed a better name than `get_default`, since "getters" of this style are generally considered unidiomatic<sup>[citation needed]</sup>. Example usage: ```rust let mut filter = Targets::new().with_target("some_module", LevelFilter::INFO); // imagine this came from `RUST_LOG` or similar let override: Targets = "trace".parse().unwrap(); // merge the override if let Some(default) = override.default_level() { filter = filter.with_default(default); } for (target, level) in override.iter() { filter = filter.with_target(target, level); } ``` Closes #1790
1 parent 22d09f6 commit d2ad8ab

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

tracing-subscriber/src/filter/targets.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,62 @@ impl Targets {
277277
self
278278
}
279279

280+
/// Returns the default level for this filter, if one is set.
281+
///
282+
/// The default level is used to filter any spans or events with targets
283+
/// that do not match any of the configured set of prefixes.
284+
///
285+
/// The default level can be set for a filter either by using
286+
/// [`with_default`](Self::with_default) or when parsing from a filter string that includes a
287+
/// level without a target (e.g. `"trace"`).
288+
///
289+
/// # Examples
290+
///
291+
/// ```
292+
/// use tracing_subscriber::filter::{LevelFilter, Targets};
293+
///
294+
/// let filter = Targets::new().with_default(LevelFilter::INFO);
295+
/// assert_eq!(filter.default_level(), Some(LevelFilter::INFO));
296+
///
297+
/// let filter: Targets = "info".parse().unwrap();
298+
/// assert_eq!(filter.default_level(), Some(LevelFilter::INFO));
299+
/// ```
300+
///
301+
/// The default level is `None` if no default is set:
302+
///
303+
/// ```
304+
/// use tracing_subscriber::filter::Targets;
305+
///
306+
/// let filter = Targets::new();
307+
/// assert_eq!(filter.default_level(), None);
308+
///
309+
/// let filter: Targets = "my_crate=info".parse().unwrap();
310+
/// assert_eq!(filter.default_level(), None);
311+
/// ```
312+
///
313+
/// Note that an unset default level (`None`) behaves like [`LevelFilter::OFF`] when the filter is
314+
/// used, but it could also be set explicitly which may be useful to distinguish (such as when
315+
/// merging multiple `Targets`).
316+
///
317+
/// ```
318+
/// use tracing_subscriber::filter::{LevelFilter, Targets};
319+
///
320+
/// let filter = Targets::new().with_default(LevelFilter::OFF);
321+
/// assert_eq!(filter.default_level(), Some(LevelFilter::OFF));
322+
///
323+
/// let filter: Targets = "off".parse().unwrap();
324+
/// assert_eq!(filter.default_level(), Some(LevelFilter::OFF));
325+
/// ```
326+
pub fn default_level(&self) -> Option<LevelFilter> {
327+
self.0.directives().into_iter().find_map(|d| {
328+
if d.target.is_none() {
329+
Some(d.level)
330+
} else {
331+
None
332+
}
333+
})
334+
}
335+
280336
/// Returns an iterator over the [target]-[`LevelFilter`] pairs in this filter.
281337
///
282338
/// The order of iteration is undefined.
@@ -685,6 +741,21 @@ mod tests {
685741
);
686742
}
687743

744+
#[test]
745+
fn targets_default_level() {
746+
let filter = expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off");
747+
assert_eq!(filter.default_level(), None);
748+
749+
let filter = expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off")
750+
.with_default(LevelFilter::OFF);
751+
assert_eq!(filter.default_level(), Some(LevelFilter::OFF));
752+
753+
let filter = expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off")
754+
.with_default(LevelFilter::OFF)
755+
.with_default(LevelFilter::INFO);
756+
assert_eq!(filter.default_level(), Some(LevelFilter::INFO));
757+
}
758+
688759
#[test]
689760
// `println!` is only available with `libstd`.
690761
#[cfg(feature = "std")]

0 commit comments

Comments
 (0)