1 //! A [filter] that enables or disables spans and events based on their [target] and [level].
3 //! See [`Targets`] for details.
5 //! [target]: tracing_core::Metadata::target
6 //! [level]: tracing_core::Level
7 //! [filter]: crate::layer#filtering-with-layers
11 directive
::{DirectiveSet, ParseError, StaticDirective}
,
16 #[cfg(not(feature = "std"))]
17 use alloc
::string
::String
;
19 iter
::{Extend, FilterMap, FromIterator}
,
23 use tracing_core
::{Interest, Level, Metadata, Subscriber}
;
25 /// A filter that enables or disables spans and events based on their [target]
28 /// Targets are typically equal to the Rust module path of the code where the
29 /// span or event was recorded, although they may be overridden.
31 /// This type can be used for both [per-layer filtering][plf] (using its
32 /// [`Filter`] implementation) and [global filtering][global] (using its
33 /// [`Layer`] implementation).
35 /// See the [documentation on filtering with layers][filtering] for details.
37 /// # Filtering With `Targets`
39 /// A `Targets` filter consists of one or more [target] prefixes, paired with
40 /// [`LevelFilter`]s. If a span or event's [target] begins with one of those
41 /// prefixes, and its [level] is at or below the [`LevelFilter`] enabled for
42 /// that prefix, then the span or event will be enabled.
44 /// This is similar to the behavior implemented by the [`env_logger` crate] in
45 /// the `log` ecosystem.
47 /// The [`EnvFilter`] type also provided by this crate is very similar to `Targets`,
48 /// but is capable of a more sophisticated form of filtering where events may
49 /// also be enabled or disabled based on the span they are recorded in.
50 /// `Targets` can be thought of as a lighter-weight form of [`EnvFilter`] that
51 /// can be used instead when this dynamic filtering is not required.
55 /// A `Targets` filter can be constructed by programmatically adding targets and
59 /// use tracing_subscriber::{filter, prelude::*};
60 /// use tracing_core::Level;
62 /// let filter = filter::Targets::new()
63 /// // Enable the `INFO` level for anything in `my_crate`
64 /// .with_target("my_crate", Level::INFO)
65 /// // Enable the `DEBUG` level for a specific module.
66 /// .with_target("my_crate::interesting_module", Level::DEBUG);
68 /// // Build a new subscriber with the `fmt` layer using the `Targets`
69 /// // filter we constructed above.
70 /// tracing_subscriber::registry()
71 /// .with(tracing_subscriber::fmt::layer())
76 /// [`LevelFilter::OFF`] can be used to disable a particular target:
78 /// use tracing_subscriber::filter::{Targets, LevelFilter};
79 /// use tracing_core::Level;
81 /// let filter = Targets::new()
82 /// .with_target("my_crate", Level::INFO)
83 /// // Disable all traces from `annoying_module`.
84 /// .with_target("my_crate::annoying_module", LevelFilter::OFF);
88 /// Alternatively, `Targets` implements [`std::str::FromStr`], allowing it to be
89 /// parsed from a comma-delimited list of `target=level` pairs. For example:
92 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
93 /// use tracing_subscriber::filter;
94 /// use tracing_core::Level;
96 /// let filter = "my_crate=info,my_crate::interesting_module=trace,other_crate=debug"
97 /// .parse::<filter::Targets>()?;
99 /// // The parsed filter is identical to a filter constructed using `with_target`:
102 /// filter::Targets::new()
103 /// .with_target("my_crate", Level::INFO)
104 /// .with_target("my_crate::interesting_module", Level::TRACE)
105 /// .with_target("other_crate", Level::DEBUG)
110 /// This is particularly useful when the list of enabled targets is configurable
111 /// by the user at runtime.
113 /// The `Targets` filter can be used as a [per-layer filter][plf] *and* as a
114 /// [global filter][global]:
117 /// use tracing_subscriber::{
119 /// filter::{Targets, LevelFilter},
122 /// use tracing_core::Level;
123 /// use std::{sync::Arc, fs::File};
124 /// # fn docs() -> Result<(), Box<dyn std::error::Error>> {
126 /// // A layer that logs events to stdout using the human-readable "pretty"
128 /// let stdout_log = fmt::layer().pretty();
130 /// // A layer that logs events to a file, using the JSON format.
131 /// let file = File::create("debug_log.json")?;
132 /// let debug_log = fmt::layer()
133 /// .with_writer(Arc::new(file))
136 /// tracing_subscriber::registry()
137 /// // Only log INFO and above to stdout, unless the span or event
138 /// // has the `my_crate::cool_module` target prefix.
141 /// Targets::default()
142 /// .with_target("my_crate::cool_module", Level::DEBUG)
143 /// .with_default(Level::INFO)
146 /// // Log everything enabled by the global filter to `debug_log.json`.
148 /// // Configure a global filter for the whole subscriber stack. This will
149 /// // control what spans and events are recorded by both the `debug_log`
150 /// // and the `stdout_log` layers, and `stdout_log` will *additionally* be
151 /// // filtered by its per-layer filter.
153 /// Targets::default()
154 /// .with_target("my_crate", Level::TRACE)
155 /// .with_target("other_crate", Level::INFO)
156 /// .with_target("other_crate::annoying_module", LevelFilter::OFF)
157 /// .with_target("third_crate", Level::DEBUG)
162 /// [target]: tracing_core::Metadata::target
163 /// [level]: tracing_core::Level
164 /// [`Filter`]: crate::layer::Filter
165 /// [`Layer`]: crate::layer::Layer
166 /// [plf]: crate::layer#per-layer-filtering
167 /// [global]: crate::layer#global-filtering
168 /// [filtering]: crate::layer#filtering-with-layers
169 /// [`env_logger` crate]: https://docs.rs/env_logger/0.9.0/env_logger/index.html#enabling-logging
170 /// [`EnvFilter`]: crate::filter::EnvFilter
171 #[derive(Debug, Default, Clone, PartialEq)]
172 pub struct Targets(DirectiveSet
<StaticDirective
>);
175 /// Returns a new `Targets` filter.
177 /// This filter will enable no targets. Call [`with_target`] or [`with_targets`]
178 /// to add enabled targets, and [`with_default`] to change the default level
179 /// enabled for spans and events that didn't match any of the provided targets.
181 /// [`with_target`]: Targets::with_target
182 /// [`with_targets`]: Targets::with_targets
183 /// [`with_default`]: Targets::with_default
184 pub fn new() -> Self {
188 /// Enables spans and events with [target]s starting with the provided target
189 /// prefix if they are at or below the provided [`LevelFilter`].
194 /// use tracing_subscriber::filter;
195 /// use tracing_core::Level;
197 /// let filter = filter::Targets::new()
198 /// // Enable the `INFO` level for anything in `my_crate`
199 /// .with_target("my_crate", Level::INFO)
200 /// // Enable the `DEBUG` level for a specific module.
201 /// .with_target("my_crate::interesting_module", Level::DEBUG);
205 /// [`LevelFilter::OFF`] can be used to disable a particular target:
207 /// use tracing_subscriber::filter::{Targets, LevelFilter};
208 /// use tracing_core::Level;
210 /// let filter = Targets::new()
211 /// .with_target("my_crate", Level::INFO)
212 /// // Disable all traces from `annoying_module`.
213 /// .with_target("my_crate::interesting_module", LevelFilter::OFF);
217 /// [target]: tracing_core::Metadata::target
218 pub fn with_target(mut self, target
: impl Into
<String
>, level
: impl Into
<LevelFilter
>) -> Self {
219 self.0.add(StaticDirective
::new(
226 /// Adds [target]s from an iterator of [target]-[`LevelFilter`] pairs to this filter.
231 /// use tracing_subscriber::filter;
232 /// use tracing_core::Level;
234 /// let filter = filter::Targets::new()
235 /// .with_targets(vec![
236 /// ("my_crate", Level::INFO),
237 /// ("my_crate::some_module", Level::DEBUG),
238 /// ("my_crate::other_module::cool_stuff", Level::TRACE),
239 /// ("other_crate", Level::WARN)
244 /// [`LevelFilter::OFF`] can be used to disable a particular target:
246 /// use tracing_subscriber::filter::{Targets, LevelFilter};
247 /// use tracing_core::Level;
249 /// let filter = Targets::new()
250 /// .with_target("my_crate", Level::INFO)
251 /// // Disable all traces from `annoying_module`.
252 /// .with_target("my_crate::interesting_module", LevelFilter::OFF);
256 /// [target]: tracing_core::Metadata::target
257 pub fn with_targets
<T
, L
>(mut self, targets
: impl IntoIterator
<Item
= (T
, L
)>) -> Self
260 LevelFilter
: From
<L
>,
262 self.extend(targets
);
266 /// Sets the default level to enable for spans and events whose targets did
267 /// not match any of the configured prefixes.
269 /// By default, this is [`LevelFilter::OFF`]. This means that spans and
270 /// events will only be enabled if they match one of the configured target
271 /// prefixes. If this is changed to a different [`LevelFilter`], spans and
272 /// events with targets that did not match any of the configured prefixes
273 /// will be enabled if their level is at or below the provided level.
274 pub fn with_default(mut self, level
: impl Into
<LevelFilter
>) -> Self {
276 .add(StaticDirective
::new(None
, Default
::default(), level
.into()));
280 /// Returns an iterator over the [target]-[`LevelFilter`] pairs in this filter.
282 /// The order of iteration is undefined.
287 /// use tracing_subscriber::filter::{Targets, LevelFilter};
288 /// use tracing_core::Level;
290 /// let filter = Targets::new()
291 /// .with_target("my_crate", Level::INFO)
292 /// .with_target("my_crate::interesting_module", Level::DEBUG);
294 /// let mut targets: Vec<_> = filter.iter().collect();
297 /// assert_eq!(targets, vec![
298 /// ("my_crate", LevelFilter::INFO),
299 /// ("my_crate::interesting_module", LevelFilter::DEBUG),
303 /// [target]: tracing_core::Metadata::target
304 pub fn iter(&self) -> Iter
<'_
> {
309 fn interested(&self, metadata
: &'
static Metadata
<'
static>) -> Interest
{
310 if self.0.enabled(metadata
) {
317 /// Returns whether a [target]-[`Level`] pair would be enabled
318 /// by this `Targets`.
320 /// This method can be used with [`module_path!`] from `std` as the target
321 /// in order to emulate the behavior of the [`tracing::event!`] and [`tracing::span!`]
327 /// use tracing_subscriber::filter::{Targets, LevelFilter};
328 /// use tracing_core::Level;
330 /// let filter = Targets::new()
331 /// .with_target("my_crate", Level::INFO)
332 /// .with_target("my_crate::interesting_module", Level::DEBUG);
334 /// assert!(filter.would_enable("my_crate", &Level::INFO));
335 /// assert!(!filter.would_enable("my_crate::interesting_module", &Level::TRACE));
338 /// [target]: tracing_core::Metadata::target
339 /// [`module_path!`]: std::module_path!
340 pub fn would_enable(&self, target
: &str, level
: &Level
) -> bool
{
341 // "Correct" to call because `Targets` only produces `StaticDirective`'s with NO
343 self.0.target_enabled(target
, level
)
347 impl<T
, L
> Extend
<(T
, L
)> for Targets
350 L
: Into
<LevelFilter
>,
352 fn extend
<I
: IntoIterator
<Item
= (T
, L
)>>(&mut self, iter
: I
) {
353 let iter
= iter
.into_iter().map(|(target
, level
)| {
354 StaticDirective
::new(Some(target
.into()), Default
::default(), level
.into())
360 impl<T
, L
> FromIterator
<(T
, L
)> for Targets
363 L
: Into
<LevelFilter
>,
365 fn from_iter
<I
: IntoIterator
<Item
= (T
, L
)>>(iter
: I
) -> Self {
366 let mut this
= Self::default();
372 impl FromStr
for Targets
{
373 type Err
= ParseError
;
374 fn from_str(s
: &str) -> Result
<Self, Self::Err
> {
376 .map(StaticDirective
::from_str
)
377 .collect
::<Result
<_
, _
>>()
382 impl<S
> layer
::Layer
<S
> for Targets
386 fn enabled(&self, metadata
: &Metadata
<'_
>, _
: layer
::Context
<'_
, S
>) -> bool
{
387 self.0.enabled(metadata
)
390 fn register_callsite(&self, metadata
: &'
static Metadata
<'
static>) -> Interest
{
391 self.interested(metadata
)
394 fn max_level_hint(&self) -> Option
<LevelFilter
> {
395 Some(self.0.max_level
)
399 #[cfg(feature = "registry")]
400 #[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
401 impl<S
> layer
::Filter
<S
> for Targets
{
402 fn enabled(&self, metadata
: &Metadata
<'_
>, _
: &layer
::Context
<'_
, S
>) -> bool
{
403 self.0.enabled(metadata
)
406 fn callsite_enabled(&self, metadata
: &'
static Metadata
<'
static>) -> Interest
{
407 self.interested(metadata
)
410 fn max_level_hint(&self) -> Option
<LevelFilter
> {
411 Some(self.0.max_level
)
415 impl IntoIterator
for Targets
{
416 type Item
= (String
, LevelFilter
);
418 type IntoIter
= IntoIter
;
420 fn into_iter(self) -> Self::IntoIter
{
425 impl<'a
> IntoIterator
for &'a Targets
{
426 type Item
= (&'a
str, LevelFilter
);
428 type IntoIter
= Iter
<'a
>;
430 fn into_iter(self) -> Self::IntoIter
{
435 /// An owning iterator over the [target]-[level] pairs of a `Targets` filter.
437 /// This struct is created by the `IntoIterator` trait implementation of [`Targets`].
441 /// Merge the targets from one `Targets` with another:
444 /// use tracing_subscriber::filter::Targets;
445 /// use tracing_core::Level;
447 /// let mut filter = Targets::new().with_target("my_crate", Level::INFO);
448 /// let overrides = Targets::new().with_target("my_crate::interesting_module", Level::DEBUG);
450 /// filter.extend(overrides);
454 /// [target]: tracing_core::Metadata::target
455 /// [level]: tracing_core::Level
458 #[allow(clippy::type_complexity)] // alias indirection would probably make this more confusing
460 <DirectiveSet
<StaticDirective
> as IntoIterator
>::IntoIter
,
461 fn(StaticDirective
) -> Option
<(String
, LevelFilter
)>,
466 fn new(targets
: Targets
) -> Self {
467 Self(targets
.0.into_iter
().filter_map(|directive
| {
468 let level
= directive
.level
;
469 directive
.target
.map(|target
| (target
, level
))
474 impl Iterator
for IntoIter
{
475 type Item
= (String
, LevelFilter
);
477 fn next(&mut self) -> Option
<Self::Item
> {
481 fn size_hint(&self) -> (usize, Option
<usize>) {
486 /// A borrowing iterator over the [target]-[level] pairs of a `Targets` filter.
488 /// This struct is created by [`iter`] method of [`Targets`], or from the `IntoIterator`
489 /// implementation for `&Targets`.
491 /// [target]: tracing_core::Metadata::target
492 /// [level]: tracing_core::Level
493 /// [`iter`]: Targets::iter
497 slice
::Iter
<'a
, StaticDirective
>,
498 fn(&'a StaticDirective
) -> Option
<(&'a
str, LevelFilter
)>,
503 fn new(targets
: &'a Targets
) -> Self {
504 Self(targets
.0.iter
().filter_map(|directive
| {
508 .map(|target
| (target
, directive
.level
))
513 impl<'a
> Iterator
for Iter
<'a
> {
514 type Item
= (&'a
str, LevelFilter
);
516 fn next(&mut self) -> Option
<Self::Item
> {
520 fn size_hint(&self) -> (usize, Option
<usize>) {
530 #![not(feature = "std")]
531 use alloc
::{vec, vec::Vec, string::ToString}
;
533 // `dbg!` is only available with `libstd`; just nop it out when testing
540 fn expect_parse(s
: &str) -> Targets
{
541 match dbg
!(s
).parse
::<Targets
>() {
542 Err(e
) => panic
!("string {:?} did not parse successfully: {}", s
, e
),
547 fn expect_parse_ralith(s
: &str) {
548 let dirs
= expect_parse(s
).0.into_vec
();
549 assert_eq
!(dirs
.len(), 2, "\nparsed: {:#?}", dirs
);
550 assert_eq
!(dirs
[0].target
, Some("server".to_string()));
551 assert_eq
!(dirs
[0].level
, LevelFilter
::DEBUG
);
552 assert_eq
!(dirs
[0].field_names
, Vec
::<String
>::new());
554 assert_eq
!(dirs
[1].target
, Some("common".to_string()));
555 assert_eq
!(dirs
[1].level
, LevelFilter
::INFO
);
556 assert_eq
!(dirs
[1].field_names
, Vec
::<String
>::new());
559 fn expect_parse_level_directives(s
: &str) {
560 let dirs
= expect_parse(s
).0.into_vec
();
561 assert_eq
!(dirs
.len(), 6, "\nparsed: {:#?}", dirs
);
563 assert_eq
!(dirs
[0].target
, Some("crate3::mod2::mod1".to_string()));
564 assert_eq
!(dirs
[0].level
, LevelFilter
::OFF
);
565 assert_eq
!(dirs
[0].field_names
, Vec
::<String
>::new());
567 assert_eq
!(dirs
[1].target
, Some("crate1::mod2::mod3".to_string()));
568 assert_eq
!(dirs
[1].level
, LevelFilter
::INFO
);
569 assert_eq
!(dirs
[1].field_names
, Vec
::<String
>::new());
571 assert_eq
!(dirs
[2].target
, Some("crate1::mod2".to_string()));
572 assert_eq
!(dirs
[2].level
, LevelFilter
::WARN
);
573 assert_eq
!(dirs
[2].field_names
, Vec
::<String
>::new());
575 assert_eq
!(dirs
[3].target
, Some("crate1::mod1".to_string()));
576 assert_eq
!(dirs
[3].level
, LevelFilter
::ERROR
);
577 assert_eq
!(dirs
[3].field_names
, Vec
::<String
>::new());
579 assert_eq
!(dirs
[4].target
, Some("crate3".to_string()));
580 assert_eq
!(dirs
[4].level
, LevelFilter
::TRACE
);
581 assert_eq
!(dirs
[4].field_names
, Vec
::<String
>::new());
583 assert_eq
!(dirs
[5].target
, Some("crate2".to_string()));
584 assert_eq
!(dirs
[5].level
, LevelFilter
::DEBUG
);
585 assert_eq
!(dirs
[5].field_names
, Vec
::<String
>::new());
590 expect_parse_ralith("common=info,server=debug");
594 fn parse_ralith_uc() {
595 expect_parse_ralith("common=INFO,server=DEBUG");
599 fn parse_ralith_mixed() {
600 expect_parse("common=iNfo,server=dEbUg");
604 fn expect_parse_valid() {
605 let dirs
= expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off")
608 assert_eq
!(dirs
.len(), 4, "\nparsed: {:#?}", dirs
);
609 assert_eq
!(dirs
[0].target
, Some("crate1::mod2".to_string()));
610 assert_eq
!(dirs
[0].level
, LevelFilter
::TRACE
);
611 assert_eq
!(dirs
[0].field_names
, Vec
::<String
>::new());
613 assert_eq
!(dirs
[1].target
, Some("crate1::mod1".to_string()));
614 assert_eq
!(dirs
[1].level
, LevelFilter
::ERROR
);
615 assert_eq
!(dirs
[1].field_names
, Vec
::<String
>::new());
617 assert_eq
!(dirs
[2].target
, Some("crate3".to_string()));
618 assert_eq
!(dirs
[2].level
, LevelFilter
::OFF
);
619 assert_eq
!(dirs
[2].field_names
, Vec
::<String
>::new());
621 assert_eq
!(dirs
[3].target
, Some("crate2".to_string()));
622 assert_eq
!(dirs
[3].level
, LevelFilter
::DEBUG
);
623 assert_eq
!(dirs
[3].field_names
, Vec
::<String
>::new());
627 fn parse_level_directives() {
628 expect_parse_level_directives(
629 "crate1::mod1=error,crate1::mod2=warn,crate1::mod2::mod3=info,\
630 crate2=debug,crate3=trace,crate3::mod2::mod1=off",
635 fn parse_uppercase_level_directives() {
636 expect_parse_level_directives(
637 "crate1::mod1=ERROR,crate1::mod2=WARN,crate1::mod2::mod3=INFO,\
638 crate2=DEBUG,crate3=TRACE,crate3::mod2::mod1=OFF",
643 fn parse_numeric_level_directives() {
644 expect_parse_level_directives(
645 "crate1::mod1=1,crate1::mod2=2,crate1::mod2::mod3=3,crate2=4,\
646 crate3=5,crate3::mod2::mod1=0",
652 let filter
= expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off")
653 .with_default(LevelFilter
::WARN
);
655 let mut targets
: Vec
<_
> = filter
.iter().collect();
661 ("crate1::mod1", LevelFilter
::ERROR
),
662 ("crate1::mod2", LevelFilter
::TRACE
),
663 ("crate2", LevelFilter
::DEBUG
),
664 ("crate3", LevelFilter
::OFF
),
670 fn targets_into_iter() {
671 let filter
= expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off")
672 .with_default(LevelFilter
::WARN
);
674 let mut targets
: Vec
<_
> = filter
.into_iter().collect();
680 ("crate1::mod1".to_string(), LevelFilter
::ERROR
),
681 ("crate1::mod2".to_string(), LevelFilter
::TRACE
),
682 ("crate2".to_string(), LevelFilter
::DEBUG
),
683 ("crate3".to_string(), LevelFilter
::OFF
),
689 // `println!` is only available with `libstd`.
690 #[cfg(feature = "std")]
691 fn size_of_filters() {
692 fn print_sz(s
: &str) {
693 let filter
= s
.parse
::<Targets
>().expect("filter should parse");
695 "size_of_val({:?})\n -> {}B",
697 std
::mem
::size_of_val(&filter
)
703 print_sz("foo=debug");
706 "crate1::mod1=error,crate1::mod2=warn,crate1::mod2::mod3=info,\
707 crate2=debug,crate3=trace,crate3::mod2::mod1=off",