tracing_core/callsite.rs
1//! Callsites represent the source locations from which spans or events
2//! originate.
3//!
4//! # What Are Callsites?
5//!
6//! Every span or event in `tracing` is associated with a [`Callsite`]. A
7//! callsite is a small `static` value that is responsible for the following:
8//!
9//! * Storing the span or event's [`Metadata`],
10//! * Uniquely [identifying](Identifier) the span or event definition,
11//! * Caching the subscriber's [`Interest`][^1] in that span or event, to avoid
12//! re-evaluating filters.
13//!
14//! # Registering Callsites
15//!
16//! When a span or event is recorded for the first time, its callsite
17//! [`register`]s itself with the global callsite registry. Registering a
18//! callsite calls the [`Subscriber::register_callsite`][`register_callsite`]
19//! method with that callsite's [`Metadata`] on every currently active
20//! subscriber. This serves two primary purposes: informing subscribers of the
21//! callsite's existence, and performing static filtering.
22//!
23//! ## Callsite Existence
24//!
25//! If a [`Subscriber`] implementation wishes to allocate storage for each
26//! unique span/event location in the program, or pre-compute some value
27//! that will be used to record that span or event in the future, it can
28//! do so in its [`register_callsite`] method.
29//!
30//! ## Performing Static Filtering
31//!
32//! The [`register_callsite`] method returns an [`Interest`] value,
33//! which indicates that the subscriber either [always] wishes to record
34//! that span or event, [sometimes] wishes to record it based on a
35//! dynamic filter evaluation, or [never] wishes to record it.
36//!
37//! When registering a new callsite, the [`Interest`]s returned by every
38//! currently active subscriber are combined, and the result is stored at
39//! each callsite. This way, when the span or event occurs in the
40//! future, the cached [`Interest`] value can be checked efficiently
41//! to determine if the span or event should be recorded, without
42//! needing to perform expensive filtering (i.e. calling the
43//! [`Subscriber::enabled`] method every time a span or event occurs).
44//!
45//! ### Rebuilding Cached Interest
46//!
47//! When a new [`Dispatch`] is created (i.e. a new subscriber becomes
48//! active), any previously cached [`Interest`] values are re-evaluated
49//! for all callsites in the program. This way, if the new subscriber
50//! will enable a callsite that was not previously enabled, the
51//! [`Interest`] in that callsite is updated. Similarly, when a
52//! subscriber is dropped, the interest cache is also re-evaluated, so
53//! that any callsites enabled only by that subscriber are disabled.
54//!
55//! In addition, the [`rebuild_interest_cache`] function in this module can be
56//! used to manually invalidate all cached interest and re-register those
57//! callsites. This function is useful in situations where a subscriber's
58//! interest can change, but it does so relatively infrequently. The subscriber
59//! may wish for its interest to be cached most of the time, and return
60//! [`Interest::always`][always] or [`Interest::never`][never] in its
61//! [`register_callsite`] method, so that its [`Subscriber::enabled`] method
62//! doesn't need to be evaluated every time a span or event is recorded.
63//! However, when the configuration changes, the subscriber can call
64//! [`rebuild_interest_cache`] to re-evaluate the entire interest cache with its
65//! new configuration. This is a relatively costly operation, but if the
66//! configuration changes infrequently, it may be more efficient than calling
67//! [`Subscriber::enabled`] frequently.
68//!
69//! # Implementing Callsites
70//!
71//! In most cases, instrumenting code using `tracing` should *not* require
72//! implementing the [`Callsite`] trait directly. When using the [`tracing`
73//! crate's macros][macros] or the [`#[instrument]` attribute][instrument], a
74//! `Callsite` is automatically generated.
75//!
76//! However, code which provides alternative forms of `tracing` instrumentation
77//! may need to interact with the callsite system directly. If
78//! instrumentation-side code needs to produce a `Callsite` to emit spans or
79//! events, the [`DefaultCallsite`] struct provided in this module is a
80//! ready-made `Callsite` implementation that is suitable for most uses. When
81//! possible, the use of `DefaultCallsite` should be preferred over implementing
82//! [`Callsite`] for user types, as `DefaultCallsite` may benefit from
83//! additional performance optimizations.
84//!
85//! [^1]: Returned by the [`Subscriber::register_callsite`][`register_callsite`]
86//! method.
87//!
88//! [`Metadata`]: crate::metadata::Metadata
89//! [`Interest`]: crate::subscriber::Interest
90//! [`Subscriber`]: crate::subscriber::Subscriber
91//! [`register_callsite`]: crate::subscriber::Subscriber::register_callsite
92//! [`Subscriber::enabled`]: crate::subscriber::Subscriber::enabled
93//! [always]: crate::subscriber::Interest::always
94//! [sometimes]: crate::subscriber::Interest::sometimes
95//! [never]: crate::subscriber::Interest::never
96//! [`Dispatch`]: crate::dispatcher::Dispatch
97//! [macros]: https://docs.rs/tracing/latest/tracing/#macros
98//! [instrument]: https://docs.rs/tracing/latest/tracing/attr.instrument.html
99
100use alloc::vec::Vec;
101use core::{
102 any::TypeId,
103 fmt,
104 hash::{Hash, Hasher},
105 ptr,
106 sync::atomic::{AtomicBool, AtomicPtr, AtomicU8, Ordering},
107};
108
109use self::dispatchers::Dispatchers;
110use crate::{
111 dispatcher::Dispatch,
112 metadata::{LevelFilter, Metadata},
113 subscriber::Interest,
114 sync::Mutex,
115};
116
117/// Trait implemented by callsites.
118///
119/// These functions are only intended to be called by the callsite registry, which
120/// correctly handles determining the common interest between all subscribers.
121///
122/// See the [module-level documentation](crate::callsite) for details on
123/// callsites.
124pub trait Callsite: Sync {
125 /// Sets the [`Interest`] for this callsite.
126 ///
127 /// See the [documentation on callsite interest caching][cache-docs] for
128 /// details.
129 ///
130 /// [`Interest`]: super::subscriber::Interest
131 /// [cache-docs]: crate::callsite#performing-static-filtering
132 fn set_interest(&self, interest: Interest);
133
134 /// Returns the [metadata] associated with the callsite.
135 ///
136 /// <div class="example-wrap" style="display:inline-block">
137 /// <pre class="ignore" style="white-space:normal;font:inherit;">
138 ///
139 /// **Note:** Implementations of this method should not produce [`Metadata`]
140 /// that share the same callsite [`Identifier`] but otherwise differ in any
141 /// way (e.g., have different `name`s).
142 ///
143 /// </pre></div>
144 ///
145 /// [metadata]: super::metadata::Metadata
146 fn metadata(&self) -> &Metadata<'_>;
147
148 /// This method is an *internal implementation detail* of `tracing-core`. It
149 /// is *not* intended to be called or overridden from downstream code.
150 ///
151 /// The `Private` type can only be constructed from within `tracing-core`.
152 /// Because this method takes a `Private` as an argument, it cannot be
153 /// called from (safe) code external to `tracing-core`. Because it must
154 /// *return* a `Private`, the only valid implementation possible outside of
155 /// `tracing-core` would have to always unconditionally panic.
156 ///
157 /// THIS IS BY DESIGN. There is currently no valid reason for code outside
158 /// of `tracing-core` to override this method.
159 // TODO(eliza): this could be used to implement a public downcasting API
160 // for `&dyn Callsite`s in the future.
161 #[doc(hidden)]
162 #[inline]
163 fn private_type_id(&self, _: private::Private<()>) -> private::Private<TypeId>
164 where
165 Self: 'static,
166 {
167 private::Private(TypeId::of::<Self>())
168 }
169}
170
171/// Uniquely identifies a [`Callsite`]
172///
173/// Two `Identifier`s are equal if they both refer to the same callsite.
174///
175/// [`Callsite`]: super::callsite::Callsite
176#[derive(Clone)]
177pub struct Identifier(
178 /// **Warning**: The fields on this type are currently `pub` because it must
179 /// be able to be constructed statically by macros. However, when `const
180 /// fn`s are available on stable Rust, this will no longer be necessary.
181 /// Thus, these fields are *not* considered stable public API, and they may
182 /// change warning. Do not rely on any fields on `Identifier`. When
183 /// constructing new `Identifier`s, use the `identify_callsite!` macro
184 /// instead.
185 #[doc(hidden)]
186 pub &'static dyn Callsite,
187);
188
189/// A default [`Callsite`] implementation.
190#[derive(Debug)]
191pub struct DefaultCallsite {
192 interest: AtomicU8,
193 registration: AtomicU8,
194 meta: &'static Metadata<'static>,
195 next: AtomicPtr<Self>,
196}
197
198/// Clear and reregister interest on every [`Callsite`]
199///
200/// This function is intended for runtime reconfiguration of filters on traces
201/// when the filter recalculation is much less frequent than trace events are.
202/// The alternative is to have the [`Subscriber`] that supports runtime
203/// reconfiguration of filters always return [`Interest::sometimes()`] so that
204/// [`enabled`] is evaluated for every event.
205///
206/// This function will also re-compute the global maximum level as determined by
207/// the [`max_level_hint`] method. If a [`Subscriber`]
208/// implementation changes the value returned by its `max_level_hint`
209/// implementation at runtime, then it **must** call this function after that
210/// value changes, in order for the change to be reflected.
211///
212/// See the [documentation on callsite interest caching][cache-docs] for
213/// additional information on this function's usage.
214///
215/// [`max_level_hint`]: super::subscriber::Subscriber::max_level_hint
216/// [`Callsite`]: super::callsite::Callsite
217/// [`enabled`]: super::subscriber::Subscriber#tymethod.enabled
218/// [`Interest::sometimes()`]: super::subscriber::Interest::sometimes
219/// [`Subscriber`]: super::subscriber::Subscriber
220/// [cache-docs]: crate::callsite#rebuilding-cached-interest
221pub fn rebuild_interest_cache() {
222 CALLSITES.rebuild_interest(DISPATCHERS.rebuilder());
223}
224
225/// Register a new [`Callsite`] with the global registry.
226///
227/// This should be called once per callsite after the callsite has been
228/// constructed.
229///
230/// See the [documentation on callsite registration][reg-docs] for details
231/// on the global callsite registry.
232///
233/// [`Callsite`]: crate::callsite::Callsite
234/// [reg-docs]: crate::callsite#registering-callsites
235pub fn register(callsite: &'static dyn Callsite) {
236 // Is this a `DefaultCallsite`? If so, use the fancy linked list!
237 if callsite.private_type_id(private::Private(())).0 == TypeId::of::<DefaultCallsite>() {
238 let callsite = unsafe {
239 // Safety: the pointer cast is safe because the type id of the
240 // provided callsite matches that of the target type for the cast
241 // (`DefaultCallsite`). Because user implementations of `Callsite`
242 // cannot override `private_type_id`, we can trust that the callsite
243 // is not lying about its type ID.
244 &*(callsite as *const dyn Callsite as *const DefaultCallsite)
245 };
246 CALLSITES.push_default(callsite);
247 } else {
248 CALLSITES.push_dyn(callsite);
249 }
250
251 rebuild_callsite_interest(callsite, &DISPATCHERS.rebuilder());
252}
253
254static CALLSITES: Callsites = Callsites {
255 list_head: AtomicPtr::new(ptr::null_mut()),
256 has_locked_callsites: AtomicBool::new(false),
257};
258
259static DISPATCHERS: Dispatchers = Dispatchers::new();
260
261static LOCKED_CALLSITES: Mutex<Vec<&'static dyn Callsite>> = Mutex::new(Vec::new());
262
263struct Callsites {
264 list_head: AtomicPtr<DefaultCallsite>,
265 has_locked_callsites: AtomicBool,
266}
267
268// === impl DefaultCallsite ===
269
270impl DefaultCallsite {
271 const UNREGISTERED: u8 = 0;
272 const REGISTERING: u8 = 1;
273 const REGISTERED: u8 = 2;
274
275 const INTEREST_NEVER: u8 = 0;
276 const INTEREST_SOMETIMES: u8 = 1;
277 const INTEREST_ALWAYS: u8 = 2;
278
279 /// Returns a new `DefaultCallsite` with the specified `Metadata`.
280 pub const fn new(meta: &'static Metadata<'static>) -> Self {
281 Self {
282 interest: AtomicU8::new(0xFF),
283 meta,
284 next: AtomicPtr::new(ptr::null_mut()),
285 registration: AtomicU8::new(Self::UNREGISTERED),
286 }
287 }
288
289 /// Registers this callsite with the global callsite registry.
290 ///
291 /// If the callsite is already registered, this does nothing. When using
292 /// [`DefaultCallsite`], this method should be preferred over
293 /// [`tracing_core::callsite::register`], as it ensures that the callsite is
294 /// only registered a single time.
295 ///
296 /// Other callsite implementations will generally ensure that
297 /// callsites are not re-registered through another mechanism.
298 ///
299 /// See the [documentation on callsite registration][reg-docs] for details
300 /// on the global callsite registry.
301 ///
302 /// [`tracing_core::callsite::register`]: crate::callsite::register
303 /// [reg-docs]: crate::callsite#registering-callsites
304 #[inline(never)]
305 // This only happens once (or if the cached interest value was corrupted).
306 #[cold]
307 pub fn register(&'static self) -> Interest {
308 // Attempt to advance the registration state to `REGISTERING`...
309 match self.registration.compare_exchange(
310 Self::UNREGISTERED,
311 Self::REGISTERING,
312 Ordering::AcqRel,
313 Ordering::Acquire,
314 ) {
315 Ok(_) => {
316 // Okay, we advanced the state, try to register the callsite.
317 CALLSITES.push_default(self);
318 rebuild_callsite_interest(self, &DISPATCHERS.rebuilder());
319 self.registration.store(Self::REGISTERED, Ordering::Release);
320 }
321 // Great, the callsite is already registered! Just load its
322 // previous cached interest.
323 Err(Self::REGISTERED) => {}
324 // Someone else is registering...
325 Err(_state) => {
326 debug_assert_eq!(
327 _state,
328 Self::REGISTERING,
329 "weird callsite registration state"
330 );
331 // Just hit `enabled` this time.
332 return Interest::sometimes();
333 }
334 }
335
336 match self.interest.load(Ordering::Relaxed) {
337 Self::INTEREST_NEVER => Interest::never(),
338 Self::INTEREST_ALWAYS => Interest::always(),
339 _ => Interest::sometimes(),
340 }
341 }
342
343 /// Returns the callsite's cached `Interest`, or registers it for the
344 /// first time if it has not yet been registered.
345 #[inline]
346 pub fn interest(&'static self) -> Interest {
347 match self.interest.load(Ordering::Relaxed) {
348 Self::INTEREST_NEVER => Interest::never(),
349 Self::INTEREST_SOMETIMES => Interest::sometimes(),
350 Self::INTEREST_ALWAYS => Interest::always(),
351 _ => self.register(),
352 }
353 }
354}
355
356impl Callsite for DefaultCallsite {
357 fn set_interest(&self, interest: Interest) {
358 let interest = match () {
359 _ if interest.is_never() => Self::INTEREST_NEVER,
360 _ if interest.is_always() => Self::INTEREST_ALWAYS,
361 _ => Self::INTEREST_SOMETIMES,
362 };
363 self.interest.store(interest, Ordering::SeqCst);
364 }
365
366 #[inline(always)]
367 fn metadata(&self) -> &Metadata<'static> {
368 self.meta
369 }
370}
371
372// ===== impl Identifier =====
373
374impl PartialEq for Identifier {
375 fn eq(&self, other: &Identifier) -> bool {
376 core::ptr::eq(
377 self.0 as *const _ as *const (),
378 other.0 as *const _ as *const (),
379 )
380 }
381}
382
383impl Eq for Identifier {}
384
385impl fmt::Debug for Identifier {
386 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
387 write!(f, "Identifier({:p})", self.0)
388 }
389}
390
391impl Hash for Identifier {
392 fn hash<H>(&self, state: &mut H)
393 where
394 H: Hasher,
395 {
396 (self.0 as *const dyn Callsite).hash(state)
397 }
398}
399
400// === impl Callsites ===
401
402impl Callsites {
403 /// Rebuild `Interest`s for all callsites in the registry.
404 ///
405 /// This also re-computes the max level hint.
406 fn rebuild_interest(&self, dispatchers: dispatchers::Rebuilder<'_>) {
407 let mut max_level = LevelFilter::OFF;
408 dispatchers.for_each(|dispatch| {
409 // If the subscriber did not provide a max level hint, assume
410 // that it may enable every level.
411 let level_hint = dispatch.max_level_hint().unwrap_or(LevelFilter::TRACE);
412 if level_hint > max_level {
413 max_level = level_hint;
414 }
415 });
416
417 self.for_each(|callsite| {
418 rebuild_callsite_interest(callsite, &dispatchers);
419 });
420 LevelFilter::set_max(max_level);
421 }
422
423 /// Push a `dyn Callsite` trait object to the callsite registry.
424 ///
425 /// This will attempt to lock the callsites vector.
426 fn push_dyn(&self, callsite: &'static dyn Callsite) {
427 let mut lock = LOCKED_CALLSITES.lock().unwrap();
428 self.has_locked_callsites.store(true, Ordering::Release);
429 lock.push(callsite);
430 }
431
432 /// Push a `DefaultCallsite` to the callsite registry.
433 ///
434 /// If we know the callsite being pushed is a `DefaultCallsite`, we can push
435 /// it to the linked list without having to acquire a lock.
436 fn push_default(&self, callsite: &'static DefaultCallsite) {
437 let mut head = self.list_head.load(Ordering::Acquire);
438
439 loop {
440 callsite.next.store(head, Ordering::Release);
441
442 assert_ne!(
443 callsite as *const _, head,
444 "Attempted to register a `DefaultCallsite` that already exists! \
445 This will cause an infinite loop when attempting to read from the \
446 callsite cache. This is likely a bug! You should only need to call \
447 `DefaultCallsite::register` once per `DefaultCallsite`."
448 );
449
450 match self.list_head.compare_exchange(
451 head,
452 callsite as *const _ as *mut _,
453 Ordering::AcqRel,
454 Ordering::Acquire,
455 ) {
456 Ok(_) => {
457 break;
458 }
459 Err(current) => head = current,
460 }
461 }
462 }
463
464 /// Invokes the provided closure `f` with each callsite in the registry.
465 fn for_each(&self, mut f: impl FnMut(&'static dyn Callsite)) {
466 let mut head = self.list_head.load(Ordering::Acquire);
467
468 while let Some(cs) = unsafe { head.as_ref() } {
469 f(cs);
470
471 head = cs.next.load(Ordering::Acquire);
472 }
473
474 if self.has_locked_callsites.load(Ordering::Acquire) {
475 let locked = LOCKED_CALLSITES.lock().unwrap();
476 for &cs in locked.iter() {
477 f(cs);
478 }
479 }
480 }
481}
482
483pub(crate) fn register_dispatch(dispatch: &Dispatch) {
484 let dispatchers = DISPATCHERS.register_dispatch(dispatch);
485 dispatch.subscriber().on_register_dispatch(dispatch);
486 CALLSITES.rebuild_interest(dispatchers);
487}
488
489fn rebuild_callsite_interest(
490 callsite: &'static dyn Callsite,
491 dispatchers: &dispatchers::Rebuilder<'_>,
492) {
493 let meta = callsite.metadata();
494
495 let mut interest = None;
496 dispatchers.for_each(|dispatch| {
497 let this_interest = dispatch.register_callsite(meta);
498 interest = match interest.take() {
499 None => Some(this_interest),
500 Some(that_interest) => Some(that_interest.and(this_interest)),
501 }
502 });
503
504 let interest = interest.unwrap_or_else(Interest::never);
505 callsite.set_interest(interest)
506}
507
508mod private {
509 /// Don't call this function, it's private.
510 #[allow(missing_debug_implementations)]
511 pub struct Private<T>(pub(crate) T);
512}
513
514#[cfg(feature = "std")]
515mod dispatchers {
516 use crate::dispatcher;
517 use alloc::vec::Vec;
518 use std::sync::{
519 atomic::{AtomicBool, Ordering},
520 RwLock, RwLockReadGuard, RwLockWriteGuard,
521 };
522
523 pub(super) struct Dispatchers {
524 has_just_one: AtomicBool,
525 }
526
527 static LOCKED_DISPATCHERS: RwLock<Vec<dispatcher::Registrar>> = RwLock::new(Vec::new());
528
529 pub(super) enum Rebuilder<'a> {
530 JustOne,
531 Read(RwLockReadGuard<'a, Vec<dispatcher::Registrar>>),
532 Write(RwLockWriteGuard<'a, Vec<dispatcher::Registrar>>),
533 }
534
535 impl Dispatchers {
536 pub(super) const fn new() -> Self {
537 Self {
538 has_just_one: AtomicBool::new(true),
539 }
540 }
541
542 pub(super) fn rebuilder(&self) -> Rebuilder<'_> {
543 if self.has_just_one.load(Ordering::SeqCst) {
544 return Rebuilder::JustOne;
545 }
546 Rebuilder::Read(LOCKED_DISPATCHERS.read().unwrap())
547 }
548
549 pub(super) fn register_dispatch(&self, dispatch: &dispatcher::Dispatch) -> Rebuilder<'_> {
550 let mut dispatchers = LOCKED_DISPATCHERS.write().unwrap();
551 dispatchers.retain(|d| d.upgrade().is_some());
552 dispatchers.push(dispatch.registrar());
553 self.has_just_one
554 .store(dispatchers.len() <= 1, Ordering::SeqCst);
555 Rebuilder::Write(dispatchers)
556 }
557 }
558
559 impl Rebuilder<'_> {
560 pub(super) fn for_each(&self, mut f: impl FnMut(&dispatcher::Dispatch)) {
561 let iter = match self {
562 Rebuilder::JustOne => {
563 dispatcher::get_default(f);
564 return;
565 }
566 Rebuilder::Read(vec) => vec.iter(),
567 Rebuilder::Write(vec) => vec.iter(),
568 };
569 iter.filter_map(dispatcher::Registrar::upgrade)
570 .for_each(|dispatch| f(&dispatch))
571 }
572 }
573}
574
575#[cfg(not(feature = "std"))]
576mod dispatchers {
577 use crate::dispatcher;
578
579 pub(super) struct Dispatchers(());
580 pub(super) struct Rebuilder<'a>(Option<&'a dispatcher::Dispatch>);
581
582 impl Dispatchers {
583 pub(super) const fn new() -> Self {
584 Self(())
585 }
586
587 pub(super) fn rebuilder(&self) -> Rebuilder<'_> {
588 Rebuilder(None)
589 }
590
591 pub(super) fn register_dispatch<'dispatch>(
592 &self,
593 dispatch: &'dispatch dispatcher::Dispatch,
594 ) -> Rebuilder<'dispatch> {
595 // nop; on no_std, there can only ever be one dispatcher
596 Rebuilder(Some(dispatch))
597 }
598 }
599
600 impl Rebuilder<'_> {
601 #[inline]
602 pub(super) fn for_each(&self, mut f: impl FnMut(&dispatcher::Dispatch)) {
603 if let Some(dispatch) = self.0 {
604 // we are rebuilding the interest cache because a new dispatcher
605 // is about to be set. on `no_std`, this should only happen
606 // once, because the new dispatcher will be the global default.
607 f(dispatch)
608 } else {
609 // otherwise, we are rebuilding the cache because the subscriber
610 // configuration changed, so use the global default.
611 // on no_std, there can only ever be one dispatcher
612 dispatcher::get_default(f)
613 }
614 }
615 }
616}