From 2637a930ef5df0f2f430ecf49b9192f42091dc4e Mon Sep 17 00:00:00 2001
From: Eliza Weisman <eliza@buoyant.io>
Date: Fri, 26 Feb 2021 11:21:49 -0800
Subject: [PATCH] subscriber: set `log` max level when reloading

This modifies the `tracing_subscriber::reload` layer to also set the
`log` crate's max level with the current max `tracing` level filter
after reloading. If reloading the subscriber caused the max `tracing`
level to change, this ensures that the change is propagated to the `log`
crate as well. In the case where the max level was made more verbose,
this will ensure that `log` records which were previously disabled are
enabled correctly; in the case where it was made less verbose, this
improve performance by not having to perfrom more costly filtering for
those `log` records.

The `log` max level is set only after rebuilding the callsite interest
cache, which is what sets the max `tracing` level filter. This ensures
that we pass the latest state to the `log` crate.

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
---
 tracing-subscriber/src/reload.rs              | 10 ++++++
 .../tests/reload_max_log_level.rs             | 36 +++++++++++++++++++
 2 files changed, 46 insertions(+)
 create mode 100644 tracing-subscriber/tests/reload_max_log_level.rs

diff --git a/tracing-subscriber/src/reload.rs b/tracing-subscriber/src/reload.rs
index 361234649b..72f5caff62 100644
--- a/tracing-subscriber/src/reload.rs
+++ b/tracing-subscriber/src/reload.rs
@@ -162,6 +162,16 @@ impl<S> Handle<S> {
         drop(lock);
 
         callsite::rebuild_interest_cache();
+
+        // If the `log` crate compatibility feature is in use, set `log`'s max
+        // level as well, in case the max `tracing` level changed. We do this
+        // *after* rebuilding the interest cache, as that's when the `tracing`
+        // max level filter is re-computed.
+        #[cfg(feature = "tracing-log")]
+        tracing_log::log::set_max_level(tracing_log::AsLog::as_log(
+            &crate::filter::LevelFilter::current(),
+        ));
+
         Ok(())
     }
 
diff --git a/tracing-subscriber/tests/reload_max_log_level.rs b/tracing-subscriber/tests/reload_max_log_level.rs
new file mode 100644
index 0000000000..5b870a918b
--- /dev/null
+++ b/tracing-subscriber/tests/reload_max_log_level.rs
@@ -0,0 +1,36 @@
+mod support;
+use self::support::*;
+use tracing::{self, Level};
+use tracing_subscriber::{filter::LevelFilter, prelude::*, reload};
+
+#[test]
+fn reload_max_log_level() {
+    let (collector, finished) = collector::mock()
+        .event(event::mock().at_level(Level::INFO))
+        .event(event::mock().at_level(Level::DEBUG))
+        .event(event::mock().at_level(Level::INFO))
+        .done()
+        .run_with_handle();
+    let (filter, reload_handle) = reload::Subscriber::new(LevelFilter::INFO);
+    collector.with(filter).init();
+
+    assert!(log::log_enabled!(log::Level::Info));
+    assert!(!log::log_enabled!(log::Level::Debug));
+    assert!(!log::log_enabled!(log::Level::Trace));
+
+    log::debug!("i'm disabled");
+    log::info!("i'm enabled");
+
+    reload_handle
+        .reload(Level::DEBUG)
+        .expect("reloading succeeds");
+
+    assert!(log::log_enabled!(log::Level::Info));
+    assert!(log::log_enabled!(log::Level::Debug));
+    assert!(!log::log_enabled!(log::Level::Trace));
+
+    log::debug!("i'm enabled now");
+    log::info!("i'm still enabled, too");
+
+    finished.assert_finished();
+}