Coverage Report

Created: 2025-07-11 06:53

/rust/registry/src/index.crates.io-6f17d22bba15001f/tracing-subscriber-0.3.19/src/reload.rs
Line
Count
Source (jump to first uncovered line)
1
//! Wrapper for a `Layer` to allow it to be dynamically reloaded.
2
//!
3
//! This module provides a [`Layer` type] implementing the [`Layer` trait] or [`Filter` trait]
4
//! which wraps another type implementing the corresponding trait. This
5
//! allows the wrapped type to be replaced with another
6
//! instance of that type at runtime.
7
//!
8
//! This can be used in cases where a subset of `Layer` or `Filter` functionality
9
//! should be dynamically reconfigured, such as when filtering directives may
10
//! change at runtime. Note that this layer introduces a (relatively small)
11
//! amount of overhead, and should thus only be used as needed.
12
//!
13
//! # Examples
14
//!
15
//! Reloading a [global filtering](crate::layer#global-filtering) layer:
16
//!
17
//! ```rust
18
//! # use tracing::info;
19
//! use tracing_subscriber::{filter, fmt, reload, prelude::*};
20
//! let filter = filter::LevelFilter::WARN;
21
//! let (filter, reload_handle) = reload::Layer::new(filter);
22
//! tracing_subscriber::registry()
23
//!   .with(filter)
24
//!   .with(fmt::Layer::default())
25
//!   .init();
26
//! #
27
//! # // specifying the Registry type is required
28
//! # let _: &reload::Handle<filter::LevelFilter, tracing_subscriber::Registry> = &reload_handle;
29
//! #
30
//! info!("This will be ignored");
31
//! reload_handle.modify(|filter| *filter = filter::LevelFilter::INFO);
32
//! info!("This will be logged");
33
//! ```
34
//!
35
//! Reloading a [`Filtered`](crate::filter::Filtered) layer:
36
//!
37
//! ```rust
38
//! # use tracing::info;
39
//! use tracing_subscriber::{filter, fmt, reload, prelude::*};
40
//! let filtered_layer = fmt::Layer::default().with_filter(filter::LevelFilter::WARN);
41
//! let (filtered_layer, reload_handle) = reload::Layer::new(filtered_layer);
42
//! #
43
//! # // specifying the Registry type is required
44
//! # let _: &reload::Handle<filter::Filtered<fmt::Layer<tracing_subscriber::Registry>,
45
//! # filter::LevelFilter, tracing_subscriber::Registry>,tracing_subscriber::Registry>
46
//! # = &reload_handle;
47
//! #
48
//! tracing_subscriber::registry()
49
//!   .with(filtered_layer)
50
//!   .init();
51
//! info!("This will be ignored");
52
//! reload_handle.modify(|layer| *layer.filter_mut() = filter::LevelFilter::INFO);
53
//! info!("This will be logged");
54
//! ```
55
//!
56
//! ## Note
57
//!
58
//! The [`Layer`] implementation is unable to implement downcasting functionality,
59
//! so certain [`Layer`] will fail to downcast if wrapped in a `reload::Layer`.
60
//!
61
//! If you only want to be able to dynamically change the
62
//! `Filter` on a layer, prefer wrapping that `Filter` in the `reload::Layer`.
63
//!
64
//! [`Filter` trait]: crate::layer::Filter
65
//! [`Layer` type]: Layer
66
//! [`Layer` trait]: super::layer::Layer
67
use crate::layer;
68
use crate::sync::RwLock;
69
70
use core::any::TypeId;
71
use std::{
72
    error, fmt,
73
    marker::PhantomData,
74
    sync::{Arc, Weak},
75
};
76
use tracing_core::{
77
    callsite, span,
78
    subscriber::{Interest, Subscriber},
79
    Dispatch, Event, LevelFilter, Metadata,
80
};
81
82
/// Wraps a `Layer` or `Filter`, allowing it to be reloaded dynamically at runtime.
83
#[derive(Debug)]
84
pub struct Layer<L, S> {
85
    // TODO(eliza): this once used a `crossbeam_util::ShardedRwLock`. We may
86
    // eventually wish to replace it with a sharded lock implementation on top
87
    // of our internal `RwLock` wrapper type. If possible, we should profile
88
    // this first to determine if it's necessary.
89
    inner: Arc<RwLock<L>>,
90
    _s: PhantomData<fn(S)>,
91
}
92
93
/// Allows reloading the state of an associated [`Layer`](crate::layer::Layer).
94
#[derive(Debug)]
95
pub struct Handle<L, S> {
96
    inner: Weak<RwLock<L>>,
97
    _s: PhantomData<fn(S)>,
98
}
99
100
/// Indicates that an error occurred when reloading a layer.
101
#[derive(Debug)]
102
pub struct Error {
103
    kind: ErrorKind,
104
}
105
106
#[derive(Debug)]
107
enum ErrorKind {
108
    SubscriberGone,
109
    Poisoned,
110
}
111
112
// ===== impl Layer =====
113
114
impl<L, S> crate::Layer<S> for Layer<L, S>
115
where
116
    L: crate::Layer<S> + 'static,
