diff --git a/tracing-subscriber/Cargo.toml b/tracing-subscriber/Cargo.toml index 807880b8cd..5822ddd922 100644 --- a/tracing-subscriber/Cargo.toml +++ b/tracing-subscriber/Cargo.toml @@ -31,6 +31,9 @@ env-filter = ["matchers", "regex", "once_cell", "tracing", "std", "thread_local" fmt = ["registry", "std"] ansi = ["fmt", "nu-ansi-term"] registry = ["sharded-slab", "thread_local", "std"] +# Raises the sharded-slab MAX_THREADS limit from 4 096 to 131 072. +# Enable on high-core nodes where many native threads are spawned. +large-thread-count = [] json = ["tracing-serde", "serde", "serde_json"] valuable = ["tracing-core/valuable", "valuable_crate", "valuable-serde", "tracing-serde/valuable"] # Enables support for local time when using the `time` crate timestamp diff --git a/tracing-subscriber/src/registry/sharded.rs b/tracing-subscriber/src/registry/sharded.rs index 544a5dc344..14549ee19c 100644 --- a/tracing-subscriber/src/registry/sharded.rs +++ b/tracing-subscriber/src/registry/sharded.rs @@ -1,4 +1,20 @@ -use sharded_slab::{pool::Ref, Clear, Pool}; +use sharded_slab::{pool::Ref, Clear, Config, Pool}; + +/// Custom [`sharded_slab::Config`] for the span registry pool. +/// +/// When the `large-thread-count` feature is enabled, `MAX_THREADS` is raised +/// from the upstream default of 4 096 to 131 072, preventing panics on +/// high-core machines where large numbers of native threads are spawned. +/// When the feature is disabled the trait default (4 096) is used unchanged. +#[derive(Debug)] +struct SlabConfig; + +impl Config for SlabConfig { + /// 131 072 threads = 2^17. Only active with the `large-thread-count` + /// feature; otherwise falls back to the trait default of 4 096. + #[cfg(feature = "large-thread-count")] + const MAX_THREADS: usize = 131_072; +} use thread_local::ThreadLocal; use super::stack::SpanStack; @@ -90,7 +106,7 @@ use tracing_core::{ #[cfg_attr(docsrs, doc(cfg(all(feature = "registry", feature = "std"))))] #[derive(Debug)] pub struct Registry { - spans: Pool, + spans: Pool, current_spans: ThreadLocal>, next_filter_id: u8, } @@ -109,7 +125,7 @@ pub struct Registry { #[derive(Debug)] pub struct Data<'a> { /// Immutable reference to the pooled `DataInner` entry. - inner: Ref<'a, DataInner>, + inner: Ref<'a, DataInner, SlabConfig>, } /// Stored data associated with a span. @@ -135,7 +151,7 @@ struct DataInner { impl Default for Registry { fn default() -> Self { Self { - spans: Pool::new(), + spans: Pool::new_with_config::(), current_spans: ThreadLocal::new(), next_filter_id: 0, } @@ -180,7 +196,7 @@ pub(crate) struct CloseGuard<'a> { } impl Registry { - fn get(&self, id: &Id) -> Option> { + fn get(&self, id: &Id) -> Option> { self.spans.get(id_to_idx(id)) } @@ -905,4 +921,13 @@ mod tests { state.assert_closed_in_order(["child", "parent", "grandparent"]); }); } + + #[cfg(feature = "large-thread-count")] + #[test] + fn large_thread_count_raises_max_threads() { + assert_eq!(SlabConfig::MAX_THREADS, 131_072); + // Confirm the registry pool is parameterised on SlabConfig at the type + // level — this is a compile-time check dressed as a runtime test. + let _: &Pool = &Pool::new_with_config::(); + } }