]>
Commit | Line | Data |
---|---|---|
f035d41b | 1 | //! Spans represent periods of time in the execution of a program. |
17df50a5 | 2 | use crate::field::FieldSet; |
f035d41b XL |
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 | /// | |
04454e1e FG |
13 | /// [`Subscriber`]: super::subscriber::Subscriber |
14 | /// [`new_span`]: super::subscriber::Subscriber::new_span | |
f035d41b XL |
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 | /// | |
04454e1e | 41 | /// [the `Subscriber` considers]: super::subscriber::Subscriber::current_span |
04454e1e | 42 | /// [`Metadata`]: super::metadata::Metadata |
f035d41b XL |
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 | /// | |
3dfed10e | 63 | /// <pre class="ignore" style="white-space:normal;font:inherit;"> |
c295e0f8 XL |
64 | /// <strong>Note</strong>: Span IDs must be greater than zero. |
65 | /// </pre> | |
f035d41b XL |
66 | /// |
67 | /// # Panics | |
c295e0f8 | 68 | /// - If the provided `u64` is 0. |
f035d41b XL |
69 | pub fn from_u64(u: u64) -> Self { |
70 | Id(NonZeroU64::new(u).expect("span IDs must be > 0")) | |
71 | } | |
72 | ||
3dfed10e XL |
73 | /// Constructs a new span ID from the given `NonZeroU64`. |
74 | /// | |
923072b8 | 75 | /// Unlike [`Id::from_u64`](Id::from_u64()), this will never panic. |
3dfed10e XL |
76 | #[inline] |
77 | pub const fn from_non_zero_u64(id: NonZeroU64) -> Self { | |
78 | Id(id) | |
79 | } | |
80 | ||
f035d41b XL |
81 | // Allow `into` by-ref since we don't want to impl Copy for Id |
82 | #[allow(clippy::wrong_self_convention)] | |
3dfed10e | 83 | /// Returns the span's ID as a `u64`. |
f035d41b XL |
84 | pub fn into_u64(&self) -> u64 { |
85 | self.0.get() | |
86 | } | |
3dfed10e XL |
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 | } | |
f035d41b XL |
95 | } |
96 | ||
17df50a5 XL |
97 | impl<'a> From<&'a Id> for Option<Id> { |
98 | fn from(id: &'a Id) -> Self { | |
99 | Some(id.clone()) | |
f035d41b XL |
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 { | |
17df50a5 | 153 | matches!(self.parent, Parent::Root) |
f035d41b XL |
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 { | |
17df50a5 | 164 | matches!(self.parent, Parent::Current) |
f035d41b XL |
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), | |
5099ac24 | 170 | /// returns `None`. |
f035d41b XL |
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 | /// | |
04454e1e | 181 | /// [visitor]: super::field::Visit |
f035d41b XL |
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 | } | |
17df50a5 XL |
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 | } | |
f035d41b XL |
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 | /// | |
04454e1e | 223 | /// [visitor]: super::field::Visit |
f035d41b XL |
224 | pub fn record(&self, visitor: &mut dyn field::Visit) { |
225 | self.values.record(visitor) | |
226 | } | |
227 | ||
923072b8 FG |
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 | ||
f035d41b XL |
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 | /// | |
923072b8 FG |
283 | /// [`id`]: Current::id() |
284 | /// [`metadata`]: Current::metadata() | |
285 | /// [`into_inner`]: Current::into_inner() | |
f035d41b | 286 | pub fn is_known(&self) -> bool { |
17df50a5 | 287 | !matches!(self.inner, CurrentInner::Unknown) |
f035d41b XL |
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 { | |
c295e0f8 | 310 | CurrentInner::Current { metadata, .. } => Some(metadata), |
f035d41b XL |
311 | _ => None, |
312 | } | |
313 | } | |
314 | } | |
315 | ||
17df50a5 XL |
316 | impl<'a> From<&'a Current> for Option<&'a Id> { |
317 | fn from(cur: &'a Current) -> Self { | |
318 | cur.id() | |
f035d41b XL |
319 | } |
320 | } | |
321 | ||
17df50a5 XL |
322 | impl<'a> From<&'a Current> for Option<Id> { |
323 | fn from(cur: &'a Current) -> Self { | |
324 | cur.id().cloned() | |
f035d41b XL |
325 | } |
326 | } | |
327 | ||
17df50a5 XL |
328 | impl From<Current> for Option<Id> { |
329 | fn from(cur: Current) -> Self { | |
330 | match cur.inner { | |
331 | CurrentInner::Current { id, .. } => Some(id), | |
332 | _ => None, | |
333 | } | |
f035d41b XL |
334 | } |
335 | } | |
336 | ||
17df50a5 XL |
337 | impl<'a> From<&'a Current> for Option<&'static Metadata<'static>> { |
338 | fn from(cur: &'a Current) -> Self { | |
339 | cur.metadata() | |
f035d41b XL |
340 | } |
341 | } |