tracing_subscriber/registry/
sharded.rs

1use sharded_slab::{pool::Ref, Clear, Pool};
2use thread_local::ThreadLocal;
3
4use super::stack::SpanStack;
5use crate::{
6    filter::{FilterId, FilterMap, FilterState},
7    registry::{
8        extensions::{Extensions, ExtensionsInner, ExtensionsMut},
9        LookupSpan, SpanData,
10    },
11    sync::RwLock,
12};
13use core::{
14    cell::{self, Cell, RefCell},
15    sync::atomic::{fence, AtomicUsize, Ordering},
16};
17use std::thread_local;
18use tracing_core::{
19    dispatcher::{self, Dispatch},
20    span::{self, Current, Id},
21    Event, Interest, Metadata, Subscriber,
22};
23
24/// A shared, reusable store for spans.
25///
26/// A `Registry` is a [`Subscriber`] around which multiple [`Layer`]s
27/// implementing various behaviors may be [added]. Unlike other types
28/// implementing `Subscriber`, `Registry` does not actually record traces itself:
29/// instead, it collects and stores span data that is exposed to any [`Layer`]s
30/// wrapping it through implementations of the [`LookupSpan`] trait.
31/// The `Registry` is responsible for storing span metadata, recording
32/// relationships between spans, and tracking which spans are active and which
33/// are closed. In addition, it provides a mechanism for [`Layer`]s to store
34/// user-defined per-span data, called [extensions], in the registry. This
35/// allows [`Layer`]-specific data to benefit from the `Registry`'s
36/// high-performance concurrent storage.
37///
38/// This registry is implemented using a [lock-free sharded slab][slab], and is
39/// highly optimized for concurrent access.
40///
41/// # Span ID Generation
42///
43/// Span IDs are not globally unique, but the registry ensures that
44/// no two currently active spans have the same ID within a process.
45///
46/// One of the primary responsibilities of the registry is to generate [span
47/// IDs]. Therefore, it's important for other code that interacts with the
48/// registry, such as [`Layer`]s, to understand the guarantees of the
49/// span IDs that are generated.
50///
51/// The registry's span IDs are guaranteed to be unique **at a given point
52/// in time**. This means that an active span will never be assigned the
53/// same ID as another **currently active** span. However, the registry
54/// **will** eventually reuse the IDs of [closed] spans, although an ID
55/// will never be reassigned immediately after a span has closed.
56///
57/// Spans are not [considered closed] by the `Registry` until *every*
58/// [`Span`] reference with that ID has been dropped.
59///
60/// Thus: span IDs generated by the registry should be considered unique
61/// only at a given point in time, and only relative to other spans
62/// generated by the same process. Two spans with the same ID will not exist
63/// in the same process concurrently. However, if historical span data is
64/// being stored, the same ID may occur for multiple spans times in that
65/// data. If spans must be uniquely identified in historical data, the user
66/// code storing this data must assign its own unique identifiers to those
67/// spans. A counter is generally sufficient for this.
68///
69/// Similarly, span IDs generated by the registry are not unique outside of
70/// a given process. Distributed tracing systems may require identifiers
71/// that are unique across multiple processes on multiple machines (for
72/// example, [OpenTelemetry's `SpanId`s and `TraceId`s][ot]). `tracing` span
73/// IDs generated by the registry should **not** be used for this purpose.
74/// Instead, code which integrates with a distributed tracing system should
75/// generate and propagate its own IDs according to the rules specified by
76/// the distributed tracing system. These IDs can be associated with
77/// `tracing` spans using [fields] and/or [stored span data].
78///
79/// [span IDs]: tracing_core::span::Id
80/// [slab]: sharded_slab
81/// [`Layer`]: crate::Layer
82/// [added]: crate::layer::Layer#composing-layers
83/// [extensions]: super::Extensions
84/// [closed]: https://docs.rs/tracing/latest/tracing/span/index.html#closing-spans
85/// [considered closed]: tracing_core::subscriber::Subscriber::try_close()
86/// [`Span`]: https://docs.rs/tracing/latest/tracing/span/struct.Span.html
87/// [ot]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#spancontext
88/// [fields]: tracing_core::field
89/// [stored span data]: crate::registry::SpanData::extensions_mut
90#[cfg(feature = "registry")]
91#[cfg_attr(docsrs, doc(cfg(all(feature = "registry", feature = "std"))))]
92#[derive(Debug)]
93pub struct Registry {
94    spans: Pool<DataInner>,
95    current_spans: ThreadLocal<RefCell<SpanStack>>,
96    next_filter_id: u8,
97}
98
99/// Span data stored in a [`Registry`].
100///
101/// The registry stores well-known data defined by tracing: span relationships,
102/// metadata and reference counts. Additional user-defined data provided by
103/// [`Layer`s], such as formatted fields, metrics, or distributed traces should
104/// be stored in the [extensions] typemap.
105///
106/// [`Layer`s]: crate::layer::Layer
107/// [extensions]: Extensions
108#[cfg(feature = "registry")]
109#[cfg_attr(docsrs, doc(cfg(all(feature = "registry", feature = "std"))))]
110#[derive(Debug)]
111pub struct Data<'a> {
112    /// Immutable reference to the pooled `DataInner` entry.
113    inner: Ref<'a, DataInner>,
114}
115
116/// Stored data associated with a span.
117///
118/// This type is pooled using [`sharded_slab::Pool`]; when a span is
119/// dropped, the `DataInner` entry at that span's slab index is cleared
120/// in place and reused by a future span. Thus, the `Default` and
121/// [`sharded_slab::Clear`] implementations for this type are
122/// load-bearing.
123#[derive(Debug)]
124struct DataInner {
125    filter_map: FilterMap,
126    metadata: &'static Metadata<'static>,
127    parent: Option<Id>,
128    ref_count: AtomicUsize,
129    // The span's `Extensions` typemap. Allocations for the `HashMap` backing
130    // this are pooled and reused in place.
131    pub(crate) extensions: RwLock<ExtensionsInner>,
132}
133
134// === impl Registry ===
135
136impl Default for Registry {
137    fn default() -> Self {
138        Self {
139            spans: Pool::new(),
140            current_spans: ThreadLocal::new(),
141            next_filter_id: 0,
142        }
143    }
144}
145
146#[inline]
147fn idx_to_id(idx: usize) -> Id {
148    Id::from_u64(idx as u64 + 1)
149}
150
151#[inline]
152fn id_to_idx(id: &Id) -> usize {
153    id.into_u64() as usize - 1
154}
155
156/// A guard that tracks how many [`Registry`]-backed `Layer`s have
157/// processed an `on_close` event.
158///
159/// This is needed to enable a [`Registry`]-backed Layer to access span
160/// data after the `Layer` has recieved the `on_close` callback.
161///
162/// Once all `Layer`s have processed this event, the [`Registry`] knows
163/// that is able to safely remove the span tracked by `id`. `CloseGuard`
164/// accomplishes this through a two-step process:
165/// 1. Whenever a [`Registry`]-backed `Layer::on_close` method is
166///    called, `Registry::start_close` is closed.
167///    `Registry::start_close` increments a thread-local `CLOSE_COUNT`
168///    by 1 and returns a `CloseGuard`.
169/// 2. The `CloseGuard` is dropped at the end of `Layer::on_close`. On
170///    drop, `CloseGuard` checks thread-local `CLOSE_COUNT`. If
171///    `CLOSE_COUNT` is 0, the `CloseGuard` removes the span with the
172///    `id` from the registry, as all `Layers` that might have seen the
173///    `on_close` notification have processed it. If `CLOSE_COUNT` is
174///    greater than 0, `CloseGuard` decrements the counter by one and
175///    _does not_ remove the span from the [`Registry`].
176///
177pub(crate) struct CloseGuard<'a> {
178    id: Id,
179    registry: &'a Registry,
180    is_closing: bool,
181}
182
183impl Registry {
184    fn get(&self, id: &Id) -> Option<Ref<'_, DataInner>> {
185        self.spans.get(id_to_idx(id))
186    }
187
188    /// Returns a guard which tracks how many `Layer`s have
189    /// processed an `on_close` notification via the `CLOSE_COUNT` thread-local.
190    /// For additional details, see [`CloseGuard`].
191    ///
192    pub(crate) fn start_close(&self, id: Id) -> CloseGuard<'_> {
193        CLOSE_COUNT.with(|count| {
194            let c = count.get();
195            count.set(c + 1);
196        });
197        CloseGuard {
198            id,
199            registry: self,
200            is_closing: false,
201        }
202    }
203
204    pub(crate) fn has_per_layer_filters(&self) -> bool {
205        self.next_filter_id > 0
206    }
207
208    pub(crate) fn span_stack(&self) -> cell::Ref<'_, SpanStack> {
209        self.current_spans.get_or_default().borrow()
210    }
211}
212
213thread_local! {
214    /// `CLOSE_COUNT` is the thread-local counter used by `CloseGuard` to
215    /// track how many layers have processed the close.
216    /// For additional details, see [`CloseGuard`].
217    ///
218    static CLOSE_COUNT: Cell<usize> = const { Cell::new(0) };
219}
220
221impl Subscriber for Registry {
222    fn register_callsite(&self, _: &'static Metadata<'static>) -> Interest {
223        if self.has_per_layer_filters() {
224            return FilterState::take_interest().unwrap_or_else(Interest::always);
225        }
226
227        Interest::always()
228    }
229
230    fn enabled(&self, _: &Metadata<'_>) -> bool {
231        if self.has_per_layer_filters() {
232            return FilterState::event_enabled();
233        }
234        true
235    }
236
237    #[inline]
238    fn new_span(&self, attrs: &span::Attributes<'_>) -> span::Id {
239        let parent = if attrs.is_root() {
240            None
241        } else if attrs.is_contextual() {
242            self.current_span().id().map(|id| self.clone_span(id))
243        } else {
244            attrs.parent().map(|id| self.clone_span(id))
245        };
246
247        let id = self
248            .spans
249            // Check out a `DataInner` entry from the pool for the new span. If
250            // there are free entries already allocated in the pool, this will
251            // preferentially reuse one; otherwise, a new `DataInner` is
252            // allocated and added to the pool.
253            .create_with(|data| {
254                data.metadata = attrs.metadata();
255                data.parent = parent;
256                data.filter_map = crate::filter::FILTERING.with(|filtering| filtering.filter_map());
257                #[cfg(debug_assertions)]
258                {
259                    if data.filter_map != FilterMap::new() {
260                        debug_assert!(self.has_per_layer_filters());
261                    }
262                }
263
264                let refs = data.ref_count.get_mut();
265                debug_assert_eq!(*refs, 0);
266                *refs = 1;
267            })
268            .expect("Unable to allocate another span");
269        idx_to_id(id)
270    }
271
272    /// This is intentionally not implemented, as recording fields
273    /// on a span is the responsibility of layers atop of this registry.
274    #[inline]
275    fn record(&self, _: &span::Id, _: &span::Record<'_>) {}
276
277    fn record_follows_from(&self, _span: &span::Id, _follows: &span::Id) {}
278
279    fn event_enabled(&self, _event: &Event<'_>) -> bool {
280        if self.has_per_layer_filters() {
281            return FilterState::event_enabled();
282        }
283        true
284    }
285
286    /// This is intentionally not implemented, as recording events
287    /// is the responsibility of layers atop of this registry.
288    fn event(&self, _: &Event<'_>) {}
289
290    fn enter(&self, id: &span::Id) {
291        self.current_spans
292            .get_or_default()
293            .borrow_mut()
294            .push(id.clone());
295    }
296
297    fn exit(&self, id: &span::Id) {
298        if let Some(spans) = self.current_spans.get() {
299            spans.borrow_mut().pop(id);
300        }
301    }
302
303    fn clone_span(&self, id: &span::Id) -> span::Id {
304        let span = self
305            .get(id)
306            .unwrap_or_else(|| panic!(
307                "tried to clone {:?}, but no span exists with that ID\n\
308                This may be caused by consuming a parent span (`parent: span`) rather than borrowing it (`parent: &span`).",
309                id,
310            ));
311        // Like `std::sync::Arc`, adds to the ref count (on clone) don't require
312        // a strong ordering; if we call` clone_span`, the reference count must
313        // always at least 1. The only synchronization necessary is between
314        // calls to `try_close`: we have to ensure that all threads have
315        // dropped their refs to the span before the span is closed.
316        let refs = span.ref_count.fetch_add(1, Ordering::Relaxed);
317        assert_ne!(
318            refs, 0,
319            "tried to clone a span ({:?}) that already closed",
320            id
321        );
322        id.clone()
323    }
324
325    fn current_span(&self) -> Current {
326        self.current_spans
327            .get()
328            .and_then(|spans| {
329                let spans = spans.borrow();
330                let id = spans.current()?;
331                let span = self.get(id)?;
332                Some(Current::new(id.clone(), span.metadata))
333            })
334            .unwrap_or_else(Current::none)
335    }
336
337    /// Decrements the reference count of the span with the given `id`, and
338    /// removes the span if it is zero.
339    ///
340    /// The allocated span slot will be reused when a new span is created.
341    fn try_close(&self, id: span::Id) -> bool {
342        let span = match self.get(&id) {
343            Some(span) => span,
344            None if std::thread::panicking() => return false,
345            None => panic!("tried to drop a ref to {:?}, but no such span exists!", id),
346        };
347
348        let refs = span.ref_count.fetch_sub(1, Ordering::Release);
349        if !std::thread::panicking() {
350            assert!(refs < usize::MAX, "reference count overflow!");
351        }
352        if refs > 1 {
353            return false;
354        }
355
356        // Synchronize if we are actually removing the span (stolen
357        // from std::Arc); this ensures that all other `try_close` calls on
358        // other threads happen-before we actually remove the span.
359        fence(Ordering::Acquire);
360        true
361    }
362}
363
364impl<'a> LookupSpan<'a> for Registry {
365    type Data = Data<'a>;
366
367    fn span_data(&'a self, id: &Id) -> Option<Self::Data> {
368        let inner = self.get(id)?;
369        Some(Data { inner })
370    }
371
372    fn register_filter(&mut self) -> FilterId {
373        let id = FilterId::new(self.next_filter_id);
374        self.next_filter_id += 1;
375        id
376    }
377}
378
379// === impl CloseGuard ===
380
381impl CloseGuard<'_> {
382    pub(crate) fn set_closing(&mut self) {
383        self.is_closing = true;
384    }
385}
386
387impl Drop for CloseGuard<'_> {
388    fn drop(&mut self) {
389        // If this returns with an error, we are already panicking. At
390        // this point, there's nothing we can really do to recover
391        // except by avoiding a double-panic.
392        let _ = CLOSE_COUNT.try_with(|count| {
393            let c = count.get();
394            // Decrement the count to indicate that _this_ guard's
395            // `on_close` callback has completed.
396            //
397            // Note that we *must* do this before we actually remove the span
398            // from the registry, since dropping the `DataInner` may trigger a
399            // new close, if this span is the last reference to a parent span.
400            count.set(c - 1);
401
402            // If the current close count is 1, this stack frame is the last
403            // `on_close` call. If the span is closing, it's okay to remove the
404            // span.
405            if c == 1 && self.is_closing {
406                self.registry.spans.clear(id_to_idx(&self.id));
407            }
408        });
409    }
410}
411
412// === impl Data ===
413
414impl<'a> SpanData<'a> for Data<'a> {
415    fn id(&self) -> Id {
416        idx_to_id(self.inner.key())
417    }
418
419    fn metadata(&self) -> &'static Metadata<'static> {
420        self.inner.metadata
421    }
422
423    fn parent(&self) -> Option<&Id> {
424        self.inner.parent.as_ref()
425    }
426
427    fn extensions(&self) -> Extensions<'_> {
428        Extensions::new(self.inner.extensions.read().expect("Mutex poisoned"))
429    }
430
431    fn extensions_mut(&self) -> ExtensionsMut<'_> {
432        ExtensionsMut::new(self.inner.extensions.write().expect("Mutex poisoned"))
433    }
434
435    #[inline]
436    fn is_enabled_for(&self, filter: FilterId) -> bool {
437        self.inner.filter_map.is_enabled(filter)
438    }
439}
440
441// === impl DataInner ===
442
443impl Default for DataInner {
444    fn default() -> Self {
445        // Since `DataInner` owns a `&'static Callsite` pointer, we need
446        // something to use as the initial default value for that callsite.
447        // Since we can't access a `DataInner` until it has had actual span data
448        // inserted into it, the null metadata will never actually be accessed.
449        struct NullCallsite;
450        impl tracing_core::callsite::Callsite for NullCallsite {
451            fn set_interest(&self, _: Interest) {
452                unreachable!(
453                    "/!\\ Tried to register the null callsite /!\\\n \
454                    This should never have happened and is definitely a bug. \
455                    A `tracing` bug report would be appreciated."
456                )
457            }
458
459            fn metadata(&self) -> &Metadata<'_> {
460                unreachable!(
461                    "/!\\ Tried to access the null callsite's metadata /!\\\n \
462                    This should never have happened and is definitely a bug. \
463                    A `tracing` bug report would be appreciated."
464                )
465            }
466        }
467
468        static NULL_CALLSITE: NullCallsite = NullCallsite;
469        static NULL_METADATA: Metadata<'static> = tracing_core::metadata! {
470            name: "",
471            target: "",
472            level: tracing_core::Level::TRACE,
473            fields: &[],
474            callsite: &NULL_CALLSITE,
475            kind: tracing_core::metadata::Kind::SPAN,
476        };
477
478        Self {
479            filter_map: FilterMap::new(),
480            metadata: &NULL_METADATA,
481            parent: None,
482            ref_count: AtomicUsize::new(0),
483            extensions: RwLock::new(ExtensionsInner::new()),
484        }
485    }
486}
487
488impl Clear for DataInner {
489    /// Clears the span's data in place, dropping the parent's reference count.
490    fn clear(&mut self) {
491        // A span is not considered closed until all of its children have closed.
492        // Therefore, each span's `DataInner` holds a "reference" to the parent
493        // span, keeping the parent span open until all its children have closed.
494        // When we close a span, we must then decrement the parent's ref count
495        // (potentially, allowing it to close, if this child is the last reference
496        // to that span).
497        // We have to actually unpack the option inside the `get_default`
498        // closure, since it is a `FnMut`, but testing that there _is_ a value
499        // here lets us avoid the thread-local access if we don't need the
500        // dispatcher at all.
501        if self.parent.is_some() {
502            // Note that --- because `Layered::try_close` works by calling
503            // `try_close` on the inner subscriber and using the return value to
504            // determine whether to call the `Layer`'s `on_close` callback ---
505            // we must call `try_close` on the entire subscriber stack, rather
506            // than just on the registry. If the registry called `try_close` on
507            // itself directly, the layers wouldn't see the close notification.
508            let subscriber = dispatcher::get_default(Dispatch::clone);
509            if let Some(parent) = self.parent.take() {
510                let _ = subscriber.try_close(parent);
511            }
512        }
513
514        // Clear (but do not deallocate!) the pooled `HashMap` for the span's extensions.
515        self.extensions
516            .get_mut()
517            .unwrap_or_else(|l| {
518                // This function can be called in a `Drop` impl, such as while
519                // panicking, so ignore lock poisoning.
520                l.into_inner()
521            })
522            .clear();
523
524        self.filter_map = FilterMap::new();
525    }
526}
527
528#[cfg(test)]
529mod tests {
530    use super::*;
531    use crate::{layer::Context, registry::LookupSpan, Layer};
532    use std::{
533        collections::HashMap,
534        dbg, println,
535        sync::{Arc, Mutex, Weak},
536        vec::Vec,
537    };
538    use tracing::{self, subscriber::with_default};
539    use tracing_core::{
540        dispatcher,
541        span::{Attributes, Id},
542        Subscriber,
543    };
544
545    struct AssertionLayer;
546    impl<S> Layer<S> for AssertionLayer
547    where
548        S: Subscriber + for<'a> LookupSpan<'a>,
549    {
550        fn on_close(&self, id: Id, ctx: Context<'_, S>) {
551            dbg!(format_args!("closing {:?}", id));
552            assert!(&ctx.span(&id).is_some());
553        }
554    }
555
556    #[test]
557    fn single_layer_can_access_closed_span() {
558        let subscriber = AssertionLayer.with_subscriber(Registry::default());
559
560        with_default(subscriber, || {
561            let span = tracing::debug_span!("span");
562            drop(span);
563        });
564    }
565
566    #[test]
567    fn multiple_layers_can_access_closed_span() {
568        let subscriber = AssertionLayer
569            .and_then(AssertionLayer)
570            .with_subscriber(Registry::default());
571
572        with_default(subscriber, || {
573            let span = tracing::debug_span!("span");
574            drop(span);
575        });
576    }
577
578    struct CloseLayer {
579        inner: Arc<Mutex<CloseState>>,
580    }
581
582    struct CloseHandle {
583        state: Arc<Mutex<CloseState>>,
584    }
585
586    #[derive(Default)]
587    struct CloseState {
588        open: HashMap<&'static str, Weak<()>>,
589        closed: Vec<(&'static str, Weak<()>)>,
590    }
591
592    #[allow(dead_code)] // Field is exercised via checking `Arc::downgrade()`
593    struct SetRemoved(Arc<()>);
594
595    impl<S> Layer<S> for CloseLayer
596    where
597        S: Subscriber + for<'a> LookupSpan<'a>,
598    {
599        fn on_new_span(&self, _: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
600            let span = ctx.span(id).expect("Missing span; this is a bug");
601            let mut lock = self.inner.lock().unwrap();
602            let is_removed = Arc::new(());
603            assert!(
604                lock.open
605                    .insert(span.name(), Arc::downgrade(&is_removed))
606                    .is_none(),
607                "test layer saw multiple spans with the same name, the test is probably messed up"
608            );
609            let mut extensions = span.extensions_mut();
610            extensions.insert(SetRemoved(is_removed));
611        }
612
613        fn on_close(&self, id: Id, ctx: Context<'_, S>) {
614            let span = if let Some(span) = ctx.span(&id) {
615                span
616            } else {
617                println!(
618                    "span {:?} did not exist in `on_close`, are we panicking?",
619                    id
620                );
621                return;
622            };
623            let name = span.name();
624            println!("close {} ({:?})", name, id);
625            if let Ok(mut lock) = self.inner.lock() {
626                if let Some(is_removed) = lock.open.remove(name) {
627                    assert!(is_removed.upgrade().is_some());
628                    lock.closed.push((name, is_removed));
629                }
630            }
631        }
632    }
633
634    impl CloseLayer {
635        fn new() -> (Self, CloseHandle) {
636            let state = Arc::new(Mutex::new(CloseState::default()));
637            (
638                Self {
639                    inner: state.clone(),
640                },
641                CloseHandle { state },
642            )
643        }
644    }
645
646    impl CloseState {
647        fn is_open(&self, span: &str) -> bool {
648            self.open.contains_key(span)
649        }
650
651        fn is_closed(&self, span: &str) -> bool {
652            self.closed.iter().any(|(name, _)| name == &span)
653        }
654    }
655
656    impl CloseHandle {
657        fn assert_closed(&self, span: &str) {
658            let lock = self.state.lock().unwrap();
659            assert!(
660                lock.is_closed(span),
661                "expected {} to be closed{}",
662                span,
663                if lock.is_open(span) {
664                    " (it was still open)"
665                } else {
666                    ", but it never existed (is there a problem with the test?)"
667                }
668            )
669        }
670
671        fn assert_open(&self, span: &str) {
672            let lock = self.state.lock().unwrap();
673            assert!(
674                lock.is_open(span),
675                "expected {} to be open{}",
676                span,
677                if lock.is_closed(span) {
678                    " (it was still open)"
679                } else {
680                    ", but it never existed (is there a problem with the test?)"
681                }
682            )
683        }
684
685        fn assert_removed(&self, span: &str) {
686            let lock = self.state.lock().unwrap();
687            let is_removed = match lock.closed.iter().find(|(name, _)| name == &span) {
688                Some((_, is_removed)) => is_removed,
689                None => panic!(
690                    "expected {} to be removed from the registry, but it was not closed {}",
691                    span,
692                    if lock.is_closed(span) {
693                        " (it was still open)"
694                    } else {
695                        ", but it never existed (is there a problem with the test?)"
696                    }
697                ),
698            };
699            assert!(
700                is_removed.upgrade().is_none(),
701                "expected {} to have been removed from the registry",
702                span
703            )
704        }
705
706        fn assert_not_removed(&self, span: &str) {
707            let lock = self.state.lock().unwrap();
708            let is_removed = match lock.closed.iter().find(|(name, _)| name == &span) {
709                Some((_, is_removed)) => is_removed,
710                None if lock.is_open(span) => return,
711                None => unreachable!(),
712            };
713            assert!(
714                is_removed.upgrade().is_some(),
715                "expected {} to have been removed from the registry",
716                span
717            )
718        }
719
720        #[allow(unused)] // may want this for future tests
721        fn assert_last_closed(&self, span: Option<&str>) {
722            let lock = self.state.lock().unwrap();
723            let last = lock.closed.last().map(|(span, _)| span);
724            assert_eq!(
725                last,
726                span.as_ref(),
727                "expected {:?} to have closed last",
728                span
729            );
730        }
731
732        fn assert_closed_in_order(&self, order: impl AsRef<[&'static str]>) {
733            let lock = self.state.lock().unwrap();
734            let order = order.as_ref();
735            for (i, name) in order.iter().enumerate() {
736                assert_eq!(
737                    lock.closed.get(i).map(|(span, _)| span),
738                    Some(name),
739                    "expected close order: {:?}, actual: {:?}",
740                    order,
741                    lock.closed.iter().map(|(name, _)| name).collect::<Vec<_>>()
742                );
743            }
744        }
745    }
746
747    #[test]
748    fn spans_are_removed_from_registry() {
749        let (close_layer, state) = CloseLayer::new();
750        let subscriber = AssertionLayer
751            .and_then(close_layer)
752            .with_subscriber(Registry::default());
753
754        // Create a `Dispatch` (which is internally reference counted) so that
755        // the subscriber lives to the end of the test. Otherwise, if we just
756        // passed the subscriber itself to `with_default`, we could see the span
757        // be dropped when the subscriber itself is dropped, destroying the
758        // registry.
759        let dispatch = dispatcher::Dispatch::new(subscriber);
760
761        dispatcher::with_default(&dispatch, || {
762            let span = tracing::debug_span!("span1");
763            drop(span);
764            let span = tracing::info_span!("span2");
765            drop(span);
766        });
767
768        state.assert_removed("span1");
769        state.assert_removed("span2");
770
771        // Ensure the registry itself outlives the span.
772        drop(dispatch);
773    }
774
775    #[test]
776    fn spans_are_only_closed_when_the_last_ref_drops() {
777        let (close_layer, state) = CloseLayer::new();
778        let subscriber = AssertionLayer
779            .and_then(close_layer)
780            .with_subscriber(Registry::default());
781
782        // Create a `Dispatch` (which is internally reference counted) so that
783        // the subscriber lives to the end of the test. Otherwise, if we just
784        // passed the subscriber itself to `with_default`, we could see the span
785        // be dropped when the subscriber itself is dropped, destroying the
786        // registry.
787        let dispatch = dispatcher::Dispatch::new(subscriber);
788
789        let span2 = dispatcher::with_default(&dispatch, || {
790            let span = tracing::debug_span!("span1");
791            drop(span);
792            let span2 = tracing::info_span!("span2");
793            let span2_clone = span2.clone();
794            drop(span2);
795            span2_clone
796        });
797
798        state.assert_removed("span1");
799        state.assert_not_removed("span2");
800
801        drop(span2);
802        state.assert_removed("span1");
803
804        // Ensure the registry itself outlives the span.
805        drop(dispatch);
806    }
807
808    #[test]
809    fn span_enter_guards_are_dropped_out_of_order() {
810        let (close_layer, state) = CloseLayer::new();
811        let subscriber = AssertionLayer
812            .and_then(close_layer)
813            .with_subscriber(Registry::default());
814
815        // Create a `Dispatch` (which is internally reference counted) so that
816        // the subscriber lives to the end of the test. Otherwise, if we just
817        // passed the subscriber itself to `with_default`, we could see the span
818        // be dropped when the subscriber itself is dropped, destroying the
819        // registry.
820        let dispatch = dispatcher::Dispatch::new(subscriber);
821
822        dispatcher::with_default(&dispatch, || {
823            let span1 = tracing::debug_span!("span1");
824            let span2 = tracing::info_span!("span2");
825
826            let enter1 = span1.enter();
827            let enter2 = span2.enter();
828
829            drop(enter1);
830            drop(span1);
831
832            state.assert_removed("span1");
833            state.assert_not_removed("span2");
834
835            drop(enter2);
836            state.assert_not_removed("span2");
837
838            drop(span2);
839            state.assert_removed("span1");
840            state.assert_removed("span2");
841        });
842    }
843
844    #[test]
845    fn child_closes_parent() {
846        // This test asserts that if a parent span's handle is dropped before
847        // a child span's handle, the parent will remain open until child
848        // closes, and will then be closed.
849
850        let (close_layer, state) = CloseLayer::new();
851        let subscriber = close_layer.with_subscriber(Registry::default());
852
853        let dispatch = dispatcher::Dispatch::new(subscriber);
854
855        dispatcher::with_default(&dispatch, || {
856            let span1 = tracing::info_span!("parent");
857            let span2 = tracing::info_span!(parent: &span1, "child");
858
859            state.assert_open("parent");
860            state.assert_open("child");
861
862            drop(span1);
863            state.assert_open("parent");
864            state.assert_open("child");
865
866            drop(span2);
867            state.assert_closed("parent");
868            state.assert_closed("child");
869        });
870    }
871
872    #[test]
873    fn child_closes_grandparent() {
874        // This test asserts that, when a span is kept open by a child which
875        // is *itself* kept open by a child, closing the grandchild will close
876        // both the parent *and* the grandparent.
877        let (close_layer, state) = CloseLayer::new();
878        let subscriber = close_layer.with_subscriber(Registry::default());
879
880        let dispatch = dispatcher::Dispatch::new(subscriber);
881
882        dispatcher::with_default(&dispatch, || {
883            let span1 = tracing::info_span!("grandparent");
884            let span2 = tracing::info_span!(parent: &span1, "parent");
885            let span3 = tracing::info_span!(parent: &span2, "child");
886
887            state.assert_open("grandparent");
888            state.assert_open("parent");
889            state.assert_open("child");
890
891            drop(span1);
892            drop(span2);
893            state.assert_open("grandparent");
894            state.assert_open("parent");
895            state.assert_open("child");
896
897            drop(span3);
898
899            state.assert_closed_in_order(["child", "parent", "grandparent"]);
900        });
901    }
902}