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