tracing_capture/predicates/
parent.rs

1//! `parent()` predicate factory.
2
3use std::{fmt, iter};
4
5use predicates::{
6    reflection::{Case, PredicateReflection, Product},
7    Predicate,
8};
9
10use crate::{Captured, CapturedSpan};
11
12/// Creates a predicate for the direct parent [`CapturedSpan`] of a span or a [`CapturedEvent`].
13///
14/// [`CapturedEvent`]: crate::CapturedEvent
15///
16/// # Examples
17///
18/// ```
19/// # use predicates::ord::eq;
20/// # use tracing_core::Level;
21/// # use tracing_subscriber::{layer::SubscriberExt, Registry};
22/// # use tracing_capture::{predicates::*, CaptureLayer, SharedStorage};
23/// let storage = SharedStorage::default();
24/// let subscriber = Registry::default().with(CaptureLayer::new(&storage));
25/// tracing::subscriber::with_default(subscriber, || {
26///     tracing::info_span!("compute").in_scope(|| {
27///         tracing::info!(answer = 42, "done");
28///     });
29/// });
30///
31/// let storage = storage.lock();
32/// let parent_pred = level(Level::INFO) & name(eq("compute"));
33/// let _ = storage.scan_events().single(&parent(parent_pred));
34/// ```
35pub fn parent<P>(matches: P) -> ParentPredicate<P>
36where
37    P: for<'a> Predicate<CapturedSpan<'a>>,
38{
39    ParentPredicate { matches }
40}
41
42/// Predicate for the parent of a [`CapturedSpan`] or [`CapturedEvent`] returned
43/// by the [`parent()`] function.
44///
45/// [`CapturedEvent`]: crate::CapturedEvent
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub struct ParentPredicate<P> {
48    matches: P,
49}
50
51impl_bool_ops!(ParentPredicate<P>);
52
53impl<P> fmt::Display for ParentPredicate<P>
54where
55    P: for<'a> Predicate<CapturedSpan<'a>>,
56{
57    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
58        write!(formatter, "parent({})", self.matches)
59    }
60}
61
62impl<P> PredicateReflection for ParentPredicate<P> where P: for<'a> Predicate<CapturedSpan<'a>> {}
63
64impl<'a, P, T> Predicate<T> for ParentPredicate<P>
65where
66    T: Captured<'a>,
67    P: for<'p> Predicate<CapturedSpan<'p>>,
68{
69    fn eval(&self, variable: &T) -> bool {
70        let parent = variable.parent();
71        parent.is_some_and(|parent| self.matches.eval(&parent))
72    }
73
74    fn find_case(&self, expected: bool, variable: &T) -> Option<Case<'_>> {
75        let Some(parent) = variable.parent() else {
76            return if expected {
77                None // was expecting a parent, but there is none
78            } else {
79                let product = Product::new("parent", "None");
80                Some(Case::new(Some(self), expected).add_product(product))
81            };
82        };
83
84        let child = self.matches.find_case(expected, &parent)?;
85        Some(Case::new(Some(self), expected).add_child(child))
86    }
87}
88
89/// Creates a predicate for ancestor [`CapturedSpan`]s of a span or a [`CapturedEvent`].
90/// The predicate is true iff the wrapped span predicate holds true for *any* of the ancestors.
91///
92/// [`CapturedEvent`]: crate::CapturedEvent
93///
94/// # Examples
95///
96/// ```
97/// # use predicates::ord::eq;
98/// # use tracing_core::Level;
99/// # use tracing_subscriber::{layer::SubscriberExt, Registry};
100/// # use tracing_capture::{predicates::*, CaptureLayer, SharedStorage};
101/// let storage = SharedStorage::default();
102/// let subscriber = Registry::default().with(CaptureLayer::new(&storage));
103/// tracing::subscriber::with_default(subscriber, || {
104///     let _entered = tracing::info_span!("wrapper").entered();
105///     tracing::info_span!("compute").in_scope(|| {
106///         tracing::info!(answer = 42, "done");
107///     });
108/// });
109///
110/// let storage = storage.lock();
111/// let parent_pred = level(Level::INFO) & name(eq("wrapper"));
112/// let _ = storage.scan_events().single(&ancestor(parent_pred));
113/// ```
114pub fn ancestor<P>(matches: P) -> AncestorPredicate<P>
115where
116    P: for<'a> Predicate<CapturedSpan<'a>>,
117{
118    AncestorPredicate { matches }
119}
120
121/// Predicate for the ancestors of a [`CapturedSpan`] or [`CapturedEvent`] returned
122/// by the [`ancestor()`] function.
123///
124/// [`CapturedEvent`]: crate::CapturedEvent
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
126pub struct AncestorPredicate<P> {
127    matches: P,
128}
129
130impl_bool_ops!(AncestorPredicate<P>);
131
132impl<P> fmt::Display for AncestorPredicate<P>
133where
134    P: for<'a> Predicate<CapturedSpan<'a>>,
135{
136    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
137        write!(formatter, "ancestor({})", self.matches)
138    }
139}
140
141impl<P> PredicateReflection for AncestorPredicate<P> where P: for<'a> Predicate<CapturedSpan<'a>> {}
142
143impl<'a, P, T> Predicate<T> for AncestorPredicate<P>
144where
145    T: Captured<'a>,
146    P: for<'p> Predicate<CapturedSpan<'p>>,
147{
148    fn eval(&self, variable: &T) -> bool {
149        let mut ancestors = iter::successors(variable.parent(), CapturedSpan::parent);
150        ancestors.any(|span| self.matches.eval(&span))
151    }
152
153    fn find_case(&self, expected: bool, variable: &T) -> Option<Case<'_>> {
154        let mut ancestors = iter::successors(variable.parent(), CapturedSpan::parent);
155        if expected {
156            // Return the first of ancestor cases.
157            let child = ancestors.find_map(|span| self.matches.find_case(expected, &span))?;
158            Some(Case::new(Some(self), expected).add_child(child))
159        } else {
160            // Need all ancestor cases.
161            let case = Case::new(Some(self), expected);
162            ancestors.try_fold(case, |case, span| {
163                let child = self.matches.find_case(expected, &span)?;
164                Some(case.add_child(child))
165            })
166        }
167    }
168}