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
67use crate::layer;
68use crate::sync::RwLock;
69
70use core::any::TypeId;
71use std::{
72 error, fmt,
73 marker::PhantomData,
74 sync::{Arc, Weak},
75};
76use 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)]
84pub 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)]
95pub 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)]
102pub struct Error {
103 kind: ErrorKind,
104}
105
106#[derive(Debug)]
107enum ErrorKind {
108 SubscriberGone,
109 Poisoned,
110}
111
112// ===== impl Layer =====
113
114impl<L, S> crate::Layer<S> for Layer<L, S>
115where
116 L: crate::Layer<S> + 'static,
117 S: Subscriber,
118{
119 fn on_register_dispatch(&self, subscriber: &Dispatch) {
120 try_lock!(self.inner.read()).on_register_dispatch(subscriber);
121 }
122
123 fn on_layer(&mut self, subscriber: &mut S) {
124 try_lock!(self.inner.write(), else return).on_layer(subscriber);
125 }
126
127 #[inline]
128 fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
129 try_lock!(self.inner.read(), else return Interest::sometimes()).register_callsite(metadata)
130 }
131
132 #[inline]
133 fn enabled(&self, metadata: &Metadata<'_>, ctx: layer::Context<'_, S>) -> bool {
134 try_lock!(self.inner.read(), else return false).enabled(metadata, ctx)
135 }
136
137 #[inline]
138 fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: layer::Context<'_, S>) {
139 try_lock!(self.inner.read()).on_new_span(attrs, id, ctx)
140 }
141
142 #[inline]
143 fn on_record(&self, span: &span::Id, values: &span::Record<'_>, ctx: layer::Context<'_, S>) {
144 try_lock!(self.inner.read()).on_record(span, values, ctx)
145 }
146
147 #[inline]
148 fn on_follows_from(&self, span: &span::Id, follows: &span::Id, ctx: layer::Context<'_, S>) {
149 try_lock!(self.inner.read()).on_follows_from(span, follows, ctx)
150 }
151
152 #[inline]
153 fn event_enabled(&self, event: &Event<'_>, ctx: layer::Context<'_, S>) -> bool {
154 try_lock!(self.inner.read(), else return false).event_enabled(event, ctx)
155 }
156
157 #[inline]
158 fn on_event(&self, event: &Event<'_>, ctx: layer::Context<'_, S>) {
159 try_lock!(self.inner.read()).on_event(event, ctx)
160 }
161
162 #[inline]
163 fn on_enter(&self, id: &span::Id, ctx: layer::Context<'_, S>) {
164 try_lock!(self.inner.read()).on_enter(id, ctx)
165 }
166
167 #[inline]
168 fn on_exit(&self, id: &span::Id, ctx: layer::Context<'_, S>) {
169 try_lock!(self.inner.read()).on_exit(id, ctx)
170 }
171
172 #[inline]
173 fn on_close(&self, id: span::Id, ctx: layer::Context<'_, S>) {
174 try_lock!(self.inner.read()).on_close(id, ctx)
175 }
176
177 #[inline]
178 fn on_id_change(&self, old: &span::Id, new: &span::Id, ctx: layer::Context<'_, S>) {
179 try_lock!(self.inner.read()).on_id_change(old, new, ctx)
180 }
181
182 #[inline]
183 fn max_level_hint(&self) -> Option<LevelFilter> {
184 try_lock!(self.inner.read(), else return None).max_level_hint()
185 }
186
187 #[doc(hidden)]
188 unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
189 // Safety: it is generally unsafe to downcast through a reload, because
190 // the pointer can be invalidated after the lock is dropped.
191 // `NoneLayerMarker` is a special case because it
192 // is never dereferenced.
193 //
194 // Additionally, even if the marker type *is* dereferenced (which it
195 // never will be), the pointer should be valid even if the subscriber
196 // is reloaded, because all `NoneLayerMarker` pointers that we return
197 // actually point to the global static singleton `NoneLayerMarker`,
198 // rather than to a field inside the lock.
199 if id == TypeId::of::<layer::NoneLayerMarker>() {
200 return try_lock!(self.inner.read(), else return None).downcast_raw(id);
201 }
202
203 None
204 }
205}
206
207// ===== impl Filter =====
208
209#[cfg(all(feature = "registry", feature = "std"))]
210#[cfg_attr(docsrs, doc(cfg(all(feature = "registry", feature = "std"))))]
211impl<S, L> crate::layer::Filter<S> for Layer<L, S>
212where
213 L: crate::layer::Filter<S> + 'static,
214 S: Subscriber,
215{
216 #[inline]
217 fn callsite_enabled(&self, metadata: &'static Metadata<'static>) -> Interest {
218 try_lock!(self.inner.read(), else return Interest::sometimes()).callsite_enabled(metadata)
219 }
220
221 #[inline]
222 fn enabled(&self, metadata: &Metadata<'_>, ctx: &layer::Context<'_, S>) -> bool {
223 try_lock!(self.inner.read(), else return false).enabled(metadata, ctx)
224 }
225
226 #[inline]
227 fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: layer::Context<'_, S>) {
228 try_lock!(self.inner.read()).on_new_span(attrs, id, ctx)
229 }
230
231 #[inline]
232 fn on_record(&self, span: &span::Id, values: &span::Record<'_>, ctx: layer::Context<'_, S>) {
233 try_lock!(self.inner.read()).on_record(span, values, ctx)
234 }
235
236 #[inline]
237 fn on_enter(&self, id: &span::Id, ctx: layer::Context<'_, S>) {
238 try_lock!(self.inner.read()).on_enter(id, ctx)
239 }
240
241 #[inline]
242 fn on_exit(&self, id: &span::Id, ctx: layer::Context<'_, S>) {
243 try_lock!(self.inner.read()).on_exit(id, ctx)
244 }
245
246 #[inline]
247 fn on_close(&self, id: span::Id, ctx: layer::Context<'_, S>) {
248 try_lock!(self.inner.read()).on_close(id, ctx)
249 }
250
251 #[inline]
252 fn max_level_hint(&self) -> Option<LevelFilter> {
253 try_lock!(self.inner.read(), else return None).max_level_hint()
254 }
255}
256
257impl<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 pub fn new(inner: L) -> (Self, Handle<L, S>) {
264 let this = Self {
265 inner: Arc::new(RwLock::new(inner)),
266 _s: PhantomData,
267 };
268 let handle = this.handle();
269 (this, handle)
270 }
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 pub fn handle(&self) -> Handle<L, S> {
277 Handle {
278 inner: Arc::downgrade(&self.inner),
279 _s: PhantomData,
280 }
281 }
282}
283
284// ===== impl Handle =====
285
286impl<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 pub fn reload(&self, new_value: impl Into<L>) -> Result<(), Error> {
301 self.modify(|layer| {
302 *layer = new_value.into();
303 })
304 }
305
306 /// Invokes a closure with a mutable reference to the current layer or filter,
307 /// allowing it to be modified in place.
308 pub fn modify(&self, f: impl FnOnce(&mut L)) -> Result<(), Error> {
309 let inner = self.inner.upgrade().ok_or(Error {
310 kind: ErrorKind::SubscriberGone,
311 })?;
312
313 let mut lock = try_lock!(inner.write(), else return Err(Error::poisoned()));
314 f(&mut *lock);
315 // Release the lock before rebuilding the interest cache, as that
316 // function will lock the new layer.
317 drop(lock);
318
319 callsite::rebuild_interest_cache();
320 Ok(())
321 }
322
323 /// Returns a clone of the layer or filter's current value if it still exists.
324 /// Otherwise, if the subscriber has been dropped, returns `None`.
325 pub fn clone_current(&self) -> Option<L>
326 where
327 L: Clone,
328 {
329 self.with_current(L::clone).ok()
330 }
331
332 /// Invokes a closure with a borrowed reference to the current layer or filter,
333 /// returning the result (or an error if the subscriber no longer exists).
334 pub fn with_current<T>(&self, f: impl FnOnce(&L) -> T) -> Result<T, Error> {
335 let inner = self.inner.upgrade().ok_or(Error {
336 kind: ErrorKind::SubscriberGone,
337 })?;
338 let inner = try_lock!(inner.read(), else return Err(Error::poisoned()));
339 Ok(f(&*inner))
340 }
341}
342
343impl<L, S> Clone for Handle<L, S> {
344 fn clone(&self) -> Self {
345 Handle {
346 inner: self.inner.clone(),
347 _s: PhantomData,
348 }
349 }
350}
351
352// ===== impl Error =====
353
354impl Error {
355 fn poisoned() -> Self {
356 Self {
357 kind: ErrorKind::Poisoned,
358 }
359 }
360
361 /// Returns `true` if this error occurred because the layer was poisoned by
362 /// a panic on another thread.
363 pub fn is_poisoned(&self) -> bool {
364 matches!(self.kind, ErrorKind::Poisoned)
365 }
366
367 /// Returns `true` if this error occurred because the `Subscriber`
368 /// containing the reloadable layer was dropped.
369 pub fn is_dropped(&self) -> bool {
370 matches!(self.kind, ErrorKind::SubscriberGone)
371 }
372}
373
374impl fmt::Display for Error {
375 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
376 let msg: &str = match self.kind {
377 ErrorKind::SubscriberGone => "subscriber no longer exists",
378 ErrorKind::Poisoned => "lock poisoned",
379 };
380 f.pad(msg)
381 }
382}
383
384impl error::Error for Error {}
385