Skip to main content

tracing_causality/
data.rs

1//! Data associated with spans.
2
3use crate::Span;
4use std::collections::{BTreeSet, HashSet};
5use std::fmt::Debug;
6
7/// The consequences — direct and indirect — of a `Span`.
8#[derive(Clone, Debug)]
9pub struct Consequences<M = crate::Metadata>
10where
11    M: Clone + Debug,
12{
13    pub(crate) direct: HashSet<Span<M>>,
14    pub(crate) indirect: HashSet<Span<M>>,
15}
16
17impl<M> Default for Consequences<M>
18where
19    M: Clone + Debug,
20{
21    fn default() -> Self {
22        Self {
23            direct: HashSet::default(),
24            indirect: HashSet::default(),
25        }
26    }
27}
28
29impl<M> Eq for Consequences<M> where M: Clone + Debug {}
30
31impl<M> PartialEq for Consequences<M>
32where
33    M: Clone + Debug,
34{
35    fn eq(&self, other: &Self) -> bool {
36        self.direct == other.direct && self.indirect == other.indirect
37    }
38}
39
40impl<M> Consequences<M>
41where
42    M: Clone + Debug,
43{
44    /// Constructs a new, empty `Consequences`.
45    pub fn none() -> Self {
46        Self {
47            direct: HashSet::default(),
48            indirect: HashSet::default(),
49        }
50    }
51
52    /// Constructs a `Consequences` with the given direct consequence.
53    pub fn with_direct(direct: Span<M>) -> Self {
54        let mut consequences = Self::none();
55        consequences.direct.insert(direct);
56        consequences
57    }
58
59    /// Constructs a `Consequences` with the given indirect consequence.
60    pub fn with_indirect(indirect: Span<M>) -> Self {
61        let mut consequences = Self::none();
62        consequences.indirect.insert(indirect);
63        consequences
64    }
65
66    /// Add the given direct consequence.
67    pub fn add_direct(&mut self, direct: Span<M>) {
68        self.direct.insert(direct);
69    }
70
71    /// Add the given indirect consequence.
72    pub fn add_indirect(&mut self, indirect: Span<M>) {
73        self.indirect.insert(indirect);
74    }
75
76    /// Remove the given direct consequence.
77    pub(crate) fn remove_direct(&mut self, direct: &Span<M>) {
78        self.direct.remove(direct);
79    }
80
81    /// Remove the given indirect consequence.
82    pub(crate) fn remove_indirect(&mut self, indirect: &Span<M>) {
83        self.indirect.remove(indirect);
84    }
85
86    /// Returns `true` if the given `id` is among this span's direct consequences.
87    ///
88    /// ```
89    /// use std::sync::Arc;
90    /// use tracing::{Subscriber, trace_span};
91    /// use tracing_causality::{self as causality, Consequences};
92    /// use tracing_subscriber::{prelude::*, registry::{LookupSpan, SpanData, Registry}};
93    ///
94    /// let subscriber: Arc<dyn Subscriber + Send + Sync > =
95    ///     Arc::new(Registry::default().with(causality::Layer));
96    /// subscriber.clone().init();
97    /// let subscriber: Arc<dyn Subscriber> = subscriber;
98    /// let registry = subscriber.downcast_ref::<Registry>().unwrap();
99    ///
100    /// let root = trace_span!("root");
101    /// let root_id_and_metadata = causality::Span {
102    ///     id: root.id().unwrap(),
103    ///     metadata: root.metadata().unwrap()
104    /// };
105    /// let consequence = root.in_scope(|| trace_span!("consequence"));
106    /// let consequence_id_and_metadata = causality::Span {
107    ///     id: consequence.id().unwrap(),
108    ///     metadata: consequence.metadata().unwrap()
109    /// };
110    ///
111    /// let root_data = registry.span_data(&root_id_and_metadata.id).unwrap();
112    /// let root_extensions = root_data.extensions();
113    /// let root_consequences = root_extensions.get::<Consequences>().unwrap();
114    /// assert!(root_consequences.contains_direct(&consequence_id_and_metadata));
115    /// ```
116    pub fn contains_direct(&self, span: &Span<M>) -> bool {
117        self.direct.contains(span)
118    }
119
120    /// Returns `true` if the given `id` is among this span's indirect consequences.
121    ///
122    /// ```
123    /// use std::sync::Arc;
124    /// use tracing::{Subscriber, trace_span};
125    /// use tracing_causality::{self as causality, Consequences};
126    /// use tracing_subscriber::{prelude::*, registry::{LookupSpan, SpanData, Registry}};
127    ///
128    /// let subscriber: Arc<dyn Subscriber + Send + Sync > =
129    ///     Arc::new(Registry::default().with(causality::Layer));
130    /// subscriber.clone().init();
131    /// let subscriber: Arc<dyn Subscriber> = subscriber;
132    /// let registry = subscriber.downcast_ref::<Registry>().unwrap();
133    ///
134    /// let root = trace_span!("root");
135    /// let root_id_and_metadata = causality::Span {
136    ///     id: root.id().unwrap(),
137    ///     metadata: root.metadata().unwrap()
138    /// };
139    /// let consequence = trace_span!("consequence");
140    /// let consequence_id_and_metadata = causality::Span {
141    ///     id: consequence.id().unwrap(),
142    ///     metadata: consequence.metadata().unwrap()
143    /// };
144    /// consequence.follows_from(&root_id_and_metadata.id);
145    ///
146    /// let root_data = registry.span_data(&root_id_and_metadata.id).unwrap();
147    /// let root_extensions = root_data.extensions();
148    /// let root_consequences = root_extensions.get::<Consequences>().unwrap();
149    /// assert!(root_consequences.contains_indirect(&consequence_id_and_metadata));
150    /// ```
151    pub fn contains_indirect(&self, span: &Span<M>) -> bool {
152        self.indirect.contains(span)
153    }
154
155    /// An iterator visiting all direct consequences in arbitrary order.
156    ///
157    /// ```
158    /// use std::sync::Arc;
159    /// use tracing::{Subscriber, trace_span};
160    /// use tracing_causality::{self as causality, Consequences};
161    /// use tracing_subscriber::{prelude::*, registry::{LookupSpan, SpanData, Registry}};
162    ///
163    /// let subscriber: Arc<dyn Subscriber + Send + Sync > =
164    ///     Arc::new(Registry::default().with(causality::Layer));
165    /// subscriber.clone().init();
166    /// let subscriber: Arc<dyn Subscriber> = subscriber;
167    /// let registry = subscriber.downcast_ref::<Registry>().unwrap();
168    ///
169    /// let root = trace_span!("root");
170    /// let root_id_and_metadata = causality::Span {
171    ///     id: root.id().unwrap(),
172    ///     metadata: root.metadata().unwrap()
173    /// };
174    /// let consequence = root.in_scope(|| trace_span!("consequence"));
175    /// let consequence_id_and_metadata = causality::Span {
176    ///     id: consequence.id().unwrap(),
177    ///     metadata: consequence.metadata().unwrap()
178    /// };
179    ///
180    /// let root_data = registry.span_data(&root_id_and_metadata.id).unwrap();
181    /// let root_extensions = root_data.extensions();
182    /// let root_consequences = root_extensions.get::<Consequences>().unwrap();
183    /// assert_eq!(
184    ///     root_consequences.iter_direct().next(),
185    ///     Some(consequence_id_and_metadata)
186    /// );
187    /// ```
188    pub fn iter_direct(&self) -> impl ExactSizeIterator<Item = Span<M>> + '_ {
189        self.direct.iter().cloned()
190    }
191
192    /// An iterator visiting all direct consequences in arbitrary order.
193    ///
194    /// ```
195    /// use std::sync::Arc;
196    /// use tracing::{Subscriber, trace_span};
197    /// use tracing_causality::{self as causality, Consequences};
198    /// use tracing_subscriber::{prelude::*, registry::{LookupSpan, SpanData, Registry}};
199    ///
200    /// let subscriber: Arc<dyn Subscriber + Send + Sync > =
201    ///     Arc::new(Registry::default().with(causality::Layer));
202    /// subscriber.clone().init();
203    /// let subscriber: Arc<dyn Subscriber> = subscriber;
204    /// let registry = subscriber.downcast_ref::<Registry>().unwrap();
205    ///
206    /// let root = trace_span!("root");
207    /// let root_id_and_metadata = causality::Span {
208    ///     id: root.id().unwrap(),
209    ///     metadata: root.metadata().unwrap()
210    /// };
211    /// let consequence = trace_span!("consequence");
212    /// let consequence_id_and_metadata = causality::Span {
213    ///     id: consequence.id().unwrap(),
214    ///     metadata: consequence.metadata().unwrap()
215    /// };
216    /// consequence.follows_from(&root_id_and_metadata.id);
217    ///
218    /// let root_data = registry.span_data(&root_id_and_metadata.id).unwrap();
219    /// let root_extensions = root_data.extensions();
220    /// let root_consequences = root_extensions.get::<Consequences>().unwrap();
221    /// assert_eq!(
222    ///     root_consequences.iter_indirect().next(),
223    ///     Some(consequence_id_and_metadata)
224    /// );
225    /// ```
226    pub fn iter_indirect(&self) -> impl ExactSizeIterator<Item = Span<M>> + '_ {
227        self.indirect.iter().cloned()
228    }
229}
230
231/// The indirect (`follows_from`) causes of a `Span`.
232pub struct IndirectCauses<M = crate::Metadata>
233where
234    M: Clone + Debug,
235{
236    pub(crate) causes: HashSet<Span<M>>,
237}
238
239impl<M> IndirectCauses<M>
240where
241    M: Clone + Debug,
242{
243    pub(crate) fn new() -> Self {
244        Self {
245            causes: HashSet::default(),
246        }
247    }
248
249    pub(crate) fn add_cause(&mut self, cause: Span<M>) {
250        self.causes.insert(cause);
251    }
252
253    pub(crate) fn with_cause(cause: Span<M>) -> Self {
254        let mut follows_from = Self::new();
255        follows_from.add_cause(cause);
256        follows_from
257    }
258
259    /// Returns `true` if the given `id` is among this span's indirect causes.
260    ///
261    /// ```
262    /// use std::sync::Arc;
263    /// use tracing::{Subscriber, trace_span};
264    /// use tracing_causality::{self as causality, data::IndirectCauses};
265    /// use tracing_subscriber::{prelude::*, registry::{LookupSpan, SpanData, Registry}};
266    ///
267    /// let subscriber: Arc<dyn Subscriber + Send + Sync > =
268    ///     Arc::new(Registry::default().with(causality::Layer));
269    /// subscriber.clone().init();
270    /// let subscriber: Arc<dyn Subscriber> = subscriber;
271    /// let registry = subscriber.downcast_ref::<Registry>().unwrap();
272    ///
273    /// let root = trace_span!("root");
274    /// let root_id_and_metadata = causality::Span {
275    ///     id: root.id().unwrap(),
276    ///     metadata: root.metadata().unwrap()
277    /// };
278    /// let consequence = trace_span!("consequence");
279    /// let consequence_id_and_metadata = causality::Span {
280    ///     id: consequence.id().unwrap(),
281    ///     metadata: consequence.metadata().unwrap()
282    /// };
283    /// consequence.follows_from(&root_id_and_metadata.id);
284    /// consequence.follows_from(&consequence_id_and_metadata.id);
285    ///
286    /// let consequence_data = registry.span_data(&consequence_id_and_metadata.id).unwrap();
287    /// let consequence_extensions = consequence_data.extensions();
288    /// let consequence_causes = consequence_extensions.get::<IndirectCauses>().unwrap();
289    /// assert!(consequence_causes.contains(&root_id_and_metadata));
290    /// assert!(consequence_causes.contains(&consequence_id_and_metadata));
291    /// ```
292    pub fn contains(&self, span: &Span<M>) -> bool {
293        self.causes.contains(span)
294    }
295
296    /// Produces an iterator over this span's indirect causes.
297    ///
298    /// ```
299    /// use std::sync::Arc;
300    /// use tracing::{Subscriber, trace_span};
301    /// use tracing_causality::{self as causality, data::IndirectCauses};
302    /// use tracing_subscriber::{prelude::*, registry::{LookupSpan, SpanData, Registry}};
303    ///
304    /// let subscriber: Arc<dyn Subscriber + Send + Sync > =
305    ///     Arc::new(Registry::default().with(causality::Layer));
306    /// subscriber.clone().init();
307    /// let subscriber: Arc<dyn Subscriber> = subscriber;
308    /// let registry = subscriber.downcast_ref::<Registry>().unwrap();
309    ///
310    /// let root = trace_span!("root");
311    /// let root_id_and_metadata = causality::Span {
312    ///     id: root.id().unwrap(),
313    ///     metadata: root.metadata().unwrap()
314    /// };
315    /// let consequence = trace_span!("consequence");
316    /// let consequence_id_and_metadata = causality::Span {
317    ///     id: consequence.id().unwrap(),
318    ///     metadata: consequence.metadata().unwrap()
319    /// };
320    /// consequence.follows_from(&root_id_and_metadata.id);
321    ///
322    /// let consequence_data = registry.span_data(&consequence_id_and_metadata.id).unwrap();
323    /// let consequence_extensions = consequence_data.extensions();
324    /// let consequence_causes = consequence_extensions.get::<IndirectCauses>().unwrap();
325    /// assert_eq!(
326    ///     consequence_causes.iter().next(),
327    ///     Some(&root_id_and_metadata)
328    /// );
329    /// ```
330    pub fn iter(&self) -> impl Iterator<Item = &Span<M>> {
331        self.causes.iter()
332    }
333}
334
335pub(crate) type Listeners = BTreeSet<crate::channel::Sender>;