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`]: ../subscriber/trait.Subscriber.html 14 /// [`new_span`]: ../subscriber/trait.Subscriber.html#method.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]: ../subscriber/trait.Subscriber.html#method.current_span 42 /// [`Id`]: struct.Id.html 43 /// [`Metadata`]: ../metadata/struct.Metadata.html 44 #[derive(Debug)] 45 pub struct Current { 46 inner: CurrentInner, 47 } 48 49 #[derive(Debug)] 50 enum CurrentInner { 51 Current { 52 id: Id, 53 metadata: &'static Metadata<'static>, 54 }, 55 None, 56 Unknown, 57 } 58 59 // ===== impl Span ===== 60 61 impl Id { 62 /// Constructs a new span ID from the given `u64`. 63 /// 64 /// <div class="information"> 65 /// <div class="tooltip ignore" style="">ⓘ<span class="tooltiptext">Note</span></div> 66 /// </div> 67 /// <div class="example-wrap" style="display:inline-block"> 68 /// <pre class="ignore" style="white-space:normal;font:inherit;"> 69 /// <strong>Note</strong>: Span IDs must be greater than zero.</pre></div> 70 /// 71 /// # Panics 72 /// - If the provided `u64` is 0 from_u64(u: u64) -> Self73 pub fn from_u64(u: u64) -> Self { 74 Id(NonZeroU64::new(u).expect("span IDs must be > 0")) 75 } 76 77 /// Constructs a new span ID from the given `NonZeroU64`. 78 /// 79 /// Unlike [`Id::from_u64`](#method.from_u64), this will never panic. 80 #[inline] from_non_zero_u64(id: NonZeroU64) -> Self81 pub const fn from_non_zero_u64(id: NonZeroU64) -> Self { 82 Id(id) 83 } 84 85 // Allow `into` by-ref since we don't want to impl Copy for Id 86 #[allow(clippy::wrong_self_convention)] 87 /// Returns the span's ID as a `u64`. into_u64(&self) -> u6488 pub fn into_u64(&self) -> u64 { 89 self.0.get() 90 } 91 92 // Allow `into` by-ref since we don't want to impl Copy for Id 93 #[allow(clippy::wrong_self_convention)] 94 /// Returns the span's ID as a `NonZeroU64`. 95 #[inline] into_non_zero_u64(&self) -> NonZeroU6496 pub const fn into_non_zero_u64(&self) -> NonZeroU64 { 97 self.0 98 } 99 } 100 101 impl<'a> From<&'a Id> for Option<Id> { from(id: &'a Id) -> Self102 fn from(id: &'a Id) -> Self { 103 Some(id.clone()) 104 } 105 } 106 107 // ===== impl Attributes ===== 108 109 impl<'a> Attributes<'a> { 110 /// Returns `Attributes` describing a new child span of the current span, 111 /// with the provided metadata and values. new(metadata: &'static Metadata<'static>, values: &'a field::ValueSet<'a>) -> Self112 pub fn new(metadata: &'static Metadata<'static>, values: &'a field::ValueSet<'a>) -> Self { 113 Attributes { 114 metadata, 115 values, 116 parent: Parent::Current, 117 } 118 } 119 120 /// Returns `Attributes` describing a new span at the root of its own trace 121 /// tree, with the provided metadata and values. new_root(metadata: &'static Metadata<'static>, values: &'a field::ValueSet<'a>) -> Self122 pub fn new_root(metadata: &'static Metadata<'static>, values: &'a field::ValueSet<'a>) -> Self { 123 Attributes { 124 metadata, 125 values, 126 parent: Parent::Root, 127 } 128 } 129 130 /// Returns `Attributes` describing a new child span of the specified 131 /// parent span, with the provided metadata and values. child_of( parent: Id, metadata: &'static Metadata<'static>, values: &'a field::ValueSet<'a>, ) -> Self132 pub fn child_of( 133 parent: Id, 134 metadata: &'static Metadata<'static>, 135 values: &'a field::ValueSet<'a>, 136 ) -> Self { 137 Attributes { 138 metadata, 139 values, 140 parent: Parent::Explicit(parent), 141 } 142 } 143 144 /// Returns a reference to the new span's metadata. metadata(&self) -> &'static Metadata<'static>145 pub fn metadata(&self) -> &'static Metadata<'static> { 146 self.metadata 147 } 148 149 /// Returns a reference to a `ValueSet` containing any values the new span 150 /// was created with. values(&self) -> &field::ValueSet<'a>151 pub fn values(&self) -> &field::ValueSet<'a> { 152 self.values 153 } 154 155 /// Returns true if the new span should be a root. is_root(&self) -> bool156 pub fn is_root(&self) -> bool { 157 matches!(self.parent, Parent::Root) 158 } 159 160 /// Returns true if the new span's parent should be determined based on the 161 /// current context. 162 /// 163 /// If this is true and the current thread is currently inside a span, then 164 /// that span should be the new span's parent. Otherwise, if the current 165 /// thread is _not_ inside a span, then the new span will be the root of its 166 /// own trace tree. is_contextual(&self) -> bool167 pub fn is_contextual(&self) -> bool { 168 matches!(self.parent, Parent::Current) 169 } 170 171 /// Returns the new span's explicitly-specified parent, if there is one. 172 /// 173 /// Otherwise (if the new span is a root or is a child of the current span), 174 /// returns false. parent(&self) -> Option<&Id>175 pub fn parent(&self) -> Option<&Id> { 176 match self.parent { 177 Parent::Explicit(ref p) => Some(p), 178 _ => None, 179 } 180 } 181 182 /// Records all the fields in this set of `Attributes` with the provided 183 /// [Visitor]. 184 /// 185 /// [visitor]: ../field/trait.Visit.html record(&self, visitor: &mut dyn field::Visit)186 pub fn record(&self, visitor: &mut dyn field::Visit) { 187 self.values.record(visitor) 188 } 189 190 /// Returns `true` if this set of `Attributes` contains a value for the 191 /// given `Field`. contains(&self, field: &field::Field) -> bool192 pub fn contains(&self, field: &field::Field) -> bool { 193 self.values.contains(field) 194 } 195 196 /// Returns true if this set of `Attributes` contains _no_ values. is_empty(&self) -> bool197 pub fn is_empty(&self) -> bool { 198 self.values.is_empty() 199 } 200 201 /// Returns the set of all [fields] defined by this span's [`Metadata`]. 202 /// 203 /// Note that the [`FieldSet`] returned by this method includes *all* the 204 /// fields declared by this span, not just those with values that are recorded 205 /// as part of this set of `Attributes`. Other fields with values not present in 206 /// this `Attributes`' value set may [record] values later. 207 /// 208 /// [fields]: crate::field 209 /// [record]: Attributes::record() 210 /// [`Metadata`]: crate::metadata::Metadata 211 /// [`FieldSet`]: crate::field::FieldSet fields(&self) -> &FieldSet212 pub fn fields(&self) -> &FieldSet { 213 self.values.field_set() 214 } 215 } 216 217 // ===== impl Record ===== 218 219 impl<'a> Record<'a> { 220 /// Constructs a new `Record` from a `ValueSet`. new(values: &'a field::ValueSet<'a>) -> Self221 pub fn new(values: &'a field::ValueSet<'a>) -> Self { 222 Self { values } 223 } 224 225 /// Records all the fields in this `Record` with the provided [Visitor]. 226 /// 227 /// [visitor]: ../field/trait.Visit.html record(&self, visitor: &mut dyn field::Visit)228 pub fn record(&self, visitor: &mut dyn field::Visit) { 229 self.values.record(visitor) 230 } 231 232 /// Returns `true` if this `Record` contains a value for the given `Field`. contains(&self, field: &field::Field) -> bool233 pub fn contains(&self, field: &field::Field) -> bool { 234 self.values.contains(field) 235 } 236 237 /// Returns true if this `Record` contains _no_ values. is_empty(&self) -> bool238 pub fn is_empty(&self) -> bool { 239 self.values.is_empty() 240 } 241 } 242 243 // ===== impl Current ===== 244 245 impl Current { 246 /// Constructs a new `Current` that indicates the current context is a span 247 /// with the given `metadata` and `metadata`. new(id: Id, metadata: &'static Metadata<'static>) -> Self248 pub fn new(id: Id, metadata: &'static Metadata<'static>) -> Self { 249 Self { 250 inner: CurrentInner::Current { id, metadata }, 251 } 252 } 253 254 /// Constructs a new `Current` that indicates the current context is *not* 255 /// in a span. none() -> Self256 pub fn none() -> Self { 257 Self { 258 inner: CurrentInner::None, 259 } 260 } 261 262 /// Constructs a new `Current` that indicates the `Subscriber` does not 263 /// track a current span. unknown() -> Self264 pub(crate) fn unknown() -> Self { 265 Self { 266 inner: CurrentInner::Unknown, 267 } 268 } 269 270 /// Returns `true` if the `Subscriber` that constructed this `Current` tracks a 271 /// current span. 272 /// 273 /// If this returns `true` and [`id`], [`metadata`], or [`into_inner`] 274 /// return `None`, that indicates that we are currently known to *not* be 275 /// inside a span. If this returns `false`, those methods will also return 276 /// `None`, but in this case, that is because the subscriber does not keep 277 /// track of the currently-entered span. 278 /// 279 /// [`id`]: #method.id 280 /// [`metadata`]: #method.metadata 281 /// [`into_inner`]: #method.into_inner is_known(&self) -> bool282 pub fn is_known(&self) -> bool { 283 !matches!(self.inner, CurrentInner::Unknown) 284 } 285 286 /// Consumes `self` and returns the span `Id` and `Metadata` of the current 287 /// span, if one exists and is known. into_inner(self) -> Option<(Id, &'static Metadata<'static>)>288 pub fn into_inner(self) -> Option<(Id, &'static Metadata<'static>)> { 289 match self.inner { 290 CurrentInner::Current { id, metadata } => Some((id, metadata)), 291 _ => None, 292 } 293 } 294 295 /// Borrows the `Id` of the current span, if one exists and is known. id(&self) -> Option<&Id>296 pub fn id(&self) -> Option<&Id> { 297 match self.inner { 298 CurrentInner::Current { ref id, .. } => Some(id), 299 _ => None, 300 } 301 } 302 303 /// Borrows the `Metadata` of the current span, if one exists and is known. metadata(&self) -> Option<&'static Metadata<'static>>304 pub fn metadata(&self) -> Option<&'static Metadata<'static>> { 305 match self.inner { 306 CurrentInner::Current { ref metadata, .. } => Some(*metadata), 307 _ => None, 308 } 309 } 310 } 311 312 impl<'a> From<&'a Current> for Option<&'a Id> { from(cur: &'a Current) -> Self313 fn from(cur: &'a Current) -> Self { 314 cur.id() 315 } 316 } 317 318 impl<'a> From<&'a Current> for Option<Id> { from(cur: &'a Current) -> Self319 fn from(cur: &'a Current) -> Self { 320 cur.id().cloned() 321 } 322 } 323 324 impl From<Current> for Option<Id> { from(cur: Current) -> Self325 fn from(cur: Current) -> Self { 326 match cur.inner { 327 CurrentInner::Current { id, .. } => Some(id), 328 _ => None, 329 } 330 } 331 } 332 333 impl<'a> From<&'a Current> for Option<&'static Metadata<'static>> { from(cur: &'a Current) -> Self334 fn from(cur: &'a Current) -> Self { 335 cur.metadata() 336 } 337 } 338