use tracing_subscriber::EnvFilter;
static QUIET_DIRECTIVES: std::sync::LazyLock<Vec<String>> = std::sync::LazyLock::new(|| {
#[cfg_attr(not(feature = "pdf-surface"), allow(unused_mut))]
let mut directives: Vec<String> = [
"ureq=warn",
"ureq_proto=warn",
"rustls=warn",
"hyper_util=warn",
"hf_hub=info",
"tower_http=info",
]
.iter()
.map(|directive| (*directive).to_string())
.collect();
#[cfg(feature = "pdf-surface")]
directives.push(format!("{}=warn", xberg::pdf::render::ENGINE_LOG_TARGET_ROOT));
directives
});
fn directive_target(directive: &str) -> Option<&str> {
directive.split_once('=').map(|(target, _)| target)
}
pub fn build_env_filter(level_override: Option<&str>) -> EnvFilter {
let base = level_override
.and_then(|level| EnvFilter::try_new(level).ok())
.or_else(|| EnvFilter::try_from_default_env().ok())
.unwrap_or_else(|| EnvFilter::new("info"));
let existing_targets: std::collections::HashSet<String> = base
.to_string()
.split(',')
.filter_map(|chunk| directive_target(chunk).map(|t| t.trim().to_string()))
.collect();
QUIET_DIRECTIVES
.iter()
.filter(|directive| {
directive_target(directive.as_str())
.map(|target| !existing_targets.contains(target))
.unwrap_or(true)
})
.fold(base, |filter, directive| {
filter.add_directive(directive.parse().expect("built-in logging directive must be valid"))
})
}
#[cfg(test)]
mod tests {
use super::*;
fn filter_directives(filter: &EnvFilter) -> String {
filter.to_string()
}
#[test]
fn default_filter_suppresses_ureq() {
let filter = build_env_filter(None);
let directives = filter_directives(&filter);
assert!(
directives.contains("ureq=warn"),
"ureq=warn must be present in default filter; got: {directives}"
);
assert!(
directives.contains("ureq_proto=warn"),
"ureq_proto=warn must be present in default filter; got: {directives}"
);
assert!(
directives.contains("rustls=warn"),
"rustls=warn must be present in default filter; got: {directives}"
);
}
#[test]
fn default_filter_keeps_xberg_info() {
let filter = build_env_filter(None);
let directives = filter_directives(&filter);
assert!(
!directives.contains("xberg=warn") && !directives.contains("xberg=error"),
"xberg must not be suppressed in the default filter; got: {directives}"
);
}
#[test]
fn env_override_wins_for_third_party() {
let filter = build_env_filter(Some("info,ureq=debug"));
let directives = filter.to_string();
assert!(
directives.contains("ureq=debug"),
"user-supplied ureq=debug must be preserved; got: {directives}"
);
assert!(
!directives.contains("ureq=warn"),
"ureq=warn suppression must not be added when user already set ureq=debug; got: {directives}"
);
}
#[test]
fn level_override_wins() {
let filter = build_env_filter(Some("debug"));
let directives = filter_directives(&filter);
assert!(
directives.contains("debug"),
"root debug level must appear in filter with --log-level debug; got: {directives}"
);
assert!(
directives.contains("ureq=warn"),
"ureq=warn suppression must still be present even under --log-level debug; got: {directives}"
);
}
#[test]
fn tower_http_suppressed_at_default() {
let filter = build_env_filter(None);
let directives = filter_directives(&filter);
assert!(
directives.contains("tower_http=info") || directives.contains("tower_http=warn"),
"tower_http must be suppressed at default level; got: {directives}"
);
}
#[test]
fn all_quiet_directives_are_valid() {
for directive in super::QUIET_DIRECTIVES.iter() {
directive
.parse::<tracing_subscriber::filter::Directive>()
.expect("built-in directive is invalid");
}
}
#[test]
fn no_level_override_uses_info_root() {
let filter = build_env_filter(None);
let directives = filter_directives(&filter);
let root_is_noisier_than_info = directives.starts_with("debug") || directives.starts_with("trace");
assert!(
!root_is_noisier_than_info,
"default root level must not be debug/trace without RUST_LOG; got: {directives}"
);
}
#[test]
fn hf_hub_suppressed_at_default() {
let filter = build_env_filter(None);
let directives = filter_directives(&filter);
assert!(
directives.contains("hf_hub=info"),
"hf_hub must be suppressed to info at default; got: {directives}"
);
}
#[test]
fn hyper_util_suppressed_at_default() {
let filter = build_env_filter(None);
let directives = filter_directives(&filter);
assert!(
directives.contains("hyper_util=warn"),
"hyper_util must be suppressed to warn at default; got: {directives}"
);
}
#[cfg(feature = "pdf-surface")]
#[test]
fn pdf_engine_suppressed_at_default() {
let engine = xberg::pdf::render::ENGINE_LOG_TARGET_ROOT;
let directives = filter_directives(&build_env_filter(None));
assert!(
directives.contains(&format!("{engine}=warn")),
"{engine} must be suppressed to warn by default; got: {directives}"
);
}
#[cfg(feature = "pdf-surface")]
#[test]
fn pdf_engine_user_override_wins() {
let engine = xberg::pdf::render::ENGINE_LOG_TARGET_ROOT;
let directives = filter_directives(&build_env_filter(Some(&format!("info,{engine}=debug"))));
let tokens: Vec<&str> = directives.split(',').map(str::trim).collect();
assert!(
tokens.contains(&format!("{engine}=debug").as_str()),
"user-supplied {engine}=debug must be preserved; got: {directives}"
);
assert!(
!tokens.contains(&format!("{engine}=warn").as_str()),
"default {engine} suppression must not replace a user override; got: {directives}"
);
}
#[test]
fn malformed_level_override_falls_back_to_info() {
let filter = build_env_filter(Some(":::garbage"));
let directives = filter_directives(&filter);
assert!(
directives.contains("ureq=warn"),
"ureq=warn must still be present after malformed override; got: {directives}"
);
}
#[test]
fn similar_target_name_does_not_block_suppression() {
let filter = build_env_filter(Some("info,hf_hub_server=debug"));
let directives = filter.to_string();
assert!(
directives.contains("hf_hub_server=debug"),
"user directive for hf_hub_server must survive; got: {directives}"
);
assert!(
directives.contains("hf_hub=info"),
"hf_hub=info suppression must still be applied; got: {directives}"
);
}
#[derive(Default)]
struct RecordingLayer {
targets: std::sync::Arc<std::sync::Mutex<Vec<String>>>,
}
impl<S: tracing::Subscriber> tracing_subscriber::Layer<S> for RecordingLayer {
fn on_event(&self, event: &tracing::Event<'_>, _ctx: tracing_subscriber::layer::Context<'_, S>) {
self.targets
.lock()
.expect("recording layer mutex poisoned")
.push(event.metadata().target().to_string());
}
}
#[test]
fn pdf_engine_info_is_suppressed_while_its_warnings_survive() {
use tracing_subscriber::layer::SubscriberExt as _;
let filter = build_env_filter(None);
let recorder = RecordingLayer::default();
let targets = recorder.targets.clone();
let subscriber = tracing_subscriber::registry().with(filter).with(recorder);
tracing::subscriber::with_default(subscriber, || {
tracing::info!(target: "xberg_native_pdf::fonts", "chatty engine info");
tracing::warn!(target: "xberg_native_pdf::fonts", "engine warning worth seeing");
tracing::warn!(target: "xberg::extract", "should still be observed");
});
let captured = targets.lock().expect("recording layer mutex poisoned");
assert!(
captured
.iter()
.filter(|target| *target == "xberg_native_pdf::fonts")
.count()
== 1,
"exactly one event at the engine target must survive: the INFO suppressed by \
`=warn`, the WARN kept. Two means the directive did not match (stale prefix); \
zero means the filter is dropping warnings it should keep; \
captured targets: {captured:?}"
);
assert!(
captured.iter().any(|target| target == "xberg::extract"),
"positive control failed: xberg::extract WARN event must still pass through \
(if this also fails, the test filtered everything and proves nothing); \
captured targets: {captured:?}"
);
}
}