tracing_core/
span.rs

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