tokio_trace_core/dispatcher.rs
1//! Dispatches trace events to `Subscriber`s.c
2use {
3 callsite, span,
4 subscriber::{self, Subscriber},
5 Event, Metadata,
6};
7
8use std::{
9 any::Any,
10 cell::{Cell, RefCell},
11 fmt,
12 sync::{Arc, Weak},
13};
14
15/// `Dispatch` trace data to a [`Subscriber`].
16///
17/// [`Subscriber`]: ../subscriber/trait.Subscriber.html
18#[derive(Clone)]
19pub struct Dispatch {
20 subscriber: Arc<Subscriber + Send + Sync>,
21}
22
23thread_local! {
24 static CURRENT_STATE: State = State {
25 default: RefCell::new(Dispatch::none()),
26 can_enter: Cell::new(true),
27 };
28}
29
30/// The dispatch state of a thread.
31struct State {
32 /// This thread's current default dispatcher.
33 default: RefCell<Dispatch>,
34 /// Whether or not we can currently begin dispatching a trace event.
35 ///
36 /// This is set to `false` when functions such as `enter`, `exit`, `event`,
37 /// and `new_span` are called on this thread's default dispatcher, to
38 /// prevent further trace events triggered inside those functions from
39 /// creating an infinite recursion. When we finish handling a dispatch, this
40 /// is set back to `true`.
41 can_enter: Cell<bool>,
42}
43
44/// A guard that resets the current default dispatcher to the prior
45/// default dispatcher when dropped.
46struct ResetGuard(Option<Dispatch>);
47
48/// Sets this dispatch as the default for the duration of a closure.
49///
50/// The default dispatcher is used when creating a new [span] or
51/// [`Event`], _if no span is currently executing_. If a span is currently
52/// executing, new spans or events are dispatched to the subscriber that
53/// tagged that span, instead.
54///
55/// [span]: ../span/index.html
56/// [`Subscriber`]: ../subscriber/trait.Subscriber.html
57/// [`Event`]: ../event/struct.Event.html
58pub fn with_default<T>(dispatcher: &Dispatch, f: impl FnOnce() -> T) -> T {
59 // When this guard is dropped, the default dispatcher will be reset to the
60 // prior default. Using this (rather than simply resetting after calling
61 // `f`) ensures that we always reset to the prior dispatcher even if `f`
62 // panics.
63 let _guard = State::set_default(dispatcher.clone());
64 f()
65}
66/// Executes a closure with a reference to this thread's current [dispatcher].
67///
68/// Note that calls to `get_default` should not be nested; if this function is
69/// called while inside of another `get_default`, that closure will be provided
70/// with `Dispatch::none` rather than the previously set dispatcher.
71///
72/// [dispatcher]: ../dispatcher/struct.Dispatch.html
73pub fn get_default<T, F>(mut f: F) -> T
74where
75 F: FnMut(&Dispatch) -> T,
76{
77 // While this guard is active, additional calls to subscriber functions on
78 // the default dispatcher will not be able to access the dispatch context.
79 // Dropping the guard will allow the dispatch context to be re-entered.
80 struct Entered<'a>(&'a Cell<bool>);
81 impl<'a> Drop for Entered<'a> {
82 #[inline]
83 fn drop(&mut self) {
84 self.0.set(true);
85 }
86 }
87
88 CURRENT_STATE
89 .try_with(|state| {
90 if state.can_enter.replace(false) {
91 let _guard = Entered(&state.can_enter);
92 f(&state.default.borrow())
93 } else {
94 f(&Dispatch::none())
95 }
96 })
97 .unwrap_or_else(|_| f(&Dispatch::none()))
98}
99
100pub(crate) struct Registrar(Weak<Subscriber + Send + Sync>);
101
102impl Dispatch {
103 /// Returns a new `Dispatch` that discards events and spans.
104 #[inline]
105 pub fn none() -> Self {
106 Dispatch {
107 subscriber: Arc::new(NoSubscriber),
108 }
109 }
110
111 /// Returns a `Dispatch` that forwards to the given [`Subscriber`].
112 ///
113 /// [`Subscriber`]: ../subscriber/trait.Subscriber.html
114 pub fn new<S>(subscriber: S) -> Self
115 where
116 S: Subscriber + Send + Sync + 'static,
117 {
118 let me = Dispatch {
119 subscriber: Arc::new(subscriber),
120 };
121 callsite::register_dispatch(&me);
122 me
123 }
124
125 pub(crate) fn registrar(&self) -> Registrar {
126 Registrar(Arc::downgrade(&self.subscriber))
127 }
128
129 /// Registers a new callsite with this subscriber, returning whether or not
130 /// the subscriber is interested in being notified about the callsite.
131 ///
132 /// This calls the [`register_callsite`] function on the [`Subscriber`]
133 /// that this `Dispatch` forwards to.
134 ///
135 /// [`Subscriber`]: ../subscriber/trait.Subscriber.html
136 /// [`register_callsite`]: ../subscriber/trait.Subscriber.html#method.register_callsite
137 #[inline]
138 pub fn register_callsite(&self, metadata: &Metadata) -> subscriber::Interest {
139 self.subscriber.register_callsite(metadata)
140 }
141
142 /// Record the construction of a new span, returning a new [ID] for the
143 /// span being constructed.
144 ///
145 /// This calls the [`new_span`] function on the [`Subscriber`] that this
146 /// `Dispatch` forwards to.
147 ///
148 /// [ID]: ../span/struct.Id.html
149 /// [`Subscriber`]: ../subscriber/trait.Subscriber.html
150 /// [`new_span`]: ../subscriber/trait.Subscriber.html#method.new_span
151 #[inline]
152 pub fn new_span(&self, span: &span::Attributes) -> span::Id {
153 self.subscriber.new_span(span)
154 }
155
156 /// Record a set of values on a span.
157 ///
158 /// This calls the [`record`] function on the [`Subscriber`] that this
159 /// `Dispatch` forwards to.
160 ///
161 /// [`Subscriber`]: ../subscriber/trait.Subscriber.html
162 /// [`record`]: ../subscriber/trait.Subscriber.html#method.record
163 #[inline]
164 pub fn record(&self, span: &span::Id, values: &span::Record) {
165 self.subscriber.record(span, values)
166 }
167
168 /// Adds an indication that `span` follows from the span with the id
169 /// `follows`.
170 ///
171 /// This calls the [`record_follows_from`] function on the [`Subscriber`]
172 /// that this `Dispatch` forwards to.
173 ///
174 /// [`Subscriber`]: ../subscriber/trait.Subscriber.html
175 /// [`record_follows_from`]: ../subscriber/trait.Subscriber.html#method.record_follows_from
176 #[inline]
177 pub fn record_follows_from(&self, span: &span::Id, follows: &span::Id) {
178 self.subscriber.record_follows_from(span, follows)
179 }
180
181 /// Returns true if a span with the specified [metadata] would be
182 /// recorded.
183 ///
184 /// This calls the [`enabled`] function on the [`Subscriber`] that this
185 /// `Dispatch` forwards to.
186 ///
187 /// [metadata]: ../metadata/struct.Metadata.html
188 /// [`Subscriber`]: ../subscriber/trait.Subscriber.html
189 /// [`enabled`]: ../subscriber/trait.Subscriber.html#method.enabled
190 #[inline]
191 pub fn enabled(&self, metadata: &Metadata) -> bool {
192 self.subscriber.enabled(metadata)
193 }
194
195 /// Records that an [`Event`] has occurred.
196 ///
197 /// This calls the [`event`] function on the [`Subscriber`] that this
198 /// `Dispatch` forwards to.
199 ///
200 /// [`Event`]: ../event/struct.Event.html
201 /// [`Subscriber`]: ../subscriber/trait.Subscriber.html
202 /// [`event`]: ../subscriber/trait.Subscriber.html#method.event
203 #[inline]
204 pub fn event(&self, event: &Event) {
205 self.subscriber.event(event)
206 }
207
208 /// Records that a span has been can_enter.
209 ///
210 /// This calls the [`enter`] function on the [`Subscriber`] that this
211 /// `Dispatch` forwards to.
212 ///
213 /// [`Subscriber`]: ../subscriber/trait.Subscriber.html
214 /// [`event`]: ../subscriber/trait.Subscriber.html#method.event
215 #[inline]
216 pub fn enter(&self, span: &span::Id) {
217 self.subscriber.enter(span);
218 }
219
220 /// Records that a span has been exited.
221 ///
222 /// This calls the [`exit`](::Subscriber::exit) function on the `Subscriber`
223 /// that this `Dispatch` forwards to.
224 #[inline]
225 pub fn exit(&self, span: &span::Id) {
226 self.subscriber.exit(span);
227 }
228
229 /// Notifies the subscriber that a [span ID] has been cloned.
230 ///
231 /// This function is guaranteed to only be called with span IDs that were
232 /// returned by this `Dispatch`'s [`new_span`] function.
233 ///
234 /// This calls the [`clone_span`] function on the `Subscriber` that this
235 /// `Dispatch` forwards to.
236 ///
237 /// [span ID]: ../span/struct.Id.html
238 /// [`Subscriber`]: ../subscriber/trait.Subscriber.html
239 /// [`clone_span`]: ../subscriber/trait.Subscriber.html#method.clone_span
240 /// [`new_span`]: ../subscriber/trait.Subscriber.html#method.new_span
241 #[inline]
242 pub fn clone_span(&self, id: &span::Id) -> span::Id {
243 self.subscriber.clone_span(&id)
244 }
245
246 /// Notifies the subscriber that a [span ID] has been dropped.
247 ///
248 /// This function is guaranteed to only be called with span IDs that were
249 /// returned by this `Dispatch`'s [`new_span`] function.
250 ///
251 /// This calls the [`drop_span`] function on the [`Subscriber`] that this
252 /// `Dispatch` forwards to.
253 ///
254 /// [span ID]: ../span/struct.Id.html
255 /// [`Subscriber`]: ../subscriber/trait.Subscriber.html
256 /// [`clone_span`]: ../subscriber/trait.Subscriber.html#method.clone_span
257 /// [`new_span`]: ../subscriber/trait.Subscriber.html#method.new_span
258 #[inline]
259 pub fn drop_span(&self, id: span::Id) {
260 self.subscriber.drop_span(id)
261 }
262
263 /// Returns `true` if this `Dispatch` forwards to a `Subscriber` of type
264 /// `T`.
265 #[inline]
266 pub fn is<T: Any>(&self) -> bool {
267 Subscriber::is::<T>(&*self.subscriber)
268 }
269
270 /// Returns some reference to the `Subscriber` this `Dispatch` forwards to
271 /// if it is of type `T`, or `None` if it isn't.
272 #[inline]
273 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
274 Subscriber::downcast_ref(&*self.subscriber)
275 }
276}
277
278impl fmt::Debug for Dispatch {
279 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
280 f.pad("Dispatch(...)")
281 }
282}
283
284impl<S> From<S> for Dispatch
285where
286 S: Subscriber + Send + Sync + 'static,
287{
288 #[inline]
289 fn from(subscriber: S) -> Self {
290 Dispatch::new(subscriber)
291 }
292}
293
294struct NoSubscriber;
295impl Subscriber for NoSubscriber {
296 #[inline]
297 fn register_callsite(&self, _: &Metadata) -> subscriber::Interest {
298 subscriber::Interest::never()
299 }
300
301 fn new_span(&self, _: &span::Attributes) -> span::Id {
302 span::Id::from_u64(0xDEAD)
303 }
304
305 fn event(&self, _event: &Event) {}
306
307 fn record(&self, _span: &span::Id, _values: &span::Record) {}
308
309 fn record_follows_from(&self, _span: &span::Id, _follows: &span::Id) {}
310
311 #[inline]
312 fn enabled(&self, _metadata: &Metadata) -> bool {
313 false
314 }
315
316 fn enter(&self, _span: &span::Id) {}
317 fn exit(&self, _span: &span::Id) {}
318}
319
320impl Registrar {
321 pub(crate) fn try_register(&self, metadata: &Metadata) -> Option<subscriber::Interest> {
322 self.0.upgrade().map(|s| s.register_callsite(metadata))
323 }
324
325 pub(crate) fn is_alive(&self) -> bool {
326 self.0.upgrade().is_some()
327 }
328}
329
330// ===== impl State =====
331
332impl State {
333 /// Replaces the current default dispatcher on this thread with the provided
334 /// dispatcher.Any
335 ///
336 /// Dropping the returned `ResetGuard` will reset the default dispatcher to
337 /// the previous value.
338 #[inline]
339 fn set_default(new_dispatch: Dispatch) -> ResetGuard {
340 let prior = CURRENT_STATE
341 .try_with(|state| {
342 state.can_enter.set(true);
343 state.default.replace(new_dispatch)
344 })
345 .ok();
346 ResetGuard(prior)
347 }
348}
349
350// ===== impl ResetGuard =====
351
352impl Drop for ResetGuard {
353 #[inline]
354 fn drop(&mut self) {
355 if let Some(dispatch) = self.0.take() {
356 let _ = CURRENT_STATE.try_with(|state| {
357 *state.default.borrow_mut() = dispatch;
358 });
359 }
360 }
361}
362
363#[cfg(test)]
364mod test {
365 use super::*;
366 use std::sync::atomic::{AtomicUsize, Ordering};
367 use {
368 callsite::Callsite,
369 metadata::{Kind, Level, Metadata},
370 span,
371 subscriber::{Interest, Subscriber},
372 Event,
373 };
374
375 #[test]
376 fn dispatch_is() {
377 let dispatcher = Dispatch::new(NoSubscriber);
378 assert!(dispatcher.is::<NoSubscriber>());
379 }
380
381 #[test]
382 fn dispatch_downcasts() {
383 let dispatcher = Dispatch::new(NoSubscriber);
384 assert!(dispatcher.downcast_ref::<NoSubscriber>().is_some());
385 }
386
387 struct TestCallsite;
388 static TEST_CALLSITE: TestCallsite = TestCallsite;
389 static TEST_META: Metadata<'static> = metadata! {
390 name: "test",
391 target: module_path!(),
392 level: Level::DEBUG,
393 fields: &[],
394 callsite: &TEST_CALLSITE,
395 kind: Kind::EVENT
396 };
397
398 impl Callsite for TestCallsite {
399 fn set_interest(&self, _: Interest) {}
400 fn metadata(&self) -> &Metadata {
401 &TEST_META
402 }
403 }
404
405 #[test]
406 fn events_dont_infinite_loop() {
407 // This test ensures that an event triggered within a subscriber
408 // won't cause an infinite loop of events.
409 struct TestSubscriber;
410 impl Subscriber for TestSubscriber {
411 fn enabled(&self, _: &Metadata) -> bool {
412 true
413 }
414
415 fn new_span(&self, _: &span::Attributes) -> span::Id {
416 span::Id::from_u64(0xAAAA)
417 }
418
419 fn record(&self, _: &span::Id, _: &span::Record) {}
420
421 fn record_follows_from(&self, _: &span::Id, _: &span::Id) {}
422
423 fn event(&self, _: &Event) {
424 static EVENTS: AtomicUsize = AtomicUsize::new(0);
425 assert_eq!(
426 EVENTS.fetch_add(1, Ordering::Relaxed),
427 0,
428 "event method called twice!"
429 );
430 Event::dispatch(&TEST_META, &TEST_META.fields().value_set(&[]))
431 }
432
433 fn enter(&self, _: &span::Id) {}
434
435 fn exit(&self, _: &span::Id) {}
436 }
437
438 with_default(&Dispatch::new(TestSubscriber), || {
439 Event::dispatch(&TEST_META, &TEST_META.fields().value_set(&[]))
440 })
441 }
442
443 #[test]
444 fn spans_dont_infinite_loop() {
445 // This test ensures that a span created within a subscriber
446 // won't cause an infinite loop of new spans.
447
448 fn mk_span() {
449 get_default(|current| {
450 current.new_span(&span::Attributes::new(
451 &TEST_META,
452 &TEST_META.fields().value_set(&[]),
453 ))
454 });
455 }
456
457 struct TestSubscriber;
458 impl Subscriber for TestSubscriber {
459 fn enabled(&self, _: &Metadata) -> bool {
460 true
461 }
462
463 fn new_span(&self, _: &span::Attributes) -> span::Id {
464 static NEW_SPANS: AtomicUsize = AtomicUsize::new(0);
465 assert_eq!(
466 NEW_SPANS.fetch_add(1, Ordering::Relaxed),
467 0,
468 "new_span method called twice!"
469 );
470 mk_span();
471 span::Id::from_u64(0xAAAA)
472 }
473
474 fn record(&self, _: &span::Id, _: &span::Record) {}
475
476 fn record_follows_from(&self, _: &span::Id, _: &span::Id) {}
477
478 fn event(&self, _: &Event) {}
479
480 fn enter(&self, _: &span::Id) {}
481
482 fn exit(&self, _: &span::Id) {}
483 }
484
485 with_default(&Dispatch::new(TestSubscriber), || mk_span())
486 }
487}