diff --git a/src/core/error.rs b/src/core/error.rs
index 26bac6e06004609bd5cea8c38f175430fe2980a2..8567f30361862a47bb3d96c861d3c85384c25c70 100644
--- a/src/core/error.rs
+++ b/src/core/error.rs
@@ -47,6 +47,8 @@ pub enum Error {
 	Regex(#[from] regex::Error),
 	#[error("Tracing filter error: {0}")]
 	TracingFilter(#[from] tracing_subscriber::filter::ParseError),
+	#[error("Tracing reload error: {0}")]
+	TracingReload(#[from] tracing_subscriber::reload::Error),
 	#[error("Image error: {0}")]
 	Image(#[from] image::error::ImageError),
 	#[error("Request error: {0}")]
diff --git a/src/core/log/reload.rs b/src/core/log/reload.rs
index 7646254edb996666121e41241067de938517c900..cfed785d8cf56824dafe11adea1846c59a1a7a1e 100644
--- a/src/core/log/reload.rs
+++ b/src/core/log/reload.rs
@@ -1,7 +1,12 @@
-use std::sync::Arc;
+use std::{
+	collections::HashMap,
+	sync::{Arc, Mutex},
+};
 
 use tracing_subscriber::{reload, EnvFilter};
 
+use crate::{error, Result};
+
 /// We need to store a reload::Handle value, but can't name it's type explicitly
 /// because the S type parameter depends on the subscriber's previous layers. In
 /// our case, this includes unnameable 'impl Trait' types.
@@ -24,32 +29,39 @@ impl<L, S> ReloadHandle<L> for reload::Handle<L, S> {
 	fn reload(&self, new_value: L) -> Result<(), reload::Error> { Self::reload(self, new_value) }
 }
 
-struct LogLevelReloadHandlesInner {
-	handles: Vec<Box<dyn ReloadHandle<EnvFilter> + Send + Sync>>,
-}
-
-/// Wrapper to allow reloading the filter on several several
-/// [`tracing_subscriber::reload::Handle`]s at once, with the same value.
 #[derive(Clone)]
 pub struct LogLevelReloadHandles {
-	inner: Arc<LogLevelReloadHandlesInner>,
+	handles: Arc<Mutex<HandleMap>>,
 }
 
+type HandleMap = HashMap<String, Handle>;
+type Handle = Box<dyn ReloadHandle<EnvFilter> + Send + Sync>;
+
 impl LogLevelReloadHandles {
-	#[must_use]
-	pub fn new(handles: Vec<Box<dyn ReloadHandle<EnvFilter> + Send + Sync>>) -> Self {
-		Self {
-			inner: Arc::new(LogLevelReloadHandlesInner {
-				handles,
-			}),
-		}
+	pub fn add(&self, name: &str, handle: Handle) {
+		self.handles
+			.lock()
+			.expect("locked")
+			.insert(name.into(), handle);
 	}
 
-	pub fn reload(&self, new_value: &EnvFilter) -> Result<(), reload::Error> {
-		for handle in &self.inner.handles {
-			handle.reload(new_value.clone())?;
-		}
+	pub fn reload(&self, new_value: &EnvFilter) -> Result<()> {
+		self.handles
+			.lock()
+			.expect("locked")
+			.values()
+			.for_each(|handle| {
+				_ = handle.reload(new_value.clone()).or_else(error::else_log);
+			});
 
 		Ok(())
 	}
 }
+
+impl Default for LogLevelReloadHandles {
+	fn default() -> Self {
+		Self {
+			handles: Arc::new(HandleMap::new().into()),
+		}
+	}
+}
diff --git a/src/main/tracing.rs b/src/main/tracing.rs
index bbfe4dc4245d6a01493590bb0c6ac93e6e214368..4c8fde5a20915e168286bf4f22f75cda0d45dfcd 100644
--- a/src/main/tracing.rs
+++ b/src/main/tracing.rs
@@ -4,7 +4,7 @@
 	config,
 	config::Config,
 	debug_warn,
-	log::{capture, LogLevelReloadHandles, ReloadHandle},
+	log::{capture, LogLevelReloadHandles},
 };
 use tracing_subscriber::{layer::SubscriberExt, reload, EnvFilter, Layer, Registry};
 
@@ -15,6 +15,8 @@
 
 #[allow(clippy::redundant_clone)]
 pub(crate) fn init(config: &Config) -> (LogLevelReloadHandles, TracingFlameGuard, Arc<capture::State>) {
+	let reload_handles = LogLevelReloadHandles::default();
+
 	let fmt_layer = tracing_subscriber::fmt::Layer::new();
 	let filter_layer = match EnvFilter::try_new(&config.log) {
 		Ok(s) => s,
@@ -24,9 +26,8 @@ pub(crate) fn init(config: &Config) -> (LogLevelReloadHandles, TracingFlameGuard
 		},
 	};
 
-	let mut reload_handles = Vec::<Box<dyn ReloadHandle<EnvFilter> + Send + Sync>>::new();
 	let (fmt_reload_filter, fmt_reload_handle) = reload::Layer::new(filter_layer.clone());
-	reload_handles.push(Box::new(fmt_reload_handle));
+	reload_handles.add("format", Box::new(fmt_reload_handle));
 
 	let subscriber = Registry::default().with(fmt_layer.with_filter(fmt_reload_filter));
 
@@ -38,7 +39,7 @@ pub(crate) fn init(config: &Config) -> (LogLevelReloadHandles, TracingFlameGuard
 	let subscriber = {
 		let sentry_layer = sentry_tracing::layer();
 		let (sentry_reload_filter, sentry_reload_handle) = reload::Layer::new(filter_layer.clone());
-		reload_handles.push(Box::new(sentry_reload_handle));
+		reload_handles.add("sentry", Box::new(sentry_reload_handle));
 		subscriber.with(sentry_layer.with_filter(sentry_reload_filter))
 	};
 
@@ -73,7 +74,7 @@ pub(crate) fn init(config: &Config) -> (LogLevelReloadHandles, TracingFlameGuard
 			let telemetry = tracing_opentelemetry::layer().with_tracer(tracer);
 
 			let (jaeger_reload_filter, jaeger_reload_handle) = reload::Layer::new(filter_layer.clone());
-			reload_handles.push(Box::new(jaeger_reload_handle));
+			reload_handles.add("jaeger", Box::new(jaeger_reload_handle));
 			Some(telemetry.with_filter(jaeger_reload_filter))
 		} else {
 			None
@@ -87,7 +88,7 @@ pub(crate) fn init(config: &Config) -> (LogLevelReloadHandles, TracingFlameGuard
 	#[cfg_attr(not(feature = "perf_measurements"), allow(clippy::let_unit_value))]
 	let flame_guard = ();
 
-	let ret = (LogLevelReloadHandles::new(reload_handles), flame_guard, cap_state);
+	let ret = (reload_handles, flame_guard, cap_state);
 
 	// Enable the tokio console. This is slightly kludgy because we're judggling
 	// compile-time and runtime conditions to elide it, each of those changing the