117
    S: Subscriber,
118
{
119
0
    fn on_register_dispatch(&self, subscriber: &Dispatch) {
120
0
        try_lock!(self.inner.read()).on_register_dispatch(subscriber);
121
0
    }
122
123
0
    fn on_layer(&mut self, subscriber: &mut S) {
124
0
        try_lock!(self.inner.write(), else return).on_layer(subscriber);
125
0
    }
126
127
    #[inline]
128
0
    fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
129
0
        try_lock!(self.inner.read(), else return Interest::sometimes()).register_callsite(metadata)
130
0
    }
131
132
    #[inline]
133
0
    fn enabled(&self, metadata: &Metadata<'_>, ctx: layer::Context<'_, S>) -> bool {
134
0
        try_lock!(self.inner.read(), else return false).enabled(metadata, ctx)
135
0
    }
136
137
    #[inline]
138
0
    fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: layer::Context<'_, S>) {
139
0
        try_lock!(self.inner.read()).on_new_span(attrs, id, ctx)
140
0
    }
141
142
    #[inline]
143
0
    fn on_record(&self, span: &span::Id, values: &span::Record<'_>, ctx: layer::Context<'_, S>) {
144
0
        try_lock!(self.inner.read()).on_record(span, values, ctx)
145
0
    }
146
147
    #[inline]
148
0
    fn on_follows_from(&self, span: &span::Id, follows: &span::Id, ctx: layer::Context<'_, S>) {
149
0
        try_lock!(self.inner.read()).on_follows_from(span, follows, ctx)
150
0
    }
151
152
    #[inline]
153
0
    fn event_enabled(&self, event: &Event<'_>, ctx: layer::Context<'_, S>) -> bool {
154
0
        try_lock!(self.inner.read(), else return false).event_enabled(event, ctx)
155
0
    }
156
157
    #[inline]
158
0
    fn on_event(&self, event: &Event<'_>, ctx: layer::Context<'_, S>) {
159
0
        try_lock!(self.inner.read()).on_event(event, ctx)
160
0
    }
161
162
    #[inline]
163
0
    fn on_enter(&self, id: &span::Id, ctx: layer::Context<'_, S>) {
164
0
        try_lock!(self.inner.read()).on_enter(id, ctx)
165
0
    }
166
167
    #[inline]
168
0
    fn on_exit(&self, id: &span::Id, ctx: layer::Context<'_, S>) {
169
0
        try_lock!(self.inner.read()).on_exit(id, ctx)
170
0
    }
171
172
    #[inline]
173
0
    fn on_close(&self, id: span::Id, ctx: layer::Context<'_, S>) {
174
0
        try_lock!(self.inner.read()).on_close(id, ctx)
175
0
    }
176
177
    #[inline]
178
0
    fn on_id_change(&self, old: &span::Id, new: &span::Id, ctx: layer::Context<'_, S>) {
179
0
        try_lock!(self.inner.read()).on_id_change(old, new, ctx)
180
0
    }
181
182
    #[inline]
183
0
    fn max_level_hint(&self) -> Option<LevelFilter> {
184
0
        try_lock!(self.inner.read(), else return None).max_level_hint()
185
0
    }
186
187
    #[doc(hidden)]
188
0
    unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
189
0
        // Safety: it is generally unsafe to downcast through a reload, because
190
0
        // the pointer can be invalidated after the lock is dropped.
191
0
        // `NoneLayerMarker` is a special case because it
192
0
        // is never dereferenced.
193
0
        //
