Skip to content

Commit b745d09

Browse files
committed
subscriber: warn if trying to enable a statically disabled level
This implements the warning in `tracing-subscriber` only, as mentioned in tokio-rs#975 (comment). It warns whenever directives are parsed, including programmatically and through environment variables. It does not include the suggested new API which returns the filters that wouldn't be parsed. - List filters that would be ignored - Mention 'static max level' - Describe how to enable the logging Example output: ``` $ RUST_LOG=off,debug,silenced[x]=trace cargo run -q warning: some trace filter directives would enable traces that are disabled statically | `debug` would enable the DEBUG level for all targets | `silenced[x]=trace` would enable the TRACE level for the `silenced` target | the static max level is info note: to enable DEBUG logging, remove the `max_level_info` feature ``` Fixes: tokio-rs#975
1 parent a8cc977 commit b745d09

File tree

4 files changed

+54
-5
lines changed

4 files changed

+54
-5
lines changed

tracing-core/src/metadata.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ pub struct Metadata<'a> {
9494
pub struct Kind(KindInner);
9595

9696
/// Describes the level of verbosity of a span or event.
97-
#[derive(Clone, Debug, PartialEq, Eq)]
97+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
9898
pub struct Level(LevelInner);
9999

100100
/// A filter comparable to a verbosity `Level`.
@@ -107,7 +107,7 @@ pub struct Level(LevelInner);
107107
/// addition of an `OFF` level that completely disables all trace
108108
/// instrumentation.
109109
#[repr(transparent)]
110-
#[derive(Clone, Eq, PartialEq)]
110+
#[derive(Copy, Clone, Eq, PartialEq)]
111111
pub struct LevelFilter(Option<Level>);
112112

113113
/// Indicates that a string could not be parsed to a valid level.

tracing-subscriber/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ keywords = ["logging", "tracing", "metrics", "subscriber"]
2424
[features]
2525

2626
default = ["env-filter", "smallvec", "fmt", "ansi", "chrono", "tracing-log", "json"]
27-
env-filter = ["matchers", "regex", "lazy_static"]
27+
env-filter = ["matchers", "regex", "lazy_static", "tracing"]
2828
fmt = ["registry"]
2929
ansi = ["fmt", "ansi_term"]
3030
registry = ["sharded-slab", "thread_local"]
@@ -34,6 +34,7 @@ json = ["tracing-serde", "serde", "serde_json"]
3434
tracing-core = { path = "../tracing-core", version = "0.1.16" }
3535

3636
# only required by the filter feature
37+
tracing = { optional = true, path = "../tracing", version = "0.1.16" }
3738
matchers = { optional = true, version = "0.0.1" }
3839
regex = { optional = true, version = "1", default-features = false, features = ["std"] }
3940
smallvec = { optional = true, version = "1" }

tracing-subscriber/src/filter/env/directive.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ use tracing_core::{span, Level, Metadata};
99
// TODO(eliza): add a builder for programmatically constructing directives?
1010
#[derive(Debug, Eq, PartialEq)]
1111
pub struct Directive {
12-
target: Option<String>,
12+
pub(crate) target: Option<String>,
1313
in_span: Option<String>,
1414
fields: FilterVec<field::Match>,
15-
level: LevelFilter,
15+
pub(crate) level: LevelFilter,
1616
}
1717

1818
/// A directive which will statically enable or disable a given callsite.

tracing-subscriber/src/filter/env/mod.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,54 @@ impl EnvFilter {
242242
}
243243

244244
fn from_directives(directives: impl IntoIterator<Item = Directive>) -> Self {
245+
use tracing::level_filters::STATIC_MAX_LEVEL;
246+
use tracing::Level;
247+
248+
let directives: Vec<_> = directives.into_iter().collect();
249+
250+
let disabled: Vec<_> = directives
251+
.iter()
252+
.filter(|directive| directive.level > STATIC_MAX_LEVEL)
253+
.collect();
254+
255+
if !disabled.is_empty() {
256+
eprintln!("warning: some trace filter directives would enable traces that are disabled statically");
257+
for directive in disabled {
258+
let target = if let Some(target) = &directive.target {
259+
format!("the `{}` target", target)
260+
} else {
261+
"all targets".into()
262+
};
263+
let level = directive
264+
.level
265+
.into_level()
266+
.expect("=off would not have enabled any filters");
267+
eprintln!(
268+
" | `{}` would enable the {} level for {}",
269+
directive, level, target
270+
);
271+
}
272+
eprintln!(" | the static max level is {}", STATIC_MAX_LEVEL);
273+
let help_msg = || {
274+
let (feature, filter) = match STATIC_MAX_LEVEL.into_level() {
275+
Some(Level::TRACE) => unreachable!(
276+
"if the max level is trace, no static filtering features are enabled"
277+
),
278+
Some(Level::DEBUG) => ("max_level_debug", Level::TRACE),
279+
Some(Level::INFO) => ("max_level_info", Level::DEBUG),
280+
Some(Level::WARN) => ("max_level_warn", Level::INFO),
281+
Some(Level::ERROR) => ("max_level_error", Level::WARN),
282+
None => return ("max_level_off", String::new()),
283+
};
284+
(feature, format!("{} ", filter))
285+
};
286+
let (feature, earlier_level) = help_msg();
287+
eprintln!(
288+
"note: to enable {}logging, remove the `{}` feature",
289+
earlier_level, feature
290+
);
291+
}
292+
245293
let (dynamics, mut statics) = Directive::make_tables(directives);
246294
let has_dynamics = !dynamics.is_empty();
247295

0 commit comments

Comments
 (0)