tracing_core/
span.rs

1//! Spans represent periods of time in the execution of a program.
2use crate::field::FieldSet;
3use crate::parent::Parent;
4use crate::stdlib::num::NonZeroU64;
5use 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)]
16pub struct Id(NonZeroU64);
17
18/// Attributes provided to a `Subscriber` describing a new span when it is
19/// created.
20#[derive(Debug)]
21pub 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)]
29pub 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)]
44pub struct Current {
45    inner: CurrentInner,
46}
47
48#[derive(Debug)]
49enum CurrentInner {
50    Current {
51        id: Id,
52        metadata: &'static Metadata<'static>,
53    },
54    None,
55    Unknown,
56}
57
58// ===== impl Span =====
59
60impl 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
97impl<'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
105impl<'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
215impl<'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
249impl 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
316impl<'a> From<&'a Current> for Option<&'a Id> {
317    fn from(cur: &'a Current) -> Self {
318        cur.id()
319    }
320}
321
322impl<'a> From<&'a Current> for Option<Id> {
323    fn from(cur: &'a Current) -> Self {
324        cur.id().cloned()
325    }
326}
327
328impl From<Current> for Option<Id> {
329    fn from(cur: Current) -> Self {
330        match cur.inner {
331            CurrentInner::Current { id, .. } => Some(id),
332            _ => None,
333        }
334    }
335}
336
337impl<'a> From<&'a Current> for Option<&'static Metadata<'static>> {
338    fn from(cur: &'a Current) -> Self {
339        cur.metadata()
340    }
341}