194
0
        // Additionally, even if the marker type *is* dereferenced (which it
195
0
        // never will be), the pointer should be valid even if the subscriber
196
0
        // is reloaded, because all `NoneLayerMarker` pointers that we return
197
0
        // actually point to the global static singleton `NoneLayerMarker`,
198
0
        // rather than to a field inside the lock.
199
0
        if id == TypeId::of::<layer::NoneLayerMarker>() {
200
0
            return try_lock!(self.inner.read(), else return None).downcast_raw(id);
201
0
        }
202
0
203
0
        None
204
0
    }
205
}
206
207
// ===== impl Filter =====
208
209
#[cfg(all(feature = "registry", feature = "std"))]
210
#[cfg_attr(docsrs, doc(cfg(all(feature = "registry", feature = "std"))))]
211
impl<S, L> crate::layer::Filter<S> for Layer<L, S>
212
where
213
    L: crate::layer::Filter<S> + 'static,
214
    S: Subscriber,
215
{
216
    #[inline]
217
0
    fn callsite_enabled(&self, metadata: &'static Metadata<'static>) -> Interest {
218
0
        try_lock!(self.inner.read(), else return Interest::sometimes()).callsite_enabled(metadata)
219
0
    }
220
221
    #[inline]
222
0
    fn enabled(&self, metadata: &Metadata<'_>, ctx: &layer::Context<'_, S>) -> bool {
223
0
        try_lock!(self.inner.read(), else return false).enabled(metadata, ctx)
224
0
    }
225
226
    #[inline]
227
0
    fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: layer::Context<'_, S>) {
228
0
        try_lock!(self.inner.read()).on_new_span(attrs, id, ctx)
229
0
    }
230
231
    #[inline]
232
0
    fn on_record(&self, span: &span::Id, values: &span::Record<'_>, ctx: layer::Context<'_, S>) {
233
0
        try_lock!(self.inner.read()).on_record(span, values, ctx)
234
0
    }
235
236
    #[inline]
237
0
    fn on_enter(&self, id: &span::Id, ctx: layer::Context<'_, S>) {
238
0
        try_lock!(self.inner.read()).on_enter(id, ctx)
239
0
    }
240
241
    #[inline]
242
0
    fn on_exit(&self, id: &span::Id, ctx: layer::Context<'_, S>) {
243
0
        try_lock!(self.inner.read()).on_exit(id, ctx)
244
0
    }
245
246
    #[inline]
247
0
    fn on_close(&self, id: span::Id, ctx: layer::Context<'_, S>) {
248
0
        try_lock!(self.inner.read()).on_close(id, ctx)
249
0
    }
250
251
    #[inline]
252
0
    fn max_level_hint(&self) -> Option<LevelFilter> {
253
0
        try_lock!(self.inner.read(), else return None).max_level_hint()
254
0
    }
