diff --git a/tracing-core/src/dispatcher.rs b/tracing-core/src/dispatcher.rs index efda4ebbb9..204c261e41 100644 --- a/tracing-core/src/dispatcher.rs +++ b/tracing-core/src/dispatcher.rs @@ -684,15 +684,10 @@ impl State { let prior = CURRENT_STATE .try_with(|state| { state.can_enter.set(true); - state - .default - .replace(Some(new_dispatch)) - // if the scoped default was not set on this thread, set the - // `prior` default to the global default to populate the - // scoped default when unsetting *this* default - .unwrap_or_else(|| get_global().cloned().unwrap_or_else(Dispatch::none)) + state.default.replace(Some(new_dispatch)) }) - .ok(); + .ok() + .flatten(); EXISTS.store(true, Ordering::Release); DefaultGuard(prior) } @@ -734,15 +729,13 @@ impl<'a> Drop for Entered<'a> { impl Drop for DefaultGuard { #[inline] fn drop(&mut self) { - if let Some(dispatch) = self.0.take() { - // Replace the dispatcher and then drop the old one outside - // of the thread-local context. Dropping the dispatch may - // lead to the drop of a subscriber which, in the process, - // could then also attempt to access the same thread local - // state -- causing a clash. - let prev = CURRENT_STATE.try_with(|state| state.default.replace(Some(dispatch))); - drop(prev) - } + // Replace the dispatcher and then drop the old one outside + // of the thread-local context. Dropping the dispatch may + // lead to the drop of a subscriber which, in the process, + // could then also attempt to access the same thread local + // state -- causing a clash. + let prev = CURRENT_STATE.try_with(|state| state.default.replace(self.0.take())); + drop(prev) } } diff --git a/tracing/tests/scoped_clobbers_default.rs b/tracing/tests/scoped_clobbers_default.rs new file mode 100644 index 0000000000..362d34a82c --- /dev/null +++ b/tracing/tests/scoped_clobbers_default.rs @@ -0,0 +1,35 @@ +#![cfg(feature = "std")] +use tracing_mock::*; + +#[test] +fn scoped_clobbers_global() { + // Reproduces https://github.com/tokio-rs/tracing/issues/2050 + + let (scoped, scoped_handle) = subscriber::mock() + .event(event::msg("before global")) + .event(event::msg("before drop")) + .done() + .run_with_handle(); + + let (global, global_handle) = subscriber::mock() + .event(event::msg("after drop")) + .done() + .run_with_handle(); + + // Set a scoped default subscriber, returning a guard. + let guard = tracing::subscriber::set_default(scoped); + tracing::info!("before global"); + + // Now, set the global default. + tracing::subscriber::set_global_default(global) + .expect("global default should not already be set"); + // This event should still be collected by the scoped default. + tracing::info!("before drop"); + + // Drop the guard. Now, the global default subscriber should be used. + drop(guard); + tracing::info!("after drop"); + + scoped_handle.assert_finished(); + global_handle.assert_finished(); +}