Skip to main content

tracing_reload/
subscriber.rs

1//! This module defines a fake subscriber which is not to be constructible from user code and thus
2//! cannot be registered as an actual subscriber. We do this just so we have something implementing
3//! [`LookupSpan`] that the reloaded layers can be provided in their [`on_layer`] implementation.
4//!
5//! [`on_layer`]: tracing_subscriber::layer::Layer::on_layer
6
7use std::{
8    any::TypeId,
9    ptr,
10    sync::atomic::{AtomicBool, Ordering},
11};
12
13use tracing::{Subscriber, span};
14use tracing_subscriber::registry::LookupSpan;
15
16use crate::ReloadableFilters;
17
18/// This is a fake subscriber that should not be constructed by user-code.
19///
20/// It exists only for this crate's internal purposes but must be public because it may appear as a
21/// generic parameter of other crates' structs and traits. Most notably in
22/// [`Layer<S>`](tracing_subscriber::layer::Layer).
23pub struct ReloadSubscriber<S>
24where
25    S: 'static,
26{
27    inner: &'static S,
28    filters: ReloadableFilters,
29    follows_from_called: AtomicBool,
30}
31
32impl<S: 'static> ReloadSubscriber<S> {
33    pub(crate) fn new(inner: &'static S, filters: ReloadableFilters) -> Self {
34        Self {
35            inner,
36            filters,
37            follows_from_called: AtomicBool::new(false),
38        }
39    }
40
41    pub(crate) fn into_filters(self) -> ReloadableFilters {
42        self.filters
43    }
44}
45
46impl<S: Subscriber + 'static> Subscriber for ReloadSubscriber<S> {
47    fn record_follows_from(&self, span: &span::Id, follows: &span::Id) {
48        // The first call is our fake call from `with_ctx`. We do not want this to propagate to the
49        // inner subscriber and especially to any other layers it wraps.
50        if self.follows_from_called.swap(true, Ordering::Relaxed) {
51            self.inner.record_follows_from(span, follows);
52        }
53    }
54
55    unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
56        if id == TypeId::of::<Self>() {
57            Some(ptr::from_ref(self).cast::<()>())
58        } else {
59            unsafe { self.inner.downcast_raw(id) }
60        }
61    }
62
63    // Everything else is `fn x(..) -> y { self.inner.x(..) }`
64
65    fn enabled(&self, metadata: &tracing::Metadata<'_>) -> bool {
66        self.inner.enabled(metadata)
67    }
68
69    fn new_span(&self, span: &span::Attributes<'_>) -> tracing_core::span::Id {
70        self.inner.new_span(span)
71    }
72
73    fn record(&self, span: &span::Id, values: &tracing_core::span::Record<'_>) {
74        self.inner.record(span, values);
75    }
76
77    fn event(&self, event: &tracing::Event<'_>) {
78        self.inner.event(event);
79    }
80
81    fn enter(&self, span: &span::Id) {
82        self.inner.enter(span);
83    }
84
85    fn exit(&self, span: &span::Id) {
86        self.inner.exit(span);
87    }
88
89    fn on_register_dispatch(&self, subscriber: &tracing::Dispatch) {
90        self.inner.on_register_dispatch(subscriber);
91    }
92
93    fn register_callsite(
94        &self,
95        metadata: &'static tracing::Metadata<'static>,
96    ) -> tracing_core::Interest {
97        self.inner.register_callsite(metadata)
98    }
99
100    fn max_level_hint(&self) -> Option<tracing_core::LevelFilter> {
101        self.inner.max_level_hint()
102    }
103
104    fn event_enabled(&self, event: &tracing::Event<'_>) -> bool {
105        self.inner.event_enabled(event)
106    }
107
108    fn clone_span(&self, id: &tracing_core::span::Id) -> tracing_core::span::Id {
109        self.inner.clone_span(id)
110    }
111
112    fn drop_span(&self, id: tracing_core::span::Id) {
113        #[expect(deprecated, reason = "It's deprecated...")]
114        self.inner.drop_span(id);
115    }
116
117    fn try_close(&self, id: tracing_core::span::Id) -> bool {
118        self.inner.try_close(id)
119    }
120
121    fn current_span(&self) -> tracing_core::span::Current {
122        self.inner.current_span()
123    }
124}
125
126impl<'lookup, S: LookupSpan<'lookup>> LookupSpan<'lookup> for ReloadSubscriber<S> {
127    type Data = S::Data;
128
129    fn span_data(&'lookup self, id: &tracing::span::Id) -> Option<Self::Data> {
130        self.inner.span_data(id)
131    }
132
133    fn register_filter(&mut self) -> tracing_subscriber::filter::FilterId {
134        let filters = &mut self.filters;
135
136        let Some(filter_id) = filters.free.pop() else {
137            // We don't have enough filter IDs. If we don't give out anything the filter would panic
138            // so we just give it _anything_ which may break some filters but at least it doesn't
139            // panic. Hopefully.
140
141            return filters.backup;
142        };
143
144        filters.used.push(filter_id);
145        filter_id
146    }
147}