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