]>
Commit | Line | Data |
---|---|---|
f035d41b XL |
1 | //! Dispatches trace events to [`Subscriber`]s. |
2 | //! | |
3 | //! The _dispatcher_ is the component of the tracing system which is responsible | |
4 | //! for forwarding trace data from the instrumentation points that generate it | |
5 | //! to the subscriber that collects it. | |
6 | //! | |
7 | //! # Using the Trace Dispatcher | |
8 | //! | |
9 | //! Every thread in a program using `tracing` has a _default subscriber_. When | |
10 | //! events occur, or spans are created, they are dispatched to the thread's | |
11 | //! current subscriber. | |
12 | //! | |
13 | //! ## Setting the Default Subscriber | |
14 | //! | |
15 | //! By default, the current subscriber is an empty implementation that does | |
16 | //! nothing. To use a subscriber implementation, it must be set as the default. | |
17 | //! There are two methods for doing so: [`with_default`] and | |
18 | //! [`set_global_default`]. `with_default` sets the default subscriber for the | |
19 | //! duration of a scope, while `set_global_default` sets a default subscriber | |
20 | //! for the entire process. | |
21 | //! | |
22 | //! To use either of these functions, we must first wrap our subscriber in a | |
23 | //! [`Dispatch`], a cloneable, type-erased reference to a subscriber. For | |
24 | //! example: | |
25 | //! ```rust | |
26 | //! # pub struct FooSubscriber; | |
27 | //! # use tracing_core::{ | |
28 | //! # dispatcher, Event, Metadata, | |
29 | //! # span::{Attributes, Id, Record} | |
30 | //! # }; | |
31 | //! # impl tracing_core::Subscriber for FooSubscriber { | |
32 | //! # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(0) } | |
33 | //! # fn record(&self, _: &Id, _: &Record) {} | |
34 | //! # fn event(&self, _: &Event) {} | |
35 | //! # fn record_follows_from(&self, _: &Id, _: &Id) {} | |
36 | //! # fn enabled(&self, _: &Metadata) -> bool { false } | |
37 | //! # fn enter(&self, _: &Id) {} | |
38 | //! # fn exit(&self, _: &Id) {} | |
39 | //! # } | |
40 | //! # impl FooSubscriber { fn new() -> Self { FooSubscriber } } | |
41 | //! use dispatcher::Dispatch; | |
42 | //! | |
43 | //! let my_subscriber = FooSubscriber::new(); | |
44 | //! let my_dispatch = Dispatch::new(my_subscriber); | |
45 | //! ``` | |
46 | //! Then, we can use [`with_default`] to set our `Dispatch` as the default for | |
47 | //! the duration of a block: | |
48 | //! ```rust | |
49 | //! # pub struct FooSubscriber; | |
50 | //! # use tracing_core::{ | |
51 | //! # dispatcher, Event, Metadata, | |
52 | //! # span::{Attributes, Id, Record} | |
53 | //! # }; | |
54 | //! # impl tracing_core::Subscriber for FooSubscriber { | |
55 | //! # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(0) } | |
56 | //! # fn record(&self, _: &Id, _: &Record) {} | |
57 | //! # fn event(&self, _: &Event) {} | |
58 | //! # fn record_follows_from(&self, _: &Id, _: &Id) {} | |
59 | //! # fn enabled(&self, _: &Metadata) -> bool { false } | |
60 | //! # fn enter(&self, _: &Id) {} | |
61 | //! # fn exit(&self, _: &Id) {} | |
62 | //! # } | |
63 | //! # impl FooSubscriber { fn new() -> Self { FooSubscriber } } | |
64 | //! # let my_subscriber = FooSubscriber::new(); | |
65 | //! # let my_dispatch = dispatcher::Dispatch::new(my_subscriber); | |
66 | //! // no default subscriber | |
67 | //! | |
68 | //! # #[cfg(feature = "std")] | |
69 | //! dispatcher::with_default(&my_dispatch, || { | |
70 | //! // my_subscriber is the default | |
71 | //! }); | |
72 | //! | |
73 | //! // no default subscriber again | |
74 | //! ``` | |
75 | //! It's important to note that `with_default` will not propagate the current | |
76 | //! thread's default subscriber to any threads spawned within the `with_default` | |
77 | //! block. To propagate the default subscriber to new threads, either use | |
78 | //! `with_default` from the new thread, or use `set_global_default`. | |
79 | //! | |
80 | //! As an alternative to `with_default`, we can use [`set_global_default`] to | |
81 | //! set a `Dispatch` as the default for all threads, for the lifetime of the | |
82 | //! program. For example: | |
83 | //! ```rust | |
84 | //! # pub struct FooSubscriber; | |
85 | //! # use tracing_core::{ | |
86 | //! # dispatcher, Event, Metadata, | |
87 | //! # span::{Attributes, Id, Record} | |
88 | //! # }; | |
89 | //! # impl tracing_core::Subscriber for FooSubscriber { | |
90 | //! # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(0) } | |
91 | //! # fn record(&self, _: &Id, _: &Record) {} | |
92 | //! # fn event(&self, _: &Event) {} | |
93 | //! # fn record_follows_from(&self, _: &Id, _: &Id) {} | |
94 | //! # fn enabled(&self, _: &Metadata) -> bool { false } | |
95 | //! # fn enter(&self, _: &Id) {} | |
96 | //! # fn exit(&self, _: &Id) {} | |
97 | //! # } | |
98 | //! # impl FooSubscriber { fn new() -> Self { FooSubscriber } } | |
99 | //! # let my_subscriber = FooSubscriber::new(); | |
100 | //! # let my_dispatch = dispatcher::Dispatch::new(my_subscriber); | |
101 | //! // no default subscriber | |
102 | //! | |
103 | //! dispatcher::set_global_default(my_dispatch) | |
104 | //! // `set_global_default` will return an error if the global default | |
105 | //! // subscriber has already been set. | |
106 | //! .expect("global default was already set!"); | |
107 | //! | |
108 | //! // `my_subscriber` is now the default | |
109 | //! ``` | |
110 | //! | |
3dfed10e | 111 | //! <pre class="ignore" style="white-space:normal;font:inherit;"> |
c295e0f8 XL |
112 | //! <strong>Note</strong>:the thread-local scoped dispatcher |
113 | //! (<a href="#fn.with_default"><code>with_default</code></a>) requires the | |
114 | //! Rust standard library. <code>no_std</code> users should use | |
115 | //! <a href="#fn.set_global_default"><code>set_global_default</code></a> | |
116 | //! instead. | |
117 | //! </pre> | |
f035d41b XL |
118 | //! |
119 | //! ## Accessing the Default Subscriber | |
120 | //! | |
121 | //! A thread's current default subscriber can be accessed using the | |
122 | //! [`get_default`] function, which executes a closure with a reference to the | |
123 | //! currently default `Dispatch`. This is used primarily by `tracing` | |
124 | //! instrumentation. | |
125 | //! | |
126 | //! [`Subscriber`]: struct.Subscriber.html | |
127 | //! [`with_default`]: fn.with_default.html | |
128 | //! [`set_global_default`]: fn.set_global_default.html | |
129 | //! [`get_default`]: fn.get_default.html | |
130 | //! [`Dispatch`]: struct.Dispatch.html | |
131 | use crate::{ | |
132 | callsite, span, | |
c295e0f8 | 133 | subscriber::{self, NoSubscriber, Subscriber}, |
3dfed10e | 134 | Event, LevelFilter, Metadata, |
f035d41b XL |
135 | }; |
136 | ||
137 | use crate::stdlib::{ | |
138 | any::Any, | |
139 | fmt, | |
140 | sync::{ | |
141 | atomic::{AtomicBool, AtomicUsize, Ordering}, | |
142 | Arc, Weak, | |
143 | }, | |
144 | }; | |
145 | ||
146 | #[cfg(feature = "std")] | |
147 | use crate::stdlib::{ | |
1b1a35ee | 148 | cell::{Cell, RefCell, RefMut}, |
f035d41b XL |
149 | error, |
150 | }; | |
151 | ||
152 | /// `Dispatch` trace data to a [`Subscriber`]. | |
153 | /// | |
154 | /// [`Subscriber`]: trait.Subscriber.html | |
155 | #[derive(Clone)] | |
156 | pub struct Dispatch { | |
157 | subscriber: Arc<dyn Subscriber + Send + Sync>, | |
158 | } | |
159 | ||
160 | #[cfg(feature = "std")] | |
161 | thread_local! { | |
162 | static CURRENT_STATE: State = State { | |
163 | default: RefCell::new(Dispatch::none()), | |
164 | can_enter: Cell::new(true), | |
165 | }; | |
166 | } | |
167 | ||
168 | static EXISTS: AtomicBool = AtomicBool::new(false); | |
169 | static GLOBAL_INIT: AtomicUsize = AtomicUsize::new(UNINITIALIZED); | |
170 | ||
171 | const UNINITIALIZED: usize = 0; | |
172 | const INITIALIZING: usize = 1; | |
173 | const INITIALIZED: usize = 2; | |
174 | ||
175 | static mut GLOBAL_DISPATCH: Option<Dispatch> = None; | |
176 | ||
177 | /// The dispatch state of a thread. | |
178 | #[cfg(feature = "std")] | |
179 | struct State { | |
180 | /// This thread's current default dispatcher. | |
181 | default: RefCell<Dispatch>, | |
182 | /// Whether or not we can currently begin dispatching a trace event. | |
183 | /// | |
184 | /// This is set to `false` when functions such as `enter`, `exit`, `event`, | |
185 | /// and `new_span` are called on this thread's default dispatcher, to | |
186 | /// prevent further trace events triggered inside those functions from | |
187 | /// creating an infinite recursion. When we finish handling a dispatch, this | |
188 | /// is set back to `true`. | |
189 | can_enter: Cell<bool>, | |
190 | } | |
191 | ||
1b1a35ee XL |
192 | /// While this guard is active, additional calls to subscriber functions on |
193 | /// the default dispatcher will not be able to access the dispatch context. | |
194 | /// Dropping the guard will allow the dispatch context to be re-entered. | |
195 | #[cfg(feature = "std")] | |
196 | struct Entered<'a>(&'a State); | |
197 | ||
f035d41b XL |
198 | /// A guard that resets the current default dispatcher to the prior |
199 | /// default dispatcher when dropped. | |
200 | #[cfg(feature = "std")] | |
201 | #[cfg_attr(docsrs, doc(cfg(feature = "std")))] | |
202 | #[derive(Debug)] | |
203 | pub struct DefaultGuard(Option<Dispatch>); | |
204 | ||
205 | /// Sets this dispatch as the default for the duration of a closure. | |
206 | /// | |
207 | /// The default dispatcher is used when creating a new [span] or | |
208 | /// [`Event`]. | |
209 | /// | |
3dfed10e | 210 | /// <pre class="ignore" style="white-space:normal;font:inherit;"> |
c295e0f8 XL |
211 | /// <strong>Note</strong>: This function required the Rust standard library. |
212 | /// <code>no_std</code> users should use <a href="../fn.set_global_default.html"> | |
213 | /// <code>set_global_default</code></a> instead. | |
214 | /// </pre> | |
f035d41b XL |
215 | /// |
216 | /// [span]: ../span/index.html | |
217 | /// [`Subscriber`]: ../subscriber/trait.Subscriber.html | |
218 | /// [`Event`]: ../event/struct.Event.html | |
219 | /// [`set_global_default`]: ../fn.set_global_default.html | |
220 | #[cfg(feature = "std")] | |
221 | #[cfg_attr(docsrs, doc(cfg(feature = "std")))] | |
222 | pub fn with_default<T>(dispatcher: &Dispatch, f: impl FnOnce() -> T) -> T { | |
223 | // When this guard is dropped, the default dispatcher will be reset to the | |
224 | // prior default. Using this (rather than simply resetting after calling | |
225 | // `f`) ensures that we always reset to the prior dispatcher even if `f` | |
226 | // panics. | |
227 | let _guard = set_default(dispatcher); | |
228 | f() | |
229 | } | |
230 | ||
231 | /// Sets the dispatch as the default dispatch for the duration of the lifetime | |
232 | /// of the returned DefaultGuard | |
233 | /// | |
3dfed10e | 234 | /// <pre class="ignore" style="white-space:normal;font:inherit;"> |
c295e0f8 XL |
235 | /// <strong>Note</strong>: This function required the Rust standard library. |
236 | /// <code>no_std</code> users should use <a href="../fn.set_global_default.html"> | |
237 | /// <code>set_global_default</code></a> instead. | |
238 | /// </pre> | |
f035d41b XL |
239 | /// |
240 | /// [`set_global_default`]: ../fn.set_global_default.html | |
241 | #[cfg(feature = "std")] | |
242 | #[cfg_attr(docsrs, doc(cfg(feature = "std")))] | |
3dfed10e | 243 | #[must_use = "Dropping the guard unregisters the dispatcher."] |
f035d41b XL |
244 | pub fn set_default(dispatcher: &Dispatch) -> DefaultGuard { |
245 | // When this guard is dropped, the default dispatcher will be reset to the | |
246 | // prior default. Using this ensures that we always reset to the prior | |
247 | // dispatcher even if the thread calling this function panics. | |
248 | State::set_default(dispatcher.clone()) | |
249 | } | |
250 | ||
251 | /// Sets this dispatch as the global default for the duration of the entire program. | |
252 | /// Will be used as a fallback if no thread-local dispatch has been set in a thread | |
253 | /// (using `with_default`.) | |
254 | /// | |
255 | /// Can only be set once; subsequent attempts to set the global default will fail. | |
256 | /// Returns `Err` if the global default has already been set. | |
257 | /// | |
5099ac24 | 258 | /// <div class="example-wrap" style="display:inline-block"><pre class="compile_fail" style="white-space:normal;font:inherit;"> |
c295e0f8 XL |
259 | /// <strong>Warning</strong>: In general, libraries should <em>not</em> call |
260 | /// <code>set_global_default()</code>! Doing so will cause conflicts when | |
261 | /// executables that depend on the library try to set the default later. | |
5099ac24 | 262 | /// </pre></div> |
f035d41b XL |
263 | /// |
264 | /// [span]: ../span/index.html | |
265 | /// [`Subscriber`]: ../subscriber/trait.Subscriber.html | |
266 | /// [`Event`]: ../event/struct.Event.html | |
267 | pub fn set_global_default(dispatcher: Dispatch) -> Result<(), SetGlobalDefaultError> { | |
17df50a5 XL |
268 | // if `compare_exchange` returns Result::Ok(_), then `new` has been set and |
269 | // `current`—now the prior value—has been returned in the `Ok()` branch. | |
270 | if GLOBAL_INIT | |
271 | .compare_exchange( | |
272 | UNINITIALIZED, | |
273 | INITIALIZING, | |
274 | Ordering::SeqCst, | |
275 | Ordering::SeqCst, | |
276 | ) | |
277 | .is_ok() | |
f035d41b XL |
278 | { |
279 | unsafe { | |
280 | GLOBAL_DISPATCH = Some(dispatcher); | |
281 | } | |
282 | GLOBAL_INIT.store(INITIALIZED, Ordering::SeqCst); | |
283 | EXISTS.store(true, Ordering::Release); | |
284 | Ok(()) | |
285 | } else { | |
286 | Err(SetGlobalDefaultError { _no_construct: () }) | |
287 | } | |
288 | } | |
289 | ||
290 | /// Returns true if a `tracing` dispatcher has ever been set. | |
291 | /// | |
292 | /// This may be used to completely elide trace points if tracing is not in use | |
293 | /// at all or has yet to be initialized. | |
294 | #[doc(hidden)] | |
295 | #[inline(always)] | |
296 | pub fn has_been_set() -> bool { | |
297 | EXISTS.load(Ordering::Relaxed) | |
298 | } | |
299 | ||
300 | /// Returned if setting the global dispatcher fails. | |
301 | #[derive(Debug)] | |
302 | pub struct SetGlobalDefaultError { | |
303 | _no_construct: (), | |
304 | } | |
305 | ||
306 | impl fmt::Display for SetGlobalDefaultError { | |
307 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
308 | f.pad("a global default trace dispatcher has already been set") | |
309 | } | |
310 | } | |
311 | ||
312 | #[cfg(feature = "std")] | |
313 | #[cfg_attr(docsrs, doc(cfg(feature = "std")))] | |
314 | impl error::Error for SetGlobalDefaultError {} | |
315 | ||
316 | /// Executes a closure with a reference to this thread's current [dispatcher]. | |
317 | /// | |
318 | /// Note that calls to `get_default` should not be nested; if this function is | |
319 | /// called while inside of another `get_default`, that closure will be provided | |
320 | /// with `Dispatch::none` rather than the previously set dispatcher. | |
321 | /// | |
322 | /// [dispatcher]: ../dispatcher/struct.Dispatch.html | |
323 | #[cfg(feature = "std")] | |
324 | pub fn get_default<T, F>(mut f: F) -> T | |
325 | where | |
326 | F: FnMut(&Dispatch) -> T, | |
327 | { | |
f035d41b XL |
328 | CURRENT_STATE |
329 | .try_with(|state| { | |
1b1a35ee XL |
330 | if let Some(entered) = state.enter() { |
331 | return f(&*entered.current()); | |
f035d41b | 332 | } |
1b1a35ee XL |
333 | |
334 | f(&Dispatch::none()) | |
f035d41b XL |
335 | }) |
336 | .unwrap_or_else(|_| f(&Dispatch::none())) | |
337 | } | |
338 | ||
1b1a35ee XL |
339 | /// Executes a closure with a reference to this thread's current [dispatcher]. |
340 | /// | |
341 | /// Note that calls to `get_default` should not be nested; if this function is | |
342 | /// called while inside of another `get_default`, that closure will be provided | |
343 | /// with `Dispatch::none` rather than the previously set dispatcher. | |
344 | /// | |
345 | /// [dispatcher]: ../dispatcher/struct.Dispatch.html | |
346 | #[cfg(feature = "std")] | |
347 | #[doc(hidden)] | |
348 | #[inline(never)] | |
349 | pub fn get_current<T>(f: impl FnOnce(&Dispatch) -> T) -> Option<T> { | |
350 | CURRENT_STATE | |
351 | .try_with(|state| { | |
352 | let entered = state.enter()?; | |
353 | Some(f(&*entered.current())) | |
354 | }) | |
355 | .ok()? | |
356 | } | |
357 | ||
358 | /// Executes a closure with a reference to the current [dispatcher]. | |
359 | /// | |
360 | /// [dispatcher]: ../dispatcher/struct.Dispatch.html | |
361 | #[cfg(not(feature = "std"))] | |
362 | #[doc(hidden)] | |
363 | pub fn get_current<T>(f: impl FnOnce(&Dispatch) -> T) -> Option<T> { | |
364 | let dispatch = get_global()?; | |
365 | Some(f(&dispatch)) | |
366 | } | |
367 | ||
f035d41b XL |
368 | /// Executes a closure with a reference to the current [dispatcher]. |
369 | /// | |
370 | /// [dispatcher]: ../dispatcher/struct.Dispatch.html | |
371 | #[cfg(not(feature = "std"))] | |
372 | pub fn get_default<T, F>(mut f: F) -> T | |
373 | where | |
374 | F: FnMut(&Dispatch) -> T, | |
375 | { | |
376 | if let Some(d) = get_global() { | |
377 | f(d) | |
378 | } else { | |
379 | f(&Dispatch::none()) | |
380 | } | |
381 | } | |
382 | ||
383 | fn get_global() -> Option<&'static Dispatch> { | |
384 | if GLOBAL_INIT.load(Ordering::SeqCst) != INITIALIZED { | |
385 | return None; | |
386 | } | |
387 | unsafe { | |
388 | // This is safe given the invariant that setting the global dispatcher | |
389 | // also sets `GLOBAL_INIT` to `INITIALIZED`. | |
390 | Some(GLOBAL_DISPATCH.as_ref().expect( | |
391 | "invariant violated: GLOBAL_DISPATCH must be initialized before GLOBAL_INIT is set", | |
392 | )) | |
393 | } | |
394 | } | |
395 | ||
396 | pub(crate) struct Registrar(Weak<dyn Subscriber + Send + Sync>); | |
397 | ||
398 | impl Dispatch { | |
399 | /// Returns a new `Dispatch` that discards events and spans. | |
400 | #[inline] | |
401 | pub fn none() -> Self { | |
402 | Dispatch { | |
c295e0f8 | 403 | subscriber: Arc::new(NoSubscriber::default()), |
f035d41b XL |
404 | } |
405 | } | |
406 | ||
407 | /// Returns a `Dispatch` that forwards to the given [`Subscriber`]. | |
408 | /// | |
409 | /// [`Subscriber`]: ../subscriber/trait.Subscriber.html | |
410 | pub fn new<S>(subscriber: S) -> Self | |
411 | where | |
412 | S: Subscriber + Send + Sync + 'static, | |
413 | { | |
414 | let me = Dispatch { | |
415 | subscriber: Arc::new(subscriber), | |
416 | }; | |
417 | callsite::register_dispatch(&me); | |
418 | me | |
419 | } | |
420 | ||
421 | pub(crate) fn registrar(&self) -> Registrar { | |
422 | Registrar(Arc::downgrade(&self.subscriber)) | |
423 | } | |
424 | ||
425 | /// Registers a new callsite with this subscriber, returning whether or not | |
426 | /// the subscriber is interested in being notified about the callsite. | |
427 | /// | |
428 | /// This calls the [`register_callsite`] function on the [`Subscriber`] | |
429 | /// that this `Dispatch` forwards to. | |
430 | /// | |
431 | /// [`Subscriber`]: ../subscriber/trait.Subscriber.html | |
432 | /// [`register_callsite`]: ../subscriber/trait.Subscriber.html#method.register_callsite | |
433 | #[inline] | |
434 | pub fn register_callsite(&self, metadata: &'static Metadata<'static>) -> subscriber::Interest { | |
435 | self.subscriber.register_callsite(metadata) | |
436 | } | |
437 | ||
3dfed10e XL |
438 | /// Returns the highest [verbosity level][level] that this [`Subscriber`] will |
439 | /// enable, or `None`, if the subscriber does not implement level-based | |
440 | /// filtering or chooses not to implement this method. | |
441 | /// | |
442 | /// This calls the [`max_level_hint`] function on the [`Subscriber`] | |
443 | /// that this `Dispatch` forwards to. | |
444 | /// | |
445 | /// [level]: ../struct.Level.html | |
446 | /// [`Subscriber`]: ../subscriber/trait.Subscriber.html | |
447 | /// [`register_callsite`]: ../subscriber/trait.Subscriber.html#method.max_level_hint | |
448 | // TODO(eliza): consider making this a public API? | |
449 | #[inline] | |
450 | pub(crate) fn max_level_hint(&self) -> Option<LevelFilter> { | |
451 | self.subscriber.max_level_hint() | |
452 | } | |
453 | ||
f035d41b XL |
454 | /// Record the construction of a new span, returning a new [ID] for the |
455 | /// span being constructed. | |
456 | /// | |
457 | /// This calls the [`new_span`] function on the [`Subscriber`] that this | |
458 | /// `Dispatch` forwards to. | |
459 | /// | |
460 | /// [ID]: ../span/struct.Id.html | |
461 | /// [`Subscriber`]: ../subscriber/trait.Subscriber.html | |
462 | /// [`new_span`]: ../subscriber/trait.Subscriber.html#method.new_span | |
463 | #[inline] | |
464 | pub fn new_span(&self, span: &span::Attributes<'_>) -> span::Id { | |
465 | self.subscriber.new_span(span) | |
466 | } | |
467 | ||
468 | /// Record a set of values on a span. | |
469 | /// | |
470 | /// This calls the [`record`] function on the [`Subscriber`] that this | |
471 | /// `Dispatch` forwards to. | |
472 | /// | |
473 | /// [`Subscriber`]: ../subscriber/trait.Subscriber.html | |
474 | /// [`record`]: ../subscriber/trait.Subscriber.html#method.record | |
475 | #[inline] | |
476 | pub fn record(&self, span: &span::Id, values: &span::Record<'_>) { | |
477 | self.subscriber.record(span, values) | |
478 | } | |
479 | ||
480 | /// Adds an indication that `span` follows from the span with the id | |
481 | /// `follows`. | |
482 | /// | |
483 | /// This calls the [`record_follows_from`] function on the [`Subscriber`] | |
484 | /// that this `Dispatch` forwards to. | |
485 | /// | |
486 | /// [`Subscriber`]: ../subscriber/trait.Subscriber.html | |
487 | /// [`record_follows_from`]: ../subscriber/trait.Subscriber.html#method.record_follows_from | |
488 | #[inline] | |
489 | pub fn record_follows_from(&self, span: &span::Id, follows: &span::Id) { | |
490 | self.subscriber.record_follows_from(span, follows) | |
491 | } | |
492 | ||
493 | /// Returns true if a span with the specified [metadata] would be | |
494 | /// recorded. | |
495 | /// | |
496 | /// This calls the [`enabled`] function on the [`Subscriber`] that this | |
497 | /// `Dispatch` forwards to. | |
498 | /// | |
499 | /// [metadata]: ../metadata/struct.Metadata.html | |
500 | /// [`Subscriber`]: ../subscriber/trait.Subscriber.html | |
501 | /// [`enabled`]: ../subscriber/trait.Subscriber.html#method.enabled | |
502 | #[inline] | |
503 | pub fn enabled(&self, metadata: &Metadata<'_>) -> bool { | |
504 | self.subscriber.enabled(metadata) | |
505 | } | |
506 | ||
507 | /// Records that an [`Event`] has occurred. | |
508 | /// | |
509 | /// This calls the [`event`] function on the [`Subscriber`] that this | |
510 | /// `Dispatch` forwards to. | |
511 | /// | |
512 | /// [`Event`]: ../event/struct.Event.html | |
513 | /// [`Subscriber`]: ../subscriber/trait.Subscriber.html | |
514 | /// [`event`]: ../subscriber/trait.Subscriber.html#method.event | |
515 | #[inline] | |
516 | pub fn event(&self, event: &Event<'_>) { | |
517 | self.subscriber.event(event) | |
518 | } | |
519 | ||
520 | /// Records that a span has been can_enter. | |
521 | /// | |
522 | /// This calls the [`enter`] function on the [`Subscriber`] that this | |
523 | /// `Dispatch` forwards to. | |
524 | /// | |
525 | /// [`Subscriber`]: ../subscriber/trait.Subscriber.html | |
526 | /// [`enter`]: ../subscriber/trait.Subscriber.html#method.enter | |
527 | #[inline] | |
528 | pub fn enter(&self, span: &span::Id) { | |
529 | self.subscriber.enter(span); | |
530 | } | |
531 | ||
532 | /// Records that a span has been exited. | |
533 | /// | |
534 | /// This calls the [`exit`] function on the [`Subscriber`] that this | |
535 | /// `Dispatch` forwards to. | |
536 | /// | |
537 | /// [`Subscriber`]: ../subscriber/trait.Subscriber.html | |
538 | /// [`exit`]: ../subscriber/trait.Subscriber.html#method.exit | |
539 | #[inline] | |
540 | pub fn exit(&self, span: &span::Id) { | |
541 | self.subscriber.exit(span); | |
542 | } | |
543 | ||
544 | /// Notifies the subscriber that a [span ID] has been cloned. | |
545 | /// | |
546 | /// This function must only be called with span IDs that were returned by | |
547 | /// this `Dispatch`'s [`new_span`] function. The `tracing` crate upholds | |
548 | /// this guarantee and any other libraries implementing instrumentation APIs | |
549 | /// must as well. | |
550 | /// | |
551 | /// This calls the [`clone_span`] function on the `Subscriber` that this | |
552 | /// `Dispatch` forwards to. | |
553 | /// | |
554 | /// [span ID]: ../span/struct.Id.html | |
555 | /// [`Subscriber`]: ../subscriber/trait.Subscriber.html | |
556 | /// [`clone_span`]: ../subscriber/trait.Subscriber.html#method.clone_span | |
557 | /// [`new_span`]: ../subscriber/trait.Subscriber.html#method.new_span | |
558 | #[inline] | |
559 | pub fn clone_span(&self, id: &span::Id) -> span::Id { | |
c295e0f8 | 560 | self.subscriber.clone_span(id) |
f035d41b XL |
561 | } |
562 | ||
563 | /// Notifies the subscriber that a [span ID] has been dropped. | |
564 | /// | |
565 | /// This function must only be called with span IDs that were returned by | |
566 | /// this `Dispatch`'s [`new_span`] function. The `tracing` crate upholds | |
567 | /// this guarantee and any other libraries implementing instrumentation APIs | |
568 | /// must as well. | |
569 | /// | |
3dfed10e | 570 | /// This calls the [`drop_span`] function on the [`Subscriber`] that this |
c295e0f8 | 571 | /// `Dispatch` forwards to. |
f035d41b | 572 | /// |
c295e0f8 XL |
573 | /// <pre class="compile_fail" style="white-space:normal;font:inherit;"> |
574 | /// <strong>Deprecated</strong>: The <a href="#method.try_close"><code> | |
575 | /// try_close</code></a> method is functionally identical, but returns | |
576 | /// <code>true</code> if the span is now closed. It should be used | |
577 | /// instead of this method. | |
578 | /// </pre> | |
f035d41b XL |
579 | /// |
580 | /// [span ID]: ../span/struct.Id.html | |
581 | /// [`Subscriber`]: ../subscriber/trait.Subscriber.html | |
582 | /// [`drop_span`]: ../subscriber/trait.Subscriber.html#method.drop_span | |
583 | /// [`new_span`]: ../subscriber/trait.Subscriber.html#method.new_span | |
584 | /// [`try_close`]: #method.try_close | |
585 | #[inline] | |
586 | #[deprecated(since = "0.1.2", note = "use `Dispatch::try_close` instead")] | |
587 | pub fn drop_span(&self, id: span::Id) { | |
588 | #[allow(deprecated)] | |
589 | self.subscriber.drop_span(id); | |
590 | } | |
591 | ||
592 | /// Notifies the subscriber that a [span ID] has been dropped, and returns | |
593 | /// `true` if there are now 0 IDs referring to that span. | |
594 | /// | |
595 | /// This function must only be called with span IDs that were returned by | |
596 | /// this `Dispatch`'s [`new_span`] function. The `tracing` crate upholds | |
597 | /// this guarantee and any other libraries implementing instrumentation APIs | |
598 | /// must as well. | |
599 | /// | |
3dfed10e | 600 | /// This calls the [`try_close`] function on the [`Subscriber`] that this |
f035d41b XL |
601 | /// `Dispatch` forwards to. |
602 | /// | |
603 | /// [span ID]: ../span/struct.Id.html | |
604 | /// [`Subscriber`]: ../subscriber/trait.Subscriber.html | |
605 | /// [`try_close`]: ../subscriber/trait.Subscriber.html#method.try_close | |
606 | /// [`new_span`]: ../subscriber/trait.Subscriber.html#method.new_span | |
607 | #[inline] | |
608 | pub fn try_close(&self, id: span::Id) -> bool { | |
609 | self.subscriber.try_close(id) | |
610 | } | |
611 | ||
612 | /// Returns a type representing this subscriber's view of the current span. | |
613 | /// | |
614 | /// This calls the [`current`] function on the `Subscriber` that this | |
615 | /// `Dispatch` forwards to. | |
616 | /// | |
617 | /// [`current`]: ../subscriber/trait.Subscriber.html#method.current | |
618 | #[inline] | |
619 | pub fn current_span(&self) -> span::Current { | |
620 | self.subscriber.current_span() | |
621 | } | |
622 | ||
623 | /// Returns `true` if this `Dispatch` forwards to a `Subscriber` of type | |
624 | /// `T`. | |
625 | #[inline] | |
626 | pub fn is<T: Any>(&self) -> bool { | |
17df50a5 | 627 | <dyn Subscriber>::is::<T>(&*self.subscriber) |
f035d41b XL |
628 | } |
629 | ||
630 | /// Returns some reference to the `Subscriber` this `Dispatch` forwards to | |
631 | /// if it is of type `T`, or `None` if it isn't. | |
632 | #[inline] | |
633 | pub fn downcast_ref<T: Any>(&self) -> Option<&T> { | |
17df50a5 | 634 | <dyn Subscriber>::downcast_ref(&*self.subscriber) |
f035d41b XL |
635 | } |
636 | } | |
637 | ||
638 | impl Default for Dispatch { | |
639 | /// Returns the current default dispatcher | |
640 | fn default() -> Self { | |
641 | get_default(|default| default.clone()) | |
642 | } | |
643 | } | |
644 | ||
645 | impl fmt::Debug for Dispatch { | |
646 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
647 | f.pad("Dispatch(...)") | |
648 | } | |
649 | } | |
650 | ||
651 | impl<S> From<S> for Dispatch | |
652 | where | |
653 | S: Subscriber + Send + Sync + 'static, | |
654 | { | |
655 | #[inline] | |
656 | fn from(subscriber: S) -> Self { | |
657 | Dispatch::new(subscriber) | |
658 | } | |
659 | } | |
660 | ||
f035d41b XL |
661 | impl Registrar { |
662 | pub(crate) fn try_register( | |
663 | &self, | |
664 | metadata: &'static Metadata<'static>, | |
665 | ) -> Option<subscriber::Interest> { | |
666 | self.0.upgrade().map(|s| s.register_callsite(metadata)) | |
667 | } | |
668 | ||
3dfed10e XL |
669 | pub(crate) fn upgrade(&self) -> Option<Dispatch> { |
670 | self.0.upgrade().map(|subscriber| Dispatch { subscriber }) | |
f035d41b XL |
671 | } |
672 | } | |
673 | ||
674 | // ===== impl State ===== | |
675 | ||
676 | #[cfg(feature = "std")] | |
677 | impl State { | |
678 | /// Replaces the current default dispatcher on this thread with the provided | |
679 | /// dispatcher.Any | |
680 | /// | |
681 | /// Dropping the returned `ResetGuard` will reset the default dispatcher to | |
682 | /// the previous value. | |
683 | #[inline] | |
684 | fn set_default(new_dispatch: Dispatch) -> DefaultGuard { | |
685 | let prior = CURRENT_STATE | |
686 | .try_with(|state| { | |
687 | state.can_enter.set(true); | |
688 | state.default.replace(new_dispatch) | |
689 | }) | |
690 | .ok(); | |
691 | EXISTS.store(true, Ordering::Release); | |
692 | DefaultGuard(prior) | |
693 | } | |
1b1a35ee XL |
694 | |
695 | #[inline] | |
696 | fn enter(&self) -> Option<Entered<'_>> { | |
697 | if self.can_enter.replace(false) { | |
c295e0f8 | 698 | Some(Entered(self)) |
1b1a35ee XL |
699 | } else { |
700 | None | |
701 | } | |
702 | } | |
703 | } | |
704 | ||
705 | // ===== impl Entered ===== | |
706 | ||
707 | #[cfg(feature = "std")] | |
708 | impl<'a> Entered<'a> { | |
709 | #[inline] | |
710 | fn current(&self) -> RefMut<'a, Dispatch> { | |
711 | let mut default = self.0.default.borrow_mut(); | |
712 | ||
713 | if default.is::<NoSubscriber>() { | |
714 | if let Some(global) = get_global() { | |
715 | // don't redo this call on the next check | |
716 | *default = global.clone(); | |
717 | } | |
718 | } | |
719 | ||
720 | default | |
721 | } | |
722 | } | |
723 | ||
724 | #[cfg(feature = "std")] | |
725 | impl<'a> Drop for Entered<'a> { | |
726 | #[inline] | |
727 | fn drop(&mut self) { | |
728 | self.0.can_enter.set(true); | |
729 | } | |
f035d41b XL |
730 | } |
731 | ||
732 | // ===== impl DefaultGuard ===== | |
733 | ||
734 | #[cfg(feature = "std")] | |
735 | impl Drop for DefaultGuard { | |
736 | #[inline] | |
737 | fn drop(&mut self) { | |
738 | if let Some(dispatch) = self.0.take() { | |
739 | // Replace the dispatcher and then drop the old one outside | |
740 | // of the thread-local context. Dropping the dispatch may | |
741 | // lead to the drop of a subscriber which, in the process, | |
742 | // could then also attempt to access the same thread local | |
743 | // state -- causing a clash. | |
744 | let prev = CURRENT_STATE.try_with(|state| state.default.replace(dispatch)); | |
745 | drop(prev) | |
746 | } | |
747 | } | |
748 | } | |
749 | ||
750 | #[cfg(test)] | |
751 | mod test { | |
752 | use super::*; | |
753 | #[cfg(feature = "std")] | |
754 | use crate::stdlib::sync::atomic::{AtomicUsize, Ordering}; | |
755 | use crate::{ | |
756 | callsite::Callsite, | |
757 | metadata::{Kind, Level, Metadata}, | |
758 | subscriber::Interest, | |
759 | }; | |
760 | ||
761 | #[test] | |
762 | fn dispatch_is() { | |
c295e0f8 | 763 | let dispatcher = Dispatch::new(NoSubscriber::default()); |
f035d41b XL |
764 | assert!(dispatcher.is::<NoSubscriber>()); |
765 | } | |
766 | ||
767 | #[test] | |
768 | fn dispatch_downcasts() { | |
c295e0f8 | 769 | let dispatcher = Dispatch::new(NoSubscriber::default()); |
f035d41b XL |
770 | assert!(dispatcher.downcast_ref::<NoSubscriber>().is_some()); |
771 | } | |
772 | ||
773 | struct TestCallsite; | |
774 | static TEST_CALLSITE: TestCallsite = TestCallsite; | |
775 | static TEST_META: Metadata<'static> = metadata! { | |
776 | name: "test", | |
777 | target: module_path!(), | |
778 | level: Level::DEBUG, | |
779 | fields: &[], | |
780 | callsite: &TEST_CALLSITE, | |
781 | kind: Kind::EVENT | |
782 | }; | |
783 | ||
784 | impl Callsite for TestCallsite { | |
785 | fn set_interest(&self, _: Interest) {} | |
786 | fn metadata(&self) -> &Metadata<'_> { | |
787 | &TEST_META | |
788 | } | |
789 | } | |
790 | ||
791 | #[test] | |
792 | #[cfg(feature = "std")] | |
793 | fn events_dont_infinite_loop() { | |
794 | // This test ensures that an event triggered within a subscriber | |
795 | // won't cause an infinite loop of events. | |
796 | struct TestSubscriber; | |
797 | impl Subscriber for TestSubscriber { | |
798 | fn enabled(&self, _: &Metadata<'_>) -> bool { | |
799 | true | |
800 | } | |
801 | ||
802 | fn new_span(&self, _: &span::Attributes<'_>) -> span::Id { | |
803 | span::Id::from_u64(0xAAAA) | |
804 | } | |
805 | ||
806 | fn record(&self, _: &span::Id, _: &span::Record<'_>) {} | |
807 | ||
808 | fn record_follows_from(&self, _: &span::Id, _: &span::Id) {} | |
809 | ||
810 | fn event(&self, _: &Event<'_>) { | |
811 | static EVENTS: AtomicUsize = AtomicUsize::new(0); | |
812 | assert_eq!( | |
813 | EVENTS.fetch_add(1, Ordering::Relaxed), | |
814 | 0, | |
815 | "event method called twice!" | |
816 | ); | |
817 | Event::dispatch(&TEST_META, &TEST_META.fields().value_set(&[])) | |
818 | } | |
819 | ||
820 | fn enter(&self, _: &span::Id) {} | |
821 | ||
822 | fn exit(&self, _: &span::Id) {} | |
823 | } | |
824 | ||
825 | with_default(&Dispatch::new(TestSubscriber), || { | |
826 | Event::dispatch(&TEST_META, &TEST_META.fields().value_set(&[])) | |
827 | }) | |
828 | } | |
829 | ||
830 | #[test] | |
831 | #[cfg(feature = "std")] | |
832 | fn spans_dont_infinite_loop() { | |
833 | // This test ensures that a span created within a subscriber | |
834 | // won't cause an infinite loop of new spans. | |
835 | ||
836 | fn mk_span() { | |
837 | get_default(|current| { | |
838 | current.new_span(&span::Attributes::new( | |
839 | &TEST_META, | |
840 | &TEST_META.fields().value_set(&[]), | |
841 | )) | |
842 | }); | |
843 | } | |
844 | ||
845 | struct TestSubscriber; | |
846 | impl Subscriber for TestSubscriber { | |
847 | fn enabled(&self, _: &Metadata<'_>) -> bool { | |
848 | true | |
849 | } | |
850 | ||
851 | fn new_span(&self, _: &span::Attributes<'_>) -> span::Id { | |
852 | static NEW_SPANS: AtomicUsize = AtomicUsize::new(0); | |
853 | assert_eq!( | |
854 | NEW_SPANS.fetch_add(1, Ordering::Relaxed), | |
855 | 0, | |
856 | "new_span method called twice!" | |
857 | ); | |
858 | mk_span(); | |
859 | span::Id::from_u64(0xAAAA) | |
860 | } | |
861 | ||
862 | fn record(&self, _: &span::Id, _: &span::Record<'_>) {} | |
863 | ||
864 | fn record_follows_from(&self, _: &span::Id, _: &span::Id) {} | |
865 | ||
866 | fn event(&self, _: &Event<'_>) {} | |
867 | ||
868 | fn enter(&self, _: &span::Id) {} | |
869 | ||
870 | fn exit(&self, _: &span::Id) {} | |
871 | } | |
872 | ||
873 | with_default(&Dispatch::new(TestSubscriber), mk_span) | |
874 | } | |
875 | ||
876 | #[test] | |
877 | fn default_no_subscriber() { | |
878 | let default_dispatcher = Dispatch::default(); | |
879 | assert!(default_dispatcher.is::<NoSubscriber>()); | |
880 | } | |
881 | ||
882 | #[cfg(feature = "std")] | |
883 | #[test] | |
884 | fn default_dispatch() { | |
885 | struct TestSubscriber; | |
886 | impl Subscriber for TestSubscriber { | |
887 | fn enabled(&self, _: &Metadata<'_>) -> bool { | |
888 | true | |
889 | } | |
890 | ||
891 | fn new_span(&self, _: &span::Attributes<'_>) -> span::Id { | |
892 | span::Id::from_u64(0xAAAA) | |
893 | } | |
894 | ||
895 | fn record(&self, _: &span::Id, _: &span::Record<'_>) {} | |
896 | ||
897 | fn record_follows_from(&self, _: &span::Id, _: &span::Id) {} | |
898 | ||
899 | fn event(&self, _: &Event<'_>) {} | |
900 | ||
901 | fn enter(&self, _: &span::Id) {} | |
902 | ||
903 | fn exit(&self, _: &span::Id) {} | |
904 | } | |
905 | let guard = set_default(&Dispatch::new(TestSubscriber)); | |
906 | let default_dispatcher = Dispatch::default(); | |
907 | assert!(default_dispatcher.is::<TestSubscriber>()); | |
908 | ||
909 | drop(guard); | |
910 | let default_dispatcher = Dispatch::default(); | |
911 | assert!(default_dispatcher.is::<NoSubscriber>()); | |
912 | } | |
913 | } |