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>;