]> git.proxmox.com Git - rustc.git/blame - vendor/tracing-subscriber/src/filter/targets.rs
New upstream version 1.62.1+dfsg1
[rustc.git] / vendor / tracing-subscriber / src / filter / targets.rs
CommitLineData
c295e0f8
XL
1//! A [filter] that enables or disables spans and events based on their [target] and [level].
2//!
3//! See [`Targets`] for details.
4//!
5//! [target]: tracing_core::Metadata::target
6//! [level]: tracing_core::Level
7//! [filter]: crate::layer#filtering-with-layers
8
9use crate::{
10 filter::{
11 directive::{DirectiveSet, ParseError, StaticDirective},
12 LevelFilter,
13 },
14 layer,
15};
a2a8927a
XL
16#[cfg(not(feature = "std"))]
17use alloc::string::String;
18use core::{
c295e0f8 19 iter::{Extend, FilterMap, FromIterator},
a2a8927a 20 slice,
c295e0f8
XL
21 str::FromStr,
22};
5099ac24 23use tracing_core::{Interest, Level, Metadata, Subscriber};
c295e0f8
XL
24
25/// A filter that enables or disables spans and events based on their [target]
26/// and [level].
27///
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.
30///
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).
34///
35/// See the [documentation on filtering with layers][filtering] for details.
36///
37/// # Filtering With `Targets`
38///
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.
43///
44/// This is similar to the behavior implemented by the [`env_logger` crate] in
45/// the `log` ecosystem.
46///
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.
52///
53/// # Examples
54///
55/// A `Targets` filter can be constructed by programmatically adding targets and
56/// levels to enable:
57///
58/// ```
59/// use tracing_subscriber::{filter, prelude::*};
60/// use tracing_core::Level;
61///
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);
67///
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())
72/// .with(filter)
73/// .init();
74/// ```
75///
76/// [`LevelFilter::OFF`] can be used to disable a particular target:
77/// ```
78/// use tracing_subscriber::filter::{Targets, LevelFilter};
79/// use tracing_core::Level;
80///
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);
85/// # drop(filter);
86/// ```
87///
88/// Alternatively, `Targets` implements [`std::str::FromStr`], allowing it to be
89/// parsed from a comma-delimited list of `target=level` pairs. For example:
90///
91/// ```rust
92/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
93/// use tracing_subscriber::filter;
94/// use tracing_core::Level;
95///
96/// let filter = "my_crate=info,my_crate::interesting_module=trace,other_crate=debug"
97/// .parse::<filter::Targets>()?;
98///
99/// // The parsed filter is identical to a filter constructed using `with_target`:
100/// assert_eq!(
101/// filter,
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)
106/// );
107/// # Ok(()) }
108/// ```
109///
110/// This is particularly useful when the list of enabled targets is configurable
111/// by the user at runtime.
112///
113/// The `Targets` filter can be used as a [per-layer filter][plf] *and* as a
04454e1e 114/// [global filter][global]:
c295e0f8
XL
115///
116/// ```rust
117/// use tracing_subscriber::{
118/// fmt,
119/// filter::{Targets, LevelFilter},
120/// prelude::*,
121/// };
122/// use tracing_core::Level;
123/// use std::{sync::Arc, fs::File};
3c0e092e 124/// # fn docs() -> Result<(), Box<dyn std::error::Error>> {
c295e0f8
XL
125///
126/// // A layer that logs events to stdout using the human-readable "pretty"
127/// // format.
128/// let stdout_log = fmt::layer().pretty();
129///
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))
134/// .json();
135///
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.
139/// .with(stdout_log
140/// .with_filter(
141/// Targets::default()
142/// .with_target("my_crate::cool_module", Level::DEBUG)
143/// .with_default(Level::INFO)
144/// )
145/// )
146/// // Log everything enabled by the global filter to `debug_log.json`.
147/// .with(debug_log)
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.
152/// .with(
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)
158/// ).init();
159/// # Ok(()) }
160///```
161///
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)]
172pub struct Targets(DirectiveSet<StaticDirective>);
173
174impl Targets {
175 /// Returns a new `Targets` filter.
176 ///
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.
180 ///
181 /// [`with_target`]: Targets::with_target
182 /// [`with_targets`]: Targets::with_targets
183 /// [`with_default`]: Targets::with_default
184 pub fn new() -> Self {
185 Self::default()
186 }
187
188 /// Enables spans and events with [target]s starting with the provided target
189 /// prefix if they are at or below the provided [`LevelFilter`].
190 ///
191 /// # Examples
192 ///
193 /// ```
194 /// use tracing_subscriber::filter;
195 /// use tracing_core::Level;
196 ///
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);
202 /// # drop(filter);
203 /// ```
204 ///
205 /// [`LevelFilter::OFF`] can be used to disable a particular target:
206 /// ```
207 /// use tracing_subscriber::filter::{Targets, LevelFilter};
208 /// use tracing_core::Level;
209 ///
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);
214 /// # drop(filter);
215 /// ```
216 ///
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(
220 Some(target.into()),
221 Default::default(),
222 level.into(),
223 ));
224 self
225 }
226 /// Adds [target]s from an iterator of [target]-[`LevelFilter`] pairs to this filter.
227 ///
228 /// # Examples
229 ///
230 /// ```
231 /// use tracing_subscriber::filter;
232 /// use tracing_core::Level;
233 ///
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)
240 /// ]);
241 /// # drop(filter);
242 /// ```
243 ///
244 /// [`LevelFilter::OFF`] can be used to disable a particular target:
245 /// ```
246 /// use tracing_subscriber::filter::{Targets, LevelFilter};
247 /// use tracing_core::Level;
248 ///
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);
253 /// # drop(filter);
254 /// ```
255 ///
256 /// [target]: tracing_core::Metadata::target
257 pub fn with_targets<T, L>(mut self, targets: impl IntoIterator<Item = (T, L)>) -> Self
258 where
259 String: From<T>,
260 LevelFilter: From<L>,
261 {
262 self.extend(targets);
263 self
264 }
265
266 /// Sets the default level to enable for spans and events whose targets did
267 /// not match any of the configured prefixes.
268 ///
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 {
275 self.0
276 .add(StaticDirective::new(None, Default::default(), level.into()));
277 self
278 }
279
280 /// Returns an iterator over the [target]-[`LevelFilter`] pairs in this filter.
281 ///
282 /// The order of iteration is undefined.
283 ///
284 /// # Examples
285 ///
286 /// ```
287 /// use tracing_subscriber::filter::{Targets, LevelFilter};
288 /// use tracing_core::Level;
289 ///
290 /// let filter = Targets::new()
291 /// .with_target("my_crate", Level::INFO)
292 /// .with_target("my_crate::interesting_module", Level::DEBUG);
293 ///
294 /// let mut targets: Vec<_> = filter.iter().collect();
295 /// targets.sort();
296 ///
297 /// assert_eq!(targets, vec![
298 /// ("my_crate", LevelFilter::INFO),
299 /// ("my_crate::interesting_module", LevelFilter::DEBUG),
300 /// ]);
301 /// ```
302 ///
303 /// [target]: tracing_core::Metadata::target
304 pub fn iter(&self) -> Iter<'_> {
305 self.into_iter()
306 }
307
308 #[inline]
309 fn interested(&self, metadata: &'static Metadata<'static>) -> Interest {
310 if self.0.enabled(metadata) {
311 Interest::always()
312 } else {
313 Interest::never()
314 }
315 }
5099ac24
FG
316
317 /// Returns whether a [target]-[`Level`] pair would be enabled
318 /// by this `Targets`.
319 ///
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!`]
322 /// macros.
323 ///
324 /// # Examples
325 ///
326 /// ```
327 /// use tracing_subscriber::filter::{Targets, LevelFilter};
328 /// use tracing_core::Level;
329 ///
330 /// let filter = Targets::new()
331 /// .with_target("my_crate", Level::INFO)
332 /// .with_target("my_crate::interesting_module", Level::DEBUG);
333 ///
334 /// assert!(filter.would_enable("my_crate", &Level::INFO));
335 /// assert!(!filter.would_enable("my_crate::interesting_module", &Level::TRACE));
336 /// ```
337 ///
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
342 // fields
343 self.0.target_enabled(target, level)
344 }
c295e0f8
XL
345}
346
347impl<T, L> Extend<(T, L)> for Targets
348where
349 T: Into<String>,
350 L: Into<LevelFilter>,
351{
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())
355 });
356 self.0.extend(iter);
357 }
358}
359
360impl<T, L> FromIterator<(T, L)> for Targets
361where
362 T: Into<String>,
363 L: Into<LevelFilter>,
364{
365 fn from_iter<I: IntoIterator<Item = (T, L)>>(iter: I) -> Self {
366 let mut this = Self::default();
367 this.extend(iter);
368 this
369 }
370}
371
372impl FromStr for Targets {
373 type Err = ParseError;
374 fn from_str(s: &str) -> Result<Self, Self::Err> {
375 s.split(',')
376 .map(StaticDirective::from_str)
377 .collect::<Result<_, _>>()
378 .map(Self)
379 }
380}
381
382impl<S> layer::Layer<S> for Targets
383where
384 S: Subscriber,
385{
386 fn enabled(&self, metadata: &Metadata<'_>, _: layer::Context<'_, S>) -> bool {
387 self.0.enabled(metadata)
388 }
389
390 fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
391 self.interested(metadata)
392 }
393
394 fn max_level_hint(&self) -> Option<LevelFilter> {
395 Some(self.0.max_level)
396 }
397}
398
399#[cfg(feature = "registry")]
400#[cfg_attr(docsrs, doc(cfg(feature = "registry")))]
401impl<S> layer::Filter<S> for Targets {
402 fn enabled(&self, metadata: &Metadata<'_>, _: &layer::Context<'_, S>) -> bool {
403 self.0.enabled(metadata)
404 }
405
406 fn callsite_enabled(&self, metadata: &'static Metadata<'static>) -> Interest {
407 self.interested(metadata)
408 }
409
410 fn max_level_hint(&self) -> Option<LevelFilter> {
411 Some(self.0.max_level)
412 }
413}
414
415impl IntoIterator for Targets {
416 type Item = (String, LevelFilter);
417
418 type IntoIter = IntoIter;
419
420 fn into_iter(self) -> Self::IntoIter {
421 IntoIter::new(self)
422 }
423}
424
425impl<'a> IntoIterator for &'a Targets {
426 type Item = (&'a str, LevelFilter);
427
428 type IntoIter = Iter<'a>;
429
430 fn into_iter(self) -> Self::IntoIter {
431 Iter::new(self)
432 }
433}
434
435/// An owning iterator over the [target]-[level] pairs of a `Targets` filter.
436///
437/// This struct is created by the `IntoIterator` trait implementation of [`Targets`].
438///
439/// # Examples
440///
441/// Merge the targets from one `Targets` with another:
442///
443/// ```
444/// use tracing_subscriber::filter::Targets;
445/// use tracing_core::Level;
446///
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);
449///
450/// filter.extend(overrides);
451/// # drop(filter);
452/// ```
453///
454/// [target]: tracing_core::Metadata::target
455/// [level]: tracing_core::Level
456#[derive(Debug)]
457pub struct IntoIter(
458 #[allow(clippy::type_complexity)] // alias indirection would probably make this more confusing
459 FilterMap<
460 <DirectiveSet<StaticDirective> as IntoIterator>::IntoIter,
461 fn(StaticDirective) -> Option<(String, LevelFilter)>,
462 >,
463);
464
465impl IntoIter {
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))
470 }))
471 }
472}
473
474impl Iterator for IntoIter {
475 type Item = (String, LevelFilter);
476
477 fn next(&mut self) -> Option<Self::Item> {
478 self.0.next()
479 }
480
481 fn size_hint(&self) -> (usize, Option<usize>) {
482 self.0.size_hint()
483 }
484}
485
486/// A borrowing iterator over the [target]-[level] pairs of a `Targets` filter.
487///
488/// This struct is created by [`iter`] method of [`Targets`], or from the `IntoIterator`
489/// implementation for `&Targets`.
490///
491/// [target]: tracing_core::Metadata::target
492/// [level]: tracing_core::Level
493/// [`iter`]: Targets::iter
494#[derive(Debug)]
495pub struct Iter<'a>(
496 FilterMap<
a2a8927a 497 slice::Iter<'a, StaticDirective>,
c295e0f8
XL
498 fn(&'a StaticDirective) -> Option<(&'a str, LevelFilter)>,
499 >,
500);
501
502impl<'a> Iter<'a> {
503 fn new(targets: &'a Targets) -> Self {
504 Self(targets.0.iter().filter_map(|directive| {
505 directive
506 .target
507 .as_deref()
508 .map(|target| (target, directive.level))
509 }))
510 }
511}
512
513impl<'a> Iterator for Iter<'a> {
514 type Item = (&'a str, LevelFilter);
515
516 fn next(&mut self) -> Option<Self::Item> {
517 self.0.next()
518 }
519
520 fn size_hint(&self) -> (usize, Option<usize>) {
521 self.0.size_hint()
522 }
523}
524
525#[cfg(test)]
526mod tests {
527 use super::*;
528
a2a8927a
XL
529 feature! {
530 #![not(feature = "std")]
531 use alloc::{vec, vec::Vec, string::ToString};
532
533 // `dbg!` is only available with `libstd`; just nop it out when testing
534 // with alloc only.
535 macro_rules! dbg {
536 ($x:expr) => { $x }
537 }
538 }
539
c295e0f8
XL
540 fn expect_parse(s: &str) -> Targets {
541 match dbg!(s).parse::<Targets>() {
542 Err(e) => panic!("string {:?} did not parse successfully: {}", s, e),
543 Ok(e) => e,
544 }
545 }
546
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());
553
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());
557 }
558
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);
562
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());
566
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());
570
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());
574
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());
578
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());
582
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());
586 }
587
588 #[test]
589 fn parse_ralith() {
590 expect_parse_ralith("common=info,server=debug");
591 }
592
593 #[test]
594 fn parse_ralith_uc() {
595 expect_parse_ralith("common=INFO,server=DEBUG");
596 }
597
598 #[test]
599 fn parse_ralith_mixed() {
600 expect_parse("common=iNfo,server=dEbUg");
601 }
602
603 #[test]
604 fn expect_parse_valid() {
605 let dirs = expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off")
606 .0
607 .into_vec();
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());
612
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());
616
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());
620
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());
624 }
625
626 #[test]
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",
631 )
632 }
633
634 #[test]
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",
639 )
640 }
641
642 #[test]
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",
647 )
648 }
649
650 #[test]
651 fn targets_iter() {
652 let filter = expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off")
653 .with_default(LevelFilter::WARN);
654
655 let mut targets: Vec<_> = filter.iter().collect();
656 targets.sort();
657
658 assert_eq!(
659 targets,
660 vec![
661 ("crate1::mod1", LevelFilter::ERROR),
662 ("crate1::mod2", LevelFilter::TRACE),
663 ("crate2", LevelFilter::DEBUG),
664 ("crate3", LevelFilter::OFF),
665 ]
666 );
667 }
668
669 #[test]
670 fn targets_into_iter() {
671 let filter = expect_parse("crate1::mod1=error,crate1::mod2,crate2=debug,crate3=off")
672 .with_default(LevelFilter::WARN);
673
674 let mut targets: Vec<_> = filter.into_iter().collect();
675 targets.sort();
676
677 assert_eq!(
678 targets,
679 vec![
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),
684 ]
685 );
686 }
687
688 #[test]
a2a8927a
XL
689 // `println!` is only available with `libstd`.
690 #[cfg(feature = "std")]
c295e0f8
XL
691 fn size_of_filters() {
692 fn print_sz(s: &str) {
693 let filter = s.parse::<Targets>().expect("filter should parse");
694 println!(
695 "size_of_val({:?})\n -> {}B",
696 s,
697 std::mem::size_of_val(&filter)
698 );
699 }
700
701 print_sz("info");
702
703 print_sz("foo=debug");
704
705 print_sz(
706 "crate1::mod1=error,crate1::mod2=warn,crate1::mod2::mod3=info,\
707 crate2=debug,crate3=trace,crate3::mod2::mod1=off",
708 );
709 }
710}