1 | //! Spans represent periods of time in the execution of a program. |
2 | use crate::field::FieldSet; |
3 | use crate::parent::Parent; |
4 | use crate::stdlib::num::NonZeroU64; |
5 | use crate::{field, Metadata}; |
6 | |
7 | /// Identifies a span within the context of a subscriber. |
8 | /// |
9 | /// They are generated by [`Subscriber`]s for each span as it is created, by |
10 | /// the [`new_span`] trait method. See the documentation for that method for |
11 | /// more information on span ID generation. |
12 | /// |
13 | /// [`Subscriber`]: super::subscriber::Subscriber |
14 | /// [`new_span`]: super::subscriber::Subscriber::new_span |
15 | #[derive (Clone, Debug, PartialEq, Eq, Hash)] |
16 | pub struct Id(NonZeroU64); |
17 | |
18 | /// Attributes provided to a `Subscriber` describing a new span when it is |
19 | /// created. |
20 | #[derive (Debug)] |
21 | pub struct Attributes<'a> { |
22 | metadata: &'static Metadata<'static>, |
23 | values: &'a field::ValueSet<'a>, |
24 | parent: Parent, |
25 | } |
26 | |
27 | /// A set of fields recorded by a span. |
28 | #[derive (Debug)] |
29 | pub struct Record<'a> { |
30 | values: &'a field::ValueSet<'a>, |
31 | } |
32 | |
33 | /// Indicates what [the `Subscriber` considers] the "current" span. |
34 | /// |
35 | /// As subscribers may not track a notion of a current span, this has three |
36 | /// possible states: |
37 | /// - "unknown", indicating that the subscriber does not track a current span, |
38 | /// - "none", indicating that the current context is known to not be in a span, |
39 | /// - "some", with the current span's [`Id`] and [`Metadata`]. |
40 | /// |
41 | /// [the `Subscriber` considers]: super::subscriber::Subscriber::current_span |
42 | /// [`Metadata`]: super::metadata::Metadata |
43 | #[derive (Debug)] |
44 | pub struct Current { |
45 | inner: CurrentInner, |
46 | } |
47 | |
48 | #[derive (Debug)] |
49 | enum CurrentInner { |
50 | Current { |
51 | id: Id, |
52 | metadata: &'static Metadata<'static>, |
53 | }, |
54 | None, |
55 | Unknown, |
56 | } |
57 | |
58 | // ===== impl Span ===== |
59 | |
60 | impl Id { |
61 | /// Constructs a new span ID from the given `u64`. |
62 | /// |
63 | /// <pre class="ignore" style="white-space:normal;font:inherit;"> |
64 | /// <strong>Note</strong>: Span IDs must be greater than zero. |
65 | /// </pre> |
66 | /// |
67 | /// # Panics |
68 | /// - If the provided `u64` is 0. |
69 | pub fn from_u64(u: u64) -> Self { |
70 | Id(NonZeroU64::new(u).expect("span IDs must be > 0" )) |
71 | } |
72 | |
73 | /// Constructs a new span ID from the given `NonZeroU64`. |
74 | /// |
75 | /// Unlike [`Id::from_u64`](Id::from_u64()), this will never panic. |
76 | #[inline ] |
77 | pub const fn from_non_zero_u64(id: NonZeroU64) -> Self { |
78 | Id(id) |
79 | } |
80 | |
81 | // Allow `into` by-ref since we don't want to impl Copy for Id |
82 | #[allow (clippy::wrong_self_convention)] |
83 | /// Returns the span's ID as a `u64`. |
84 | pub fn into_u64(&self) -> u64 { |
85 | self.0.get() |
86 | } |
87 | |
88 | // Allow `into` by-ref since we don't want to impl Copy for Id |
89 | #[allow (clippy::wrong_self_convention)] |
90 | /// Returns the span's ID as a `NonZeroU64`. |
91 | #[inline ] |
92 | pub const fn into_non_zero_u64(&self) -> NonZeroU64 { |
93 | self.0 |
94 | } |
95 | } |
96 | |
97 | impl<'a> From<&'a Id> for Option<Id> { |
98 | fn from(id: &'a Id) -> Self { |
99 | Some(id.clone()) |
100 | } |
101 | } |
102 | |
103 | // ===== impl Attributes ===== |
104 | |
105 | impl<'a> Attributes<'a> { |
106 | /// Returns `Attributes` describing a new child span of the current span, |
107 | /// with the provided metadata and values. |
108 | pub fn new(metadata: &'static Metadata<'static>, values: &'a field::ValueSet<'a>) -> Self { |
109 | Attributes { |
110 | metadata, |
111 | values, |
112 | parent: Parent::Current, |
113 | } |
114 | } |
115 | |
116 | /// Returns `Attributes` describing a new span at the root of its own trace |
117 | /// tree, with the provided metadata and values. |
118 | pub fn new_root(metadata: &'static Metadata<'static>, values: &'a field::ValueSet<'a>) -> Self { |
119 | Attributes { |
120 | metadata, |
121 | values, |
122 | parent: Parent::Root, |
123 | } |
124 | } |
125 | |
126 | /// Returns `Attributes` describing a new child span of the specified |
127 | /// parent span, with the provided metadata and values. |
128 | pub fn child_of( |
129 | parent: Id, |
130 | metadata: &'static Metadata<'static>, |
131 | values: &'a field::ValueSet<'a>, |
132 | ) -> Self { |
133 | Attributes { |
134 | metadata, |
135 | values, |
136 | parent: Parent::Explicit(parent), |
137 | } |
138 | } |
139 | |
140 | /// Returns a reference to the new span's metadata. |
141 | pub fn metadata(&self) -> &'static Metadata<'static> { |
142 | self.metadata |
143 | } |
144 | |
145 | /// Returns a reference to a `ValueSet` containing any values the new span |
146 | /// was created with. |
147 | pub fn values(&self) -> &field::ValueSet<'a> { |
148 | self.values |
149 | } |
150 | |
151 | /// Returns true if the new span should be a root. |
152 | pub fn is_root(&self) -> bool { |
153 | matches!(self.parent, Parent::Root) |
154 | } |
155 | |
156 | /// Returns true if the new span's parent should be determined based on the |
157 | /// current context. |
158 | /// |
159 | /// If this is true and the current thread is currently inside a span, then |
160 | /// that span should be the new span's parent. Otherwise, if the current |
161 | /// thread is _not_ inside a span, then the new span will be the root of its |
162 | /// own trace tree. |
163 | pub fn is_contextual(&self) -> bool { |
164 | matches!(self.parent, Parent::Current) |
165 | } |
166 | |
167 | /// Returns the new span's explicitly-specified parent, if there is one. |
168 | /// |
169 | /// Otherwise (if the new span is a root or is a child of the current span), |
170 | /// returns `None`. |
171 | pub fn parent(&self) -> Option<&Id> { |
172 | match self.parent { |
173 | Parent::Explicit(ref p) => Some(p), |
174 | _ => None, |
175 | } |
176 | } |
177 | |
178 | /// Records all the fields in this set of `Attributes` with the provided |
179 | /// [Visitor]. |
180 | /// |
181 | /// [visitor]: super::field::Visit |
182 | pub fn record(&self, visitor: &mut dyn field::Visit) { |
183 | self.values.record(visitor) |
184 | } |
185 | |
186 | /// Returns `true` if this set of `Attributes` contains a value for the |
187 | /// given `Field`. |
188 | pub fn contains(&self, field: &field::Field) -> bool { |
189 | self.values.contains(field) |
190 | } |
191 | |
192 | /// Returns true if this set of `Attributes` contains _no_ values. |
193 | pub fn is_empty(&self) -> bool { |
194 | self.values.is_empty() |
195 | } |
196 | |
197 | /// Returns the set of all [fields] defined by this span's [`Metadata`]. |
198 | /// |
199 | /// Note that the [`FieldSet`] returned by this method includes *all* the |
200 | /// fields declared by this span, not just those with values that are recorded |
201 | /// as part of this set of `Attributes`. Other fields with values not present in |
202 | /// this `Attributes`' value set may [record] values later. |
203 | /// |
204 | /// [fields]: crate::field |
205 | /// [record]: Attributes::record() |
206 | /// [`Metadata`]: crate::metadata::Metadata |
207 | /// [`FieldSet`]: crate::field::FieldSet |
208 | pub fn fields(&self) -> &FieldSet { |
209 | self.values.field_set() |
210 | } |
211 | } |
212 | |
213 | // ===== impl Record ===== |
214 | |
215 | impl<'a> Record<'a> { |
216 | /// Constructs a new `Record` from a `ValueSet`. |
217 | pub fn new(values: &'a field::ValueSet<'a>) -> Self { |
218 | Self { values } |
219 | } |
220 | |
221 | /// Records all the fields in this `Record` with the provided [Visitor]. |
222 | /// |
223 | /// [visitor]: super::field::Visit |
224 | pub fn record(&self, visitor: &mut dyn field::Visit) { |
225 | self.values.record(visitor) |
226 | } |
227 | |
228 | /// Returns the number of fields that would be visited from this `Record` |
229 | /// when [`Record::record()`] is called |
230 | /// |
231 | /// [`Record::record()`]: Record::record() |
232 | pub fn len(&self) -> usize { |
233 | self.values.len() |
234 | } |
235 | |
236 | /// Returns `true` if this `Record` contains a value for the given `Field`. |
237 | pub fn contains(&self, field: &field::Field) -> bool { |
238 | self.values.contains(field) |
239 | } |
240 | |
241 | /// Returns true if this `Record` contains _no_ values. |
242 | pub fn is_empty(&self) -> bool { |
243 | self.values.is_empty() |
244 | } |
245 | } |
246 | |
247 | // ===== impl Current ===== |
248 | |
249 | impl Current { |
250 | /// Constructs a new `Current` that indicates the current context is a span |
251 | /// with the given `metadata` and `metadata`. |
252 | pub fn new(id: Id, metadata: &'static Metadata<'static>) -> Self { |
253 | Self { |
254 | inner: CurrentInner::Current { id, metadata }, |
255 | } |
256 | } |
257 | |
258 | /// Constructs a new `Current` that indicates the current context is *not* |
259 | /// in a span. |
260 | pub fn none() -> Self { |
261 | Self { |
262 | inner: CurrentInner::None, |
263 | } |
264 | } |
265 | |
266 | /// Constructs a new `Current` that indicates the `Subscriber` does not |
267 | /// track a current span. |
268 | pub(crate) fn unknown() -> Self { |
269 | Self { |
270 | inner: CurrentInner::Unknown, |
271 | } |
272 | } |
273 | |
274 | /// Returns `true` if the `Subscriber` that constructed this `Current` tracks a |
275 | /// current span. |
276 | /// |
277 | /// If this returns `true` and [`id`], [`metadata`], or [`into_inner`] |
278 | /// return `None`, that indicates that we are currently known to *not* be |
279 | /// inside a span. If this returns `false`, those methods will also return |
280 | /// `None`, but in this case, that is because the subscriber does not keep |
281 | /// track of the currently-entered span. |
282 | /// |
283 | /// [`id`]: Current::id() |
284 | /// [`metadata`]: Current::metadata() |
285 | /// [`into_inner`]: Current::into_inner() |
286 | pub fn is_known(&self) -> bool { |
287 | !matches!(self.inner, CurrentInner::Unknown) |
288 | } |
289 | |
290 | /// Consumes `self` and returns the span `Id` and `Metadata` of the current |
291 | /// span, if one exists and is known. |
292 | pub fn into_inner(self) -> Option<(Id, &'static Metadata<'static>)> { |
293 | match self.inner { |
294 | CurrentInner::Current { id, metadata } => Some((id, metadata)), |
295 | _ => None, |
296 | } |
297 | } |
298 | |
299 | /// Borrows the `Id` of the current span, if one exists and is known. |
300 | pub fn id(&self) -> Option<&Id> { |
301 | match self.inner { |
302 | CurrentInner::Current { ref id, .. } => Some(id), |
303 | _ => None, |
304 | } |
305 | } |
306 | |
307 | /// Borrows the `Metadata` of the current span, if one exists and is known. |
308 | pub fn metadata(&self) -> Option<&'static Metadata<'static>> { |
309 | match self.inner { |
310 | CurrentInner::Current { metadata, .. } => Some(metadata), |
311 | _ => None, |
312 | } |
313 | } |
314 | } |
315 | |
316 | impl<'a> From<&'a Current> for Option<&'a Id> { |
317 | fn from(cur: &'a Current) -> Self { |
318 | cur.id() |
319 | } |
320 | } |
321 | |
322 | impl<'a> From<&'a Current> for Option<Id> { |
323 | fn from(cur: &'a Current) -> Self { |
324 | cur.id().cloned() |
325 | } |
326 | } |
327 | |
328 | impl From<Current> for Option<Id> { |
329 | fn from(cur: Current) -> Self { |
330 | match cur.inner { |
331 | CurrentInner::Current { id: Id, .. } => Some(id), |
332 | _ => None, |
333 | } |
334 | } |
335 | } |
336 | |
337 | impl<'a> From<&'a Current> for Option<&'static Metadata<'static>> { |
338 | fn from(cur: &'a Current) -> Self { |
339 | cur.metadata() |
340 | } |
341 | } |
342 | |