1 use tracing_core::{metadata::Metadata, span, subscriber::Subscriber, Event}; 2 3 use crate::registry::{self, LookupSpan, SpanRef}; 4 5 #[cfg(all(feature = "registry", feature = "std"))] 6 use crate::{filter::FilterId, registry::Registry}; 7 /// Represents information about the current context provided to [`Layer`]s by the 8 /// wrapped [`Subscriber`]. 9 /// 10 /// To access [stored data] keyed by a span ID, implementors of the `Layer` 11 /// trait should ensure that the `Subscriber` type parameter is *also* bound by the 12 /// [`LookupSpan`]: 13 /// 14 /// ```rust 15 /// use tracing::Subscriber; 16 /// use tracing_subscriber::{Layer, registry::LookupSpan}; 17 /// 18 /// pub struct MyLayer; 19 /// 20 /// impl<S> Layer<S> for MyLayer 21 /// where 22 /// S: Subscriber + for<'a> LookupSpan<'a>, 23 /// { 24 /// // ... 25 /// } 26 /// ``` 27 /// 28 /// [`Layer`]: super::Layer 29 /// [`Subscriber`]: tracing_core::Subscriber 30 /// [stored data]: crate::registry::SpanRef 31 /// [`LookupSpan`]: crate::registry::LookupSpan 32 #[derive(Debug)] 33 pub struct Context<'a, S> { 34 subscriber: Option<&'a S>, 35 /// The bitmask of all [`Filtered`] layers that currently apply in this 36 /// context. If there is only a single [`Filtered`] wrapping the layer that 37 /// produced this context, then this is that filter's ID. Otherwise, if we 38 /// are in a nested tree with multiple filters, this is produced by 39 /// [`and`]-ing together the [`FilterId`]s of each of the filters that wrap 40 /// the current layer. 41 /// 42 /// [`Filtered`]: crate::filter::Filtered 43 /// [`FilterId`]: crate::filter::FilterId 44 /// [`and`]: crate::filter::FilterId::and 45 #[cfg(all(feature = "registry", feature = "std"))] 46 filter: FilterId, 47 } 48 49 // === impl Context === 50 51 impl<'a, S> Context<'a, S> 52 where 53 S: Subscriber, 54 { new(subscriber: &'a S) -> Self55 pub(super) fn new(subscriber: &'a S) -> Self { 56 Self { 57 subscriber: Some(subscriber), 58 59 #[cfg(feature = "registry")] 60 filter: FilterId::none(), 61 } 62 } 63 64 /// Returns the wrapped subscriber's view of the current span. 65 #[inline] current_span(&self) -> span::Current66 pub fn current_span(&self) -> span::Current { 67 self.subscriber 68 .map(Subscriber::current_span) 69 // TODO: this would be more correct as "unknown", so perhaps 70 // `tracing-core` should make `Current::unknown()` public? 71 .unwrap_or_else(span::Current::none) 72 } 73 74 /// Returns whether the wrapped subscriber would enable the current span. 75 #[inline] enabled(&self, metadata: &Metadata<'_>) -> bool76 pub fn enabled(&self, metadata: &Metadata<'_>) -> bool { 77 self.subscriber 78 .map(|subscriber| subscriber.enabled(metadata)) 79 // If this context is `None`, we are registering a callsite, so 80 // return `true` so that the layer does not incorrectly assume that 81 // the inner subscriber has disabled this metadata. 82 // TODO(eliza): would it be more correct for this to return an `Option`? 83 .unwrap_or(true) 84 } 85 86 /// Records the provided `event` with the wrapped subscriber. 87 /// 88 /// # Notes 89 /// 90 /// - The subscriber is free to expect that the event's callsite has been 91 /// [registered][register], and may panic or fail to observe the event if this is 92 /// not the case. The `tracing` crate's macros ensure that all events are 93 /// registered, but if the event is constructed through other means, the 94 /// user is responsible for ensuring that [`register_callsite`][register] 95 /// has been called prior to calling this method. 96 /// - This does _not_ call [`enabled`] on the inner subscriber. If the 97 /// caller wishes to apply the wrapped subscriber's filter before choosing 98 /// whether to record the event, it may first call [`Context::enabled`] to 99 /// check whether the event would be enabled. This allows `Layer`s to 100 /// elide constructing the event if it would not be recorded. 101 /// 102 /// [register]: tracing_core::subscriber::Subscriber::register_callsite() 103 /// [`enabled`]: tracing_core::subscriber::Subscriber::enabled() 104 /// [`Context::enabled`]: Context::enabled() 105 #[inline] event(&self, event: &Event<'_>)106 pub fn event(&self, event: &Event<'_>) { 107 if let Some(subscriber) = self.subscriber { 108 subscriber.event(event); 109 } 110 } 111 112 /// Returns a [`SpanRef`] for the parent span of the given [`Event`], if 113 /// it has a parent. 114 /// 115 /// If the event has an explicitly overridden parent, this method returns 116 /// a reference to that span. If the event's parent is the current span, 117 /// this returns a reference to the current span, if there is one. If this 118 /// returns `None`, then either the event's parent was explicitly set to 119 /// `None`, or the event's parent was defined contextually, but no span 120 /// is currently entered. 121 /// 122 /// Compared to [`Context::current_span`] and [`Context::lookup_current`], 123 /// this respects overrides provided by the [`Event`]. 124 /// 125 /// Compared to [`Event::parent`], this automatically falls back to the contextual 126 /// span, if required. 127 /// 128 /// ```rust 129 /// use tracing::{Event, Subscriber}; 130 /// use tracing_subscriber::{ 131 /// layer::{Context, Layer}, 132 /// prelude::*, 133 /// registry::LookupSpan, 134 /// }; 135 /// 136 /// struct PrintingLayer; 137 /// impl<S> Layer<S> for PrintingLayer 138 /// where 139 /// S: Subscriber + for<'lookup> LookupSpan<'lookup>, 140 /// { 141 /// fn on_event(&self, event: &Event, ctx: Context<S>) { 142 /// let span = ctx.event_span(event); 143 /// println!("Event in span: {:?}", span.map(|s| s.name())); 144 /// } 145 /// } 146 /// 147 /// tracing::subscriber::with_default(tracing_subscriber::registry().with(PrintingLayer), || { 148 /// tracing::info!("no span"); 149 /// // Prints: Event in span: None 150 /// 151 /// let span = tracing::info_span!("span"); 152 /// tracing::info!(parent: &span, "explicitly specified"); 153 /// // Prints: Event in span: Some("span") 154 /// 155 /// let _guard = span.enter(); 156 /// tracing::info!("contextual span"); 157 /// // Prints: Event in span: Some("span") 158 /// }); 159 /// ``` 160 /// 161 /// <pre class="ignore" style="white-space:normal;font:inherit;"> 162 /// <strong>Note</strong>: This requires the wrapped subscriber to 163 /// implement the <a href="../registry/trait.LookupSpan.html"><code> 164 /// LookupSpan</code></a> trait. See the documentation on 165 /// <a href="./struct.Context.html"><code>Context</code>'s 166 /// declaration</a> for details. 167 /// </pre> 168 #[inline] event_span(&self, event: &Event<'_>) -> Option<SpanRef<'_, S>> where S: for<'lookup> LookupSpan<'lookup>,169 pub fn event_span(&self, event: &Event<'_>) -> Option<SpanRef<'_, S>> 170 where 171 S: for<'lookup> LookupSpan<'lookup>, 172 { 173 if event.is_root() { 174 None 175 } else if event.is_contextual() { 176 self.lookup_current() 177 } else { 178 // TODO(eliza): this should handle parent IDs 179 event.parent().and_then(|id| self.span(id)) 180 } 181 } 182 183 /// Returns metadata for the span with the given `id`, if it exists. 184 /// 185 /// If this returns `None`, then no span exists for that ID (either it has 186 /// closed or the ID is invalid). 187 #[inline] metadata(&self, id: &span::Id) -> Option<&'static Metadata<'static>> where S: for<'lookup> LookupSpan<'lookup>,188 pub fn metadata(&self, id: &span::Id) -> Option<&'static Metadata<'static>> 189 where 190 S: for<'lookup> LookupSpan<'lookup>, 191 { 192 let span = self.span(id)?; 193 Some(span.metadata()) 194 } 195 196 /// Returns [stored data] for the span with the given `id`, if it exists. 197 /// 198 /// If this returns `None`, then no span exists for that ID (either it has 199 /// closed or the ID is invalid). 200 /// 201 /// <pre class="ignore" style="white-space:normal;font:inherit;"> 202 /// <strong>Note</strong>: This requires the wrapped subscriber to 203 /// implement the <a href="../registry/trait.LookupSpan.html"><code> 204 /// LookupSpan</code></a> trait. See the documentation on 205 /// <a href="./struct.Context.html"><code>Context</code>'s 206 /// declaration</a> for details. 207 /// </pre> 208 /// 209 /// [stored data]: crate::registry::SpanRef 210 #[inline] span(&self, id: &span::Id) -> Option<registry::SpanRef<'_, S>> where S: for<'lookup> LookupSpan<'lookup>,211 pub fn span(&self, id: &span::Id) -> Option<registry::SpanRef<'_, S>> 212 where 213 S: for<'lookup> LookupSpan<'lookup>, 214 { 215 let span = self.subscriber.as_ref()?.span(id)?; 216 217 #[cfg(all(feature = "registry", feature = "std"))] 218 return span.try_with_filter(self.filter); 219 220 #[cfg(not(feature = "registry"))] 221 Some(span) 222 } 223 224 /// Returns `true` if an active span exists for the given `Id`. 225 /// 226 /// <pre class="ignore" style="white-space:normal;font:inherit;"> 227 /// <strong>Note</strong>: This requires the wrapped subscriber to 228 /// implement the <a href="../registry/trait.LookupSpan.html"><code> 229 /// LookupSpan</code></a> trait. See the documentation on 230 /// <a href="./struct.Context.html"><code>Context</code>'s 231 /// declaration</a> for details. 232 /// </pre> 233 #[inline] exists(&self, id: &span::Id) -> bool where S: for<'lookup> LookupSpan<'lookup>,234 pub fn exists(&self, id: &span::Id) -> bool 235 where 236 S: for<'lookup> LookupSpan<'lookup>, 237 { 238 self.subscriber.as_ref().and_then(|s| s.span(id)).is_some() 239 } 240 241 /// Returns [stored data] for the span that the wrapped subscriber considers 242 /// to be the current. 243 /// 244 /// If this returns `None`, then we are not currently within a span. 245 /// 246 /// <pre class="ignore" style="white-space:normal;font:inherit;"> 247 /// <strong>Note</strong>: This requires the wrapped subscriber to 248 /// implement the <a href="../registry/trait.LookupSpan.html"><code> 249 /// LookupSpan</code></a> trait. See the documentation on 250 /// <a href="./struct.Context.html"><code>Context</code>'s 251 /// declaration</a> for details. 252 /// </pre> 253 /// 254 /// [stored data]: crate::registry::SpanRef 255 #[inline] lookup_current(&self) -> Option<registry::SpanRef<'_, S>> where S: for<'lookup> LookupSpan<'lookup>,256 pub fn lookup_current(&self) -> Option<registry::SpanRef<'_, S>> 257 where 258 S: for<'lookup> LookupSpan<'lookup>, 259 { 260 let subscriber = *self.subscriber.as_ref()?; 261 let current = subscriber.current_span(); 262 let id = current.id()?; 263 let span = subscriber.span(id); 264 debug_assert!( 265 span.is_some(), 266 "the subscriber should have data for the current span ({:?})!", 267 id, 268 ); 269 270 // If we found a span, and our per-layer filter enables it, return that 271 // span! 272 #[cfg(all(feature = "registry", feature = "std"))] 273 { 274 if let Some(span) = span?.try_with_filter(self.filter) { 275 Some(span) 276 } else { 277 // Otherwise, the span at the *top* of the stack is disabled by 278 // per-layer filtering, but there may be additional spans in the stack. 279 // 280 // Currently, `LookupSpan` doesn't have a nice way of exposing access to 281 // the whole span stack. However, if we can downcast the innermost 282 // subscriber to a a `Registry`, we can iterate over its current span 283 // stack. 284 // 285 // TODO(eliza): when https://github.com/tokio-rs/tracing/issues/1459 is 286 // implemented, change this to use that instead... 287 self.lookup_current_filtered(subscriber) 288 } 289 } 290 291 #[cfg(not(feature = "registry"))] 292 span 293 } 294 295 /// Slow path for when the current span is disabled by PLF and we have a 296 /// registry. 297 // This is called by `lookup_current` in the case that per-layer filtering 298 // is in use. `lookup_current` is allowed to be inlined, but this method is 299 // factored out to prevent the loop and (potentially-recursive) subscriber 300 // downcasting from being inlined if `lookup_current` is inlined. 301 #[inline(never)] 302 #[cfg(all(feature = "registry", feature = "std"))] lookup_current_filtered<'lookup>( &self, subscriber: &'lookup S, ) -> Option<registry::SpanRef<'lookup, S>> where S: LookupSpan<'lookup>,303 fn lookup_current_filtered<'lookup>( 304 &self, 305 subscriber: &'lookup S, 306 ) -> Option<registry::SpanRef<'lookup, S>> 307 where 308 S: LookupSpan<'lookup>, 309 { 310 let registry = (subscriber as &dyn Subscriber).downcast_ref::<Registry>()?; 311 registry 312 .span_stack() 313 .iter() 314 .find_map(|id| subscriber.span(id)?.try_with_filter(self.filter)) 315 } 316 317 /// Returns an iterator over the [stored data] for all the spans in the 318 /// current context, starting with the specified span and ending with the 319 /// root of the trace tree and ending with the current span. 320 /// 321 /// <pre class="ignore" style="white-space:normal;font:inherit;"> 322 /// <strong>Note</strong>: Compared to <a href="#method.scope"><code>scope</code></a> this 323 /// returns the spans in reverse order (from leaf to root). Use 324 /// <a href="../registry/struct.Scope.html#method.from_root"><code>Scope::from_root</code></a> 325 /// in case root-to-leaf ordering is desired. 326 /// </pre> 327 /// 328 /// <pre class="ignore" style="white-space:normal;font:inherit;"> 329 /// <strong>Note</strong>: This requires the wrapped subscriber to 330 /// implement the <a href="../registry/trait.LookupSpan.html"><code> 331 /// LookupSpan</code></a> trait. See the documentation on 332 /// <a href="./struct.Context.html"><code>Context</code>'s 333 /// declaration</a> for details. 334 /// </pre> 335 /// 336 /// [stored data]: crate::registry::SpanRef span_scope(&self, id: &span::Id) -> Option<registry::Scope<'_, S>> where S: for<'lookup> LookupSpan<'lookup>,337 pub fn span_scope(&self, id: &span::Id) -> Option<registry::Scope<'_, S>> 338 where 339 S: for<'lookup> LookupSpan<'lookup>, 340 { 341 Some(self.span(id)?.scope()) 342 } 343 344 /// Returns an iterator over the [stored data] for all the spans in the 345 /// current context, starting with the parent span of the specified event, 346 /// and ending with the root of the trace tree and ending with the current span. 347 /// 348 /// <pre class="ignore" style="white-space:normal;font:inherit;"> 349 /// <strong>Note</strong>: Compared to <a href="#method.scope"><code>scope</code></a> this 350 /// returns the spans in reverse order (from leaf to root). Use 351 /// <a href="../registry/struct.Scope.html#method.from_root"><code>Scope::from_root</code></a> 352 /// in case root-to-leaf ordering is desired. 353 /// </pre> 354 /// 355 /// <pre class="ignore" style="white-space:normal;font:inherit;"> 356 /// <strong>Note</strong>: This requires the wrapped subscriber to 357 /// implement the <a href="../registry/trait.LookupSpan.html"><code> 358 /// LookupSpan</code></a> trait. See the documentation on 359 /// <a href="./struct.Context.html"><code>Context</code>'s 360 /// declaration</a> for details. 361 /// </pre> 362 /// 363 /// [stored data]: crate::registry::SpanRef event_scope(&self, event: &Event<'_>) -> Option<registry::Scope<'_, S>> where S: for<'lookup> LookupSpan<'lookup>,364 pub fn event_scope(&self, event: &Event<'_>) -> Option<registry::Scope<'_, S>> 365 where 366 S: for<'lookup> LookupSpan<'lookup>, 367 { 368 Some(self.event_span(event)?.scope()) 369 } 370 371 #[cfg(all(feature = "registry", feature = "std"))] with_filter(self, filter: FilterId) -> Self372 pub(crate) fn with_filter(self, filter: FilterId) -> Self { 373 // If we already have our own `FilterId`, combine it with the provided 374 // one. That way, the new `FilterId` will consider a span to be disabled 375 // if it was disabled by the given `FilterId` *or* any `FilterId`s for 376 // layers "above" us in the stack. 377 // 378 // See the doc comment for `FilterId::and` for details. 379 let filter = self.filter.and(filter); 380 Self { filter, ..self } 381 } 382 383 #[cfg(all(feature = "registry", feature = "std"))] is_enabled_for(&self, span: &span::Id, filter: FilterId) -> bool where S: for<'lookup> LookupSpan<'lookup>,384 pub(crate) fn is_enabled_for(&self, span: &span::Id, filter: FilterId) -> bool 385 where 386 S: for<'lookup> LookupSpan<'lookup>, 387 { 388 self.is_enabled_inner(span, filter).unwrap_or(false) 389 } 390 391 #[cfg(all(feature = "registry", feature = "std"))] if_enabled_for(self, span: &span::Id, filter: FilterId) -> Option<Self> where S: for<'lookup> LookupSpan<'lookup>,392 pub(crate) fn if_enabled_for(self, span: &span::Id, filter: FilterId) -> Option<Self> 393 where 394 S: for<'lookup> LookupSpan<'lookup>, 395 { 396 if self.is_enabled_inner(span, filter)? { 397 Some(self.with_filter(filter)) 398 } else { 399 None 400 } 401 } 402 403 #[cfg(all(feature = "registry", feature = "std"))] is_enabled_inner(&self, span: &span::Id, filter: FilterId) -> Option<bool> where S: for<'lookup> LookupSpan<'lookup>,404 fn is_enabled_inner(&self, span: &span::Id, filter: FilterId) -> Option<bool> 405 where 406 S: for<'lookup> LookupSpan<'lookup>, 407 { 408 Some(self.span(span)?.is_enabled_for(filter)) 409 } 410 } 411 412 impl<'a, S> Context<'a, S> { none() -> Self413 pub(crate) fn none() -> Self { 414 Self { 415 subscriber: None, 416 417 #[cfg(feature = "registry")] 418 filter: FilterId::none(), 419 } 420 } 421 } 422 423 impl<'a, S> Clone for Context<'a, S> { 424 #[inline] clone(&self) -> Self425 fn clone(&self) -> Self { 426 let subscriber = self.subscriber.as_ref().copied(); 427 Context { 428 subscriber, 429 430 #[cfg(all(feature = "registry", feature = "std"))] 431 filter: self.filter, 432 } 433 } 434 } 435