1 //! Spans represent periods of time in the execution of a program. 2 use crate::field::FieldSet; 3 use crate::parent::Parent; 4 use crate::stdlib::num::NonZeroU64; 5 use 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)] 16 pub struct Id(NonZeroU64); 17 18 /// Attributes provided to a `Subscriber` describing a new span when it is 19 /// created. 20 #[derive(Debug)] 21 pub 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)] 29 pub 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)] 44 pub struct Current { 45 inner: CurrentInner, 46 } 47 48 #[derive(Debug)] 49 enum CurrentInner { 50 Current { 51 id: Id, 52 metadata: &'static Metadata<'static>, 53 }, 54 None, 55 Unknown, 56 } 57 58 // ===== impl Span ===== 59 60 impl 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. from_u64(u: u64) -> Self69 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] from_non_zero_u64(id: NonZeroU64) -> Self77 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`. into_u64(&self) -> u6484 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] into_non_zero_u64(&self) -> NonZeroU6492 pub const fn into_non_zero_u64(&self) -> NonZeroU64 { 93 self.0 94 } 95 } 96 97 impl<'a> From<&'a Id> for Option<Id> { from(id: &'a Id) -> Self98 fn from(id: &'a Id) -> Self { 99 Some(id.clone()) 100 } 101 } 102 103 // ===== impl Attributes ===== 104 105 impl<'a> Attributes<'a> { 106 /// Returns `Attributes` describing a new child span of the current span, 107 /// with the provided metadata and values. new(metadata: &'static Metadata<'static>, values: &'a field::ValueSet<'a>) -> Self108 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. new_root(metadata: &'static Metadata<'static>, values: &'a field::ValueSet<'a>) -> Self118 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. child_of( parent: Id, metadata: &'static Metadata<'static>, values: &'a field::ValueSet<'a>, ) -> Self128 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. metadata(&self) -> &'static Metadata<'static>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. values(&self) -> &field::ValueSet<'a>147 pub fn values(&self) -> &field::ValueSet<'a> { 148 self.values 149 } 150 151 /// Returns true if the new span should be a root. is_root(&self) -> bool152 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. is_contextual(&self) -> bool163 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`. parent(&self) -> Option<&Id>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 record(&self, visitor: &mut dyn 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`. contains(&self, field: &field::Field) -> bool188 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. is_empty(&self) -> bool193 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 fields(&self) -> &FieldSet208 pub fn fields(&self) -> &FieldSet { 209 self.values.field_set() 210 } 211 } 212 213 // ===== impl Record ===== 214 215 impl<'a> Record<'a> { 216 /// Constructs a new `Record` from a `ValueSet`. new(values: &'a field::ValueSet<'a>) -> Self217 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 record(&self, visitor: &mut dyn 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() len(&self) -> usize232 pub fn len(&self) -> usize { 233 self.values.len() 234 } 235 236 /// Returns `true` if this `Record` contains a value for the given `Field`. contains(&self, field: &field::Field) -> bool237 pub fn contains(&self, field: &field::Field) -> bool { 238 self.values.contains(field) 239 } 240 241 /// Returns true if this `Record` contains _no_ values. is_empty(&self) -> bool242 pub fn is_empty(&self) -> bool { 243 self.values.is_empty() 244 } 245 } 246 247 // ===== impl Current ===== 248 249 impl Current { 250 /// Constructs a new `Current` that indicates the current context is a span 251 /// with the given `metadata` and `metadata`. new(id: Id, metadata: &'static Metadata<'static>) -> Self252 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. none() -> Self260 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. unknown() -> Self268 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() is_known(&self) -> bool286 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. into_inner(self) -> Option<(Id, &'static Metadata<'static>)>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. id(&self) -> Option<&Id>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. metadata(&self) -> Option<&'static Metadata<'static>>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 316 impl<'a> From<&'a Current> for Option<&'a Id> { from(cur: &'a Current) -> Self317 fn from(cur: &'a Current) -> Self { 318 cur.id() 319 } 320 } 321 322 impl<'a> From<&'a Current> for Option<Id> { from(cur: &'a Current) -> Self323 fn from(cur: &'a Current) -> Self { 324 cur.id().cloned() 325 } 326 } 327 328 impl From<Current> for Option<Id> { from(cur: Current) -> Self329 fn from(cur: Current) -> Self { 330 match cur.inner { 331 CurrentInner::Current { id, .. } => Some(id), 332 _ => None, 333 } 334 } 335 } 336 337 impl<'a> From<&'a Current> for Option<&'static Metadata<'static>> { from(cur: &'a Current) -> Self338 fn from(cur: &'a Current) -> Self { 339 cur.metadata() 340 } 341 } 342