Skip to content

Commit 1d901b3

Browse files
authored
subscriber: warn if trying to enable a statically disabled level (#990)
## Motivation Fixes #975. ## Solution This implements the warning in `tracing-subscriber` only, as mentioned in #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 = note: the static max level is info = note: to enable DEBUG logging, remove the `max_level_info` feature ``` ![image](https://user-images.githubusercontent.com/23638587/95243324-77dc6a00-07de-11eb-8ed3-6ee2109940d4.png)
1 parent cb1dd95 commit 1d901b3

File tree

3 files changed

+94
-3
lines changed

3 files changed

+94
-3
lines changed

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.2" }
3535

3636
# only required by the filter feature
37+
tracing = { optional = true, path = "../tracing", version = "0.2" }
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>,
1312
in_span: Option<String>,
1413
fields: FilterVec<field::Match>,
15-
level: LevelFilter,
14+
pub(crate) target: Option<String>,
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: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,96 @@ impl EnvFilter {
247247
}
248248

249249
fn from_directives(directives: impl IntoIterator<Item = Directive>) -> Self {
250+
use tracing::level_filters::STATIC_MAX_LEVEL;
251+
use tracing::Level;
252+
253+
let directives: Vec<_> = directives.into_iter().collect();
254+
255+
let disabled: Vec<_> = directives
256+
.iter()
257+
.filter(|directive| directive.level > STATIC_MAX_LEVEL)
258+
.collect();
259+
260+
if !disabled.is_empty() {
261+
#[cfg(feature = "ansi_term")]
262+
use ansi_term::{Color, Style};
263+
// NOTE: We can't use a configured `MakeWriter` because the EnvFilter
264+
// has no knowledge of any underlying subscriber or collector, which
265+
// may or may not use a `MakeWriter`.
266+
let warn = |msg: &str| {
267+
#[cfg(not(feature = "ansi_term"))]
268+
let msg = format!("warning: {}", msg);
269+
#[cfg(feature = "ansi_term")]
270+
let msg = {
271+
let bold = Style::new().bold();
272+
let mut warning = Color::Yellow.paint("warning");
273+
warning.style_ref_mut().is_bold = true;
274+
format!("{}{} {}", warning, bold.clone().paint(":"), bold.paint(msg))
275+
};
276+
eprintln!("{}", msg);
277+
};
278+
let ctx_prefixed = |prefix: &str, msg: &str| {
279+
#[cfg(not(feature = "ansi_term"))]
280+
let msg = format!("note: {}", msg);
281+
#[cfg(feature = "ansi_term")]
282+
let msg = {
283+
let mut equal = Color::Fixed(21).paint("="); // dark blue
284+
equal.style_ref_mut().is_bold = true;
285+
format!(" {} {} {}", equal, Style::new().bold().paint(prefix), msg)
286+
};
287+
eprintln!("{}", msg);
288+
};
289+
let ctx_help = |msg| ctx_prefixed("help:", msg);
290+
let ctx_note = |msg| ctx_prefixed("note:", msg);
291+
let ctx = |msg: &str| {
292+
#[cfg(not(feature = "ansi_term"))]
293+
let msg = format!("note: {}", msg);
294+
#[cfg(feature = "ansi_term")]
295+
let msg = {
296+
let mut pipe = Color::Fixed(21).paint("|");
297+
pipe.style_ref_mut().is_bold = true;
298+
format!(" {} {}", pipe, msg)
299+
};
300+
eprintln!("{}", msg);
301+
};
302+
warn("some trace filter directives would enable traces that are disabled statically");
303+
for directive in disabled {
304+
let target = if let Some(target) = &directive.target {
305+
format!("the `{}` target", target)
306+
} else {
307+
"all targets".into()
308+
};
309+
let level = directive
310+
.level
311+
.clone()
312+
.into_level()
313+
.expect("=off would not have enabled any filters");
314+
ctx(&format!(
315+
"`{}` would enable the {} level for {}",
316+
directive, level, target
317+
));
318+
}
319+
ctx_note(&format!("the static max level is `{}`", STATIC_MAX_LEVEL));
320+
let help_msg = || {
321+
let (feature, filter) = match STATIC_MAX_LEVEL.into_level() {
322+
Some(Level::TRACE) => unreachable!(
323+
"if the max level is trace, no static filtering features are enabled"
324+
),
325+
Some(Level::DEBUG) => ("max_level_debug", Level::TRACE),
326+
Some(Level::INFO) => ("max_level_info", Level::DEBUG),
327+
Some(Level::WARN) => ("max_level_warn", Level::INFO),
328+
Some(Level::ERROR) => ("max_level_error", Level::WARN),
329+
None => return ("max_level_off", String::new()),
330+
};
331+
(feature, format!("{} ", filter))
332+
};
333+
let (feature, earlier_level) = help_msg();
334+
ctx_help(&format!(
335+
"to enable {}logging, remove the `{}` feature",
336+
earlier_level, feature
337+
));
338+
}
339+
250340
let (dynamics, mut statics) = Directive::make_tables(directives);
251341
let has_dynamics = !dynamics.is_empty();
252342

0 commit comments

Comments
 (0)