| //! Spans represent periods of time in the execution of a program. |
| use crate::field::FieldSet; |
| use crate::parent::Parent; |
| use crate::stdlib::num::NonZeroU64; |
| use crate::{field, Metadata}; |
| |
| /// Identifies a span within the context of a subscriber. |
| /// |
| /// They are generated by [`Subscriber`]s for each span as it is created, by |
| /// the [`new_span`] trait method. See the documentation for that method for |
| /// more information on span ID generation. |
| /// |
| /// [`Subscriber`]: super::subscriber::Subscriber |
| /// [`new_span`]: super::subscriber::Subscriber::new_span |
| #[derive(Clone, Debug, PartialEq, Eq, Hash)] |
| pub struct Id(NonZeroU64); |
| |
| /// Attributes provided to a `Subscriber` describing a new span when it is |
| /// created. |
| #[derive(Debug)] |
| pub struct Attributes<'a> { |
| metadata: &'static Metadata<'static>, |
| values: &'a field::ValueSet<'a>, |
| parent: Parent, |
| } |
| |
| /// A set of fields recorded by a span. |
| #[derive(Debug)] |
| pub struct Record<'a> { |
| values: &'a field::ValueSet<'a>, |
| } |
| |
| /// Indicates what [the `Subscriber` considers] the "current" span. |
| /// |
| /// As subscribers may not track a notion of a current span, this has three |
| /// possible states: |
| /// - "unknown", indicating that the subscriber does not track a current span, |
| /// - "none", indicating that the current context is known to not be in a span, |
| /// - "some", with the current span's [`Id`] and [`Metadata`]. |
| /// |
| /// [the `Subscriber` considers]: super::subscriber::Subscriber::current_span |
| /// [`Metadata`]: super::metadata::Metadata |
| #[derive(Debug)] |
| pub struct Current { |
| inner: CurrentInner, |
| } |
| |
| #[derive(Debug)] |
| enum CurrentInner { |
| Current { |
| id: Id, |
| metadata: &'static Metadata<'static>, |
| }, |
| None, |
| Unknown, |
| } |
| |
| // ===== impl Span ===== |
| |
| impl Id { |
| /// Constructs a new span ID from the given `u64`. |
| /// |
| /// <pre class="ignore" style="white-space:normal;font:inherit;"> |
| /// <strong>Note</strong>: Span IDs must be greater than zero. |
| /// </pre> |
| /// |
| /// # Panics |
| /// - If the provided `u64` is 0. |
| pub fn from_u64(u: u64) -> Self { |
| Id(NonZeroU64::new(u).expect("span IDs must be > 0")) |
| } |
| |
| /// Constructs a new span ID from the given `NonZeroU64`. |
| /// |
| /// Unlike [`Id::from_u64`](Id::from_u64()), this will never panic. |
| #[inline] |
| pub const fn from_non_zero_u64(id: NonZeroU64) -> Self { |
| Id(id) |
| } |
| |
| // Allow `into` by-ref since we don't want to impl Copy for Id |
| #[allow(clippy::wrong_self_convention)] |
| /// Returns the span's ID as a `u64`. |
| pub fn into_u64(&self) -> u64 { |
| self.0.get() |
| } |
| |
| // Allow `into` by-ref since we don't want to impl Copy for Id |
| #[allow(clippy::wrong_self_convention)] |
| /// Returns the span's ID as a `NonZeroU64`. |
| #[inline] |
| pub const fn into_non_zero_u64(&self) -> NonZeroU64 { |
| self.0 |
| } |
| } |
| |
| impl<'a> From<&'a Id> for Option<Id> { |
| fn from(id: &'a Id) -> Self { |
| Some(id.clone()) |
| } |
| } |
| |
| // ===== impl Attributes ===== |
| |
| impl<'a> Attributes<'a> { |
| /// Returns `Attributes` describing a new child span of the current span, |
| /// with the provided metadata and values. |
| pub fn new(metadata: &'static Metadata<'static>, values: &'a field::ValueSet<'a>) -> Self { |
| Attributes { |
| metadata, |
| values, |
| parent: Parent::Current, |
| } |
| } |
| |
| /// Returns `Attributes` describing a new span at the root of its own trace |
| /// tree, with the provided metadata and values. |
| pub fn new_root(metadata: &'static Metadata<'static>, values: &'a field::ValueSet<'a>) -> Self { |
| Attributes { |
| metadata, |
| values, |
| parent: Parent::Root, |
| } |
| } |
| |
| /// Returns `Attributes` describing a new child span of the specified |
| /// parent span, with the provided metadata and values. |
| pub fn child_of( |
| parent: Id, |
| metadata: &'static Metadata<'static>, |
| values: &'a field::ValueSet<'a>, |
| ) -> Self { |
| Attributes { |
| metadata, |
| values, |
| parent: Parent::Explicit(parent), |
| } |
| } |
| |
| /// Returns a reference to the new span's metadata. |
| pub fn metadata(&self) -> &'static Metadata<'static> { |
| self.metadata |
| } |
| |
| /// Returns a reference to a `ValueSet` containing any values the new span |
| /// was created with. |
| pub fn values(&self) -> &field::ValueSet<'a> { |
| self.values |
| } |
| |
| /// Returns true if the new span should be a root. |
| pub fn is_root(&self) -> bool { |
| matches!(self.parent, Parent::Root) |
| } |
| |
| /// Returns true if the new span's parent should be determined based on the |
| /// current context. |
| /// |
| /// If this is true and the current thread is currently inside a span, then |
| /// that span should be the new span's parent. Otherwise, if the current |
| /// thread is _not_ inside a span, then the new span will be the root of its |
| /// own trace tree. |
| pub fn is_contextual(&self) -> bool { |
| matches!(self.parent, Parent::Current) |
| } |
| |
| /// Returns the new span's explicitly-specified parent, if there is one. |
| /// |
| /// Otherwise (if the new span is a root or is a child of the current span), |
| /// returns `None`. |
| pub fn parent(&self) -> Option<&Id> { |
| match self.parent { |
| Parent::Explicit(ref p) => Some(p), |
| _ => None, |
| } |
| } |
| |
| /// Records all the fields in this set of `Attributes` with the provided |
| /// [Visitor]. |
| /// |
| /// [visitor]: super::field::Visit |
| pub fn record(&self, visitor: &mut dyn field::Visit) { |
| self.values.record(visitor) |
| } |
| |
| /// Returns `true` if this set of `Attributes` contains a value for the |
| /// given `Field`. |
| pub fn contains(&self, field: &field::Field) -> bool { |
| self.values.contains(field) |
| } |
| |
| /// Returns true if this set of `Attributes` contains _no_ values. |
| pub fn is_empty(&self) -> bool { |
| self.values.is_empty() |
| } |
| |
| /// Returns the set of all [fields] defined by this span's [`Metadata`]. |
| /// |
| /// Note that the [`FieldSet`] returned by this method includes *all* the |
| /// fields declared by this span, not just those with values that are recorded |
| /// as part of this set of `Attributes`. Other fields with values not present in |
| /// this `Attributes`' value set may [record] values later. |
| /// |
| /// [fields]: crate::field |
| /// [record]: Attributes::record() |
| /// [`Metadata`]: crate::metadata::Metadata |
| /// [`FieldSet`]: crate::field::FieldSet |
| pub fn fields(&self) -> &FieldSet { |
| self.values.field_set() |
| } |
| } |
| |
| // ===== impl Record ===== |
| |
| impl<'a> Record<'a> { |
| /// Constructs a new `Record` from a `ValueSet`. |
| pub fn new(values: &'a field::ValueSet<'a>) -> Self { |
| Self { values } |
| } |
| |
| /// Records all the fields in this `Record` with the provided [Visitor]. |
| /// |
| /// [visitor]: super::field::Visit |
| pub fn record(&self, visitor: &mut dyn field::Visit) { |
| self.values.record(visitor) |
| } |
| |
| /// Returns the number of fields that would be visited from this `Record` |
| /// when [`Record::record()`] is called |
| /// |
| /// [`Record::record()`]: Record::record() |
| pub fn len(&self) -> usize { |
| self.values.len() |
| } |
| |
| /// Returns `true` if this `Record` contains a value for the given `Field`. |
| pub fn contains(&self, field: &field::Field) -> bool { |
| self.values.contains(field) |
| } |
| |
| /// Returns true if this `Record` contains _no_ values. |
| pub fn is_empty(&self) -> bool { |
| self.values.is_empty() |
| } |
| } |
| |
| // ===== impl Current ===== |
| |
| impl Current { |
| /// Constructs a new `Current` that indicates the current context is a span |
| /// with the given `metadata` and `metadata`. |
| pub fn new(id: Id, metadata: &'static Metadata<'static>) -> Self { |
| Self { |
| inner: CurrentInner::Current { id, metadata }, |
| } |
| } |
| |
| /// Constructs a new `Current` that indicates the current context is *not* |
| /// in a span. |
| pub fn none() -> Self { |
| Self { |
| inner: CurrentInner::None, |
| } |
| } |
| |
| /// Constructs a new `Current` that indicates the `Subscriber` does not |
| /// track a current span. |
| pub(crate) fn unknown() -> Self { |
| Self { |
| inner: CurrentInner::Unknown, |
| } |
| } |
| |
| /// Returns `true` if the `Subscriber` that constructed this `Current` tracks a |
| /// current span. |
| /// |
| /// If this returns `true` and [`id`], [`metadata`], or [`into_inner`] |
| /// return `None`, that indicates that we are currently known to *not* be |
| /// inside a span. If this returns `false`, those methods will also return |
| /// `None`, but in this case, that is because the subscriber does not keep |
| /// track of the currently-entered span. |
| /// |
| /// [`id`]: Current::id() |
| /// [`metadata`]: Current::metadata() |
| /// [`into_inner`]: Current::into_inner() |
| pub fn is_known(&self) -> bool { |
| !matches!(self.inner, CurrentInner::Unknown) |
| } |
| |
| /// Consumes `self` and returns the span `Id` and `Metadata` of the current |
| /// span, if one exists and is known. |
| pub fn into_inner(self) -> Option<(Id, &'static Metadata<'static>)> { |
| match self.inner { |
| CurrentInner::Current { id, metadata } => Some((id, metadata)), |
| _ => None, |
| } |
| } |
| |
| /// Borrows the `Id` of the current span, if one exists and is known. |
| pub fn id(&self) -> Option<&Id> { |
| match self.inner { |
| CurrentInner::Current { ref id, .. } => Some(id), |
| _ => None, |
| } |
| } |
| |
| /// Borrows the `Metadata` of the current span, if one exists and is known. |
| pub fn metadata(&self) -> Option<&'static Metadata<'static>> { |
| match self.inner { |
| CurrentInner::Current { metadata, .. } => Some(metadata), |
| _ => None, |
| } |
| } |
| } |
| |
| impl<'a> From<&'a Current> for Option<&'a Id> { |
| fn from(cur: &'a Current) -> Self { |
| cur.id() |
| } |
| } |
| |
| impl<'a> From<&'a Current> for Option<Id> { |
| fn from(cur: &'a Current) -> Self { |
| cur.id().cloned() |
| } |
| } |
| |
| impl From<Current> for Option<Id> { |
| fn from(cur: Current) -> Self { |
| match cur.inner { |
| CurrentInner::Current { id, .. } => Some(id), |
| _ => None, |
| } |
| } |
| } |
| |
| impl<'a> From<&'a Current> for Option<&'static Metadata<'static>> { |
| fn from(cur: &'a Current) -> Self { |
| cur.metadata() |
| } |
| } |