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