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: 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}
342