//! 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`. /// ///
    ///     Note: Span IDs must be greater than zero.
    /// 
/// /// # 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 { 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 { fn from(cur: &'a Current) -> Self { cur.id().cloned() } } impl From for Option { 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() } }