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