tracing_capture/predicates/level.rs
1//! `level()` predicate factory.
2
3use predicates::{
4 reflection::{Case, PredicateReflection},
5 Predicate,
6};
7use tracing_core::{Level, LevelFilter};
8
9use std::fmt;
10
11use crate::Captured;
12
13/// Conversion into a predicate for [`Level`]s used in the [`level()`] function.
14pub trait IntoLevelPredicate {
15 /// Predicate output of the conversion. The exact type should be considered an implementation
16 /// detail and should not be relied upon.
17 type Predicate: Predicate<Level>;
18 /// Performs the conversion.
19 fn into_predicate(self) -> Self::Predicate;
20}
21
22impl<P: Predicate<Level>> IntoLevelPredicate for [P; 1] {
23 type Predicate = P;
24
25 fn into_predicate(self) -> Self::Predicate {
26 self.into_iter().next().unwrap()
27 }
28}
29
30impl IntoLevelPredicate for Level {
31 type Predicate = predicates::ord::EqPredicate<Level>;
32
33 fn into_predicate(self) -> Self::Predicate {
34 predicates::ord::eq(self)
35 }
36}
37
38impl IntoLevelPredicate for LevelFilter {
39 type Predicate = predicates::ord::OrdPredicate<Level>;
40
41 fn into_predicate(self) -> Self::Predicate {
42 self.into_level()
43 .map_or_else(|| predicates::ord::lt(Level::ERROR), predicates::ord::le)
44 }
45}
46
47/// Creates a predicate for the [`Level`] of a [`CapturedSpan`] or [`CapturedEvent`].
48///
49/// # Arguments
50///
51/// The argument of this function may be:
52///
53/// - [`Level`]: will be compared exactly
54/// - [`LevelFilter`]: will be compared as per ordinary rules
55/// - Any `Predicate` for [`Level`]. To bypass Rust orphaning rules, the predicate
56/// must be enclosed in square brackets (i.e., a one-value array).
57///
58/// [`CapturedSpan`]: crate::CapturedSpan
59/// [`CapturedEvent`]: crate::CapturedEvent
60///
61/// # Examples
62///
63/// ```
64/// # use predicates::ord::gt;
65/// # use tracing_core::{Level, LevelFilter};
66/// # use tracing_subscriber::{layer::SubscriberExt, Registry};
67/// # use tracing_capture::{predicates::{level, ScanExt}, CaptureLayer, SharedStorage};
68/// let storage = SharedStorage::default();
69/// let subscriber = Registry::default().with(CaptureLayer::new(&storage));
70/// tracing::subscriber::with_default(subscriber, || {
71/// tracing::info_span!("compute").in_scope(|| {
72/// tracing::info!(answer = 42, "done");
73/// });
74/// });
75///
76/// let storage = storage.lock();
77/// // All of these access the single captured span.
78/// let spans = storage.scan_spans();
79/// let _ = spans.single(&level(Level::INFO));
80/// let _ = spans.first(&level(LevelFilter::DEBUG));
81/// let _ = spans.last(&level([gt(Level::WARN)]));
82/// ```
83pub fn level<P: IntoLevelPredicate>(matches: P) -> LevelPredicate<P::Predicate> {
84 LevelPredicate {
85 matches: matches.into_predicate(),
86 }
87}
88
89/// Predicate for the [`Level`] of a [`CapturedSpan`] or [`CapturedEvent`] returned by
90/// the [`level()`] function.
91///
92/// [`CapturedSpan`]: crate::CapturedSpan
93/// [`CapturedEvent`]: crate::CapturedEvent
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95pub struct LevelPredicate<P> {
96 matches: P,
97}
98
99impl_bool_ops!(LevelPredicate<P>);
100
101impl<P: Predicate<Level>> fmt::Display for LevelPredicate<P> {
102 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
103 write!(formatter, "level({})", self.matches)
104 }
105}
106
107impl<P: Predicate<Level>> PredicateReflection for LevelPredicate<P> {}
108
109impl<'a, P: Predicate<Level>, T: Captured<'a>> Predicate<T> for LevelPredicate<P> {
110 fn eval(&self, variable: &T) -> bool {
111 self.matches.eval(variable.metadata().level())
112 }
113
114 fn find_case(&self, expected: bool, variable: &T) -> Option<Case<'_>> {
115 let child = self
116 .matches
117 .find_case(expected, variable.metadata().level())?;
118 Some(Case::new(Some(self), expected).add_child(child))
119 }
120}