255
}
256
257
impl<L, S> Layer<L, S> {
258
    /// Wraps the given [`Layer`] or [`Filter`], returning a `reload::Layer`
259
    /// and a `Handle` that allows the inner value to be modified at runtime.
260
    ///
261
    /// [`Layer`]: crate::layer::Layer
262
    /// [`Filter`]: crate::layer::Filter
263
0
    pub fn new(inner: L) -> (Self, Handle<L, S>) {
264
0
        let this = Self {
265
0
            inner: Arc::new(RwLock::new(inner)),
266
0
            _s: PhantomData,
267
0
        };
268
0
        let handle = this.handle();
269
0
        (this, handle)
270
0
    }
271
272
    /// Returns a `Handle` that can be used to reload the wrapped [`Layer`] or [`Filter`].
273
    ///
274
    /// [`Layer`]: crate::layer::Layer
275
    /// [`Filter`]: crate::filter::Filter
276
0
    pub fn handle(&self) -> Handle<L, S> {
277
0
        Handle {
278
0
            inner: Arc::downgrade(&self.inner),
279
0
            _s: PhantomData,
280
0
        }
281
0
    }
282
}
283
284
// ===== impl Handle =====
285
286
impl<L, S> Handle<L, S> {
287
    /// Replace the current [`Layer`] or [`Filter`] with the provided `new_value`.
288
    ///
289
    /// [`Handle::reload`] cannot be used with the [`Filtered`] layer; use
290
    /// [`Handle::modify`] instead (see [this issue] for additional details).
291
    ///
292
    /// However, if the _only_ the [`Filter`]  needs to be modified, use
293
    /// `reload::Layer` to wrap the `Filter` directly.
294
    ///
295
    /// [`Layer`]: crate::layer::Layer
296
    /// [`Filter`]: crate::layer::Filter
297
    /// [`Filtered`]: crate::filter::Filtered
298
    ///
299
    /// [this issue]: https://github.com/tokio-rs/tracing/issues/1629
300
0
    pub fn reload(&self, new_value: impl Into<L>) -> Result<(), Error> {
301
0
        self.modify(|layer| {
302
0
            *layer = new_value.into();
303
0
        })
304
0
    }
305
306
    /// Invokes a closure with a mutable reference to the current layer or filter,
307
    /// allowing it to be modified in place.
308
0
    pub fn modify(&self, f: impl FnOnce(&mut L)) -> Result<(), Error> {
309
0
        let inner = self.inner.upgrade().ok_or(Error {
310
0
            kind: ErrorKind::SubscriberGone,
311
0
        })?;
312
313
0
        let mut lock = try_lock!(inner.write(), else return Err(Error::poisoned()));
314
0
        f(&mut *lock);
315
0
        // Release the lock before rebuilding the interest cache, as that
316
0
        // function will lock the new layer.
317
0
        drop(lock);
318
0
319
0
        callsite::rebuild_interest_cache();
320
0
321
0
        // If the `log` crate compatibility feature is in use, set `log`'s max
322
0
        // level as well, in case the max `tracing` level changed. We do this
323
0
        // *after* rebuilding the interest cache, as that's when the `tracing`
324
0
        // max level filter is re-computed.
325
0
        #[cfg(feature = "tracing-log")]
326
0
        tracing_log::log::set_max_level(tracing_log::AsLog::as_log(
327
0
            &crate::filter::LevelFilter::current(),
328
0
        ));
329
0
330
0
        Ok(())
331
0
    }
332
333
    /// Returns a clone of the layer or filter's current value if it still exists.
334
    /// Otherwise, if the subscriber has been dropped, returns `None`.
335
0
    pub fn clone_current(&self) -> Option<L>
336
0
    where
337
0
        L: Clone,
338
0
    {
339
0
        self.with_current(L::clone).ok()
340
0
    }
341
342
    /// Invokes a closure with a borrowed reference to the current layer or filter,
343
    /// returning the result (or an error if the subscriber no longer exists).
344
0
    pub fn with_current<T>(&self, f: impl FnOnce(&L) -> T) -> Result<T, Error> {
345
0
        let inner = self.inner.upgrade().ok_or(Error {
346
0
            kind: ErrorKind::SubscriberGone,
347
0
        })?;
348
0
        let inner = try_lock!(inner.read(), else return Err(Error::poisoned()));
349
0
        Ok(f(&*inner))
350
0
    }
351
}
352
353
impl<L, S> Clone for Handle<L, S> {
354
0
    fn clone(&self) -> Self {
355
0
        Handle {
356
0
            inner: self.inner.clone(),
357
0
            _s: PhantomData,
358
0
        }
359
0
    }
360
}
361
362
// ===== impl Error =====
363
364
impl Error {
365
0
    fn poisoned() -> Self {
366
0
        Self {
367
0
            kind: ErrorKind::Poisoned,
368
0
        }
369
0
    }
370
371
    /// Returns `true` if this error occurred because the layer was poisoned by
372
    /// a panic on another thread.
373
0
    pub fn is_poisoned(&self) -> bool {
374
0
        matches!(self.kind, ErrorKind::Poisoned)
375
0
    }
376
377
    /// Returns `true` if this error occurred because the `Subscriber`
378
    /// containing the reloadable layer was dropped.
379
0
    pub fn is_dropped(&self) -> bool {
380
0
        matches!(self.kind, ErrorKind::SubscriberGone)
381
0
    }
382
}
383
384
impl fmt::Display for Error {
385
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
386
0
        let msg = match self.kind {
387
0
            ErrorKind::SubscriberGone => "subscriber no longer exists",
388
0
            ErrorKind::Poisoned => "lock poisoned",
389
        };
390
0
        f.pad(msg)
391
0
    }
392
}
393
394
impl error::Error for Error {}