Skip to content

Commit 6017d2c

Browse files
committed
subscriber: increase EnvFilter test coverage (#3262)
1 parent c47aeb5 commit 6017d2c

File tree

2 files changed

+232
-0
lines changed

2 files changed

+232
-0
lines changed

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ impl Builder {
133133

134134
/// Returns a new [`EnvFilter`] from the directives in the given string,
135135
/// *ignoring* any that are invalid.
136+
///
137+
/// If `parse_lossy` is called with an empty string, then the
138+
/// [default directive] is used instead.
139+
///
140+
/// [default directive]: Self::with_default_directive
136141
pub fn parse_lossy<S: AsRef<str>>(&self, dirs: S) -> EnvFilter {
137142
let directives = dirs
138143
.as_ref()
@@ -150,6 +155,11 @@ impl Builder {
150155

151156
/// Returns a new [`EnvFilter`] from the directives in the given string,
152157
/// or an error if any are invalid.
158+
///
159+
/// If `parse` is called with an empty string, then the [default directive]
160+
/// is used instead.
161+
///
162+
/// [default directive]: Self::with_default_directive
153163
pub fn parse<S: AsRef<str>>(&self, dirs: S) -> Result<EnvFilter, directive::ParseError> {
154164
let dirs = dirs.as_ref();
155165
if dirs.is_empty() {
@@ -165,6 +175,11 @@ impl Builder {
165175

166176
/// Returns a new [`EnvFilter`] from the directives in the configured
167177
/// environment variable, ignoring any directives that are invalid.
178+
///
179+
/// If the environment variable is empty, then the [default directive]
180+
/// is used instead.
181+
///
182+
/// [default directive]: Self::with_default_directive
168183
pub fn from_env_lossy(&self) -> EnvFilter {
169184
let var = env::var(self.env_var_name()).unwrap_or_default();
170185
self.parse_lossy(var)
@@ -174,6 +189,11 @@ impl Builder {
174189
/// environment variable. If the environment variable is unset, no directive is added.
175190
///
176191
/// An error is returned if the environment contains invalid directives.
192+
///
193+
/// If the environment variable is empty, then the [default directive]
194+
/// is used instead.
195+
///
196+
/// [default directive]: Self::with_default_directive
177197
pub fn from_env(&self) -> Result<EnvFilter, FromEnvError> {
178198
let var = env::var(self.env_var_name()).unwrap_or_default();
179199
self.parse(var).map_err(Into::into)
@@ -182,6 +202,11 @@ impl Builder {
182202
/// Returns a new [`EnvFilter`] from the directives in the configured
183203
/// environment variable, or an error if the environment variable is not set
184204
/// or contains invalid directives.
205+
///
206+
/// If the environment variable is empty, then the [default directive]
207+
/// is used instead.
208+
///
209+
/// [default directive]: Self::with_default_directive
185210
pub fn try_from_env(&self) -> Result<EnvFilter, FromEnvError> {
186211
let var = env::var(self.env_var_name())?;
187212
self.parse(var).map_err(Into::into)

tracing-subscriber/tests/env_filter/main.rs

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,213 @@ fn method_name_resolution() {
236236
filter.max_level_hint();
237237
}
238238

239+
#[test]
240+
fn parse_invalid_string() {
241+
assert!(EnvFilter::builder().parse(",!").is_err());
242+
}
243+
244+
#[test]
245+
fn parse_empty_string_no_default_directive() {
246+
let filter = EnvFilter::builder().parse("").expect("filter should parse");
247+
let (subscriber, finished) = subscriber::mock().only().run_with_handle();
248+
let layer = subscriber.with(filter);
249+
250+
with_default(layer, || {
251+
tracing::trace!("this should be disabled");
252+
tracing::debug!("this should be disabled");
253+
tracing::info!("this should be disabled");
254+
tracing::warn!("this should be disabled");
255+
tracing::error!("this should be disabled");
256+
});
257+
258+
finished.assert_finished();
259+
}
260+
261+
#[test]
262+
fn parse_empty_string_with_default_directive() {
263+
let filter = EnvFilter::builder()
264+
.with_default_directive(LevelFilter::INFO.into())
265+
.parse("")
266+
.expect("filter should parse");
267+
let (subscriber, finished) = subscriber::mock()
268+
.event(expect::event().at_level(Level::INFO))
269+
.event(expect::event().at_level(Level::WARN))
270+
.event(expect::event().at_level(Level::ERROR))
271+
.only()
272+
.run_with_handle();
273+
let layer = subscriber.with(filter);
274+
275+
with_default(layer, || {
276+
tracing::trace!("this should be disabled");
277+
tracing::debug!("this should be disabled");
278+
tracing::info!("this shouldn't be disabled");
279+
tracing::warn!("this shouldn't be disabled");
280+
tracing::error!("this shouldn't be disabled");
281+
});
282+
283+
finished.assert_finished();
284+
}
285+
286+
#[test]
287+
fn new_invalid_string() {
288+
let filter = EnvFilter::new(",!");
289+
let (subscriber, finished) = subscriber::mock()
290+
.event(expect::event().at_level(Level::ERROR))
291+
.only()
292+
.run_with_handle();
293+
let layer = subscriber.with(filter);
294+
295+
with_default(layer, || {
296+
tracing::trace!("this should be disabled");
297+
tracing::debug!("this should be disabled");
298+
tracing::info!("this should be disabled");
299+
tracing::warn!("this should be disabled");
300+
tracing::error!("this shouldn't be disabled");
301+
});
302+
303+
finished.assert_finished();
304+
}
305+
306+
#[test]
307+
fn new_empty_string() {
308+
let filter = EnvFilter::new("");
309+
let (subscriber, finished) = subscriber::mock()
310+
.event(expect::event().at_level(Level::ERROR))
311+
.only()
312+
.run_with_handle();
313+
let layer = subscriber.with(filter);
314+
315+
with_default(layer, || {
316+
tracing::trace!("this should be disabled");
317+
tracing::debug!("this should be disabled");
318+
tracing::info!("this should be disabled");
319+
tracing::warn!("this should be disabled");
320+
tracing::error!("this shouldn't be disabled");
321+
});
322+
323+
finished.assert_finished();
324+
}
325+
326+
#[test]
327+
fn more_specific_static_filter_more_verbose() {
328+
let filter = EnvFilter::new("info,hello=debug");
329+
let (subscriber, finished) = subscriber::mock()
330+
.event(expect::event().at_level(Level::INFO))
331+
.event(expect::event().at_level(Level::DEBUG).with_target("hello"))
332+
.only()
333+
.run_with_handle();
334+
let layer = subscriber.with(filter);
335+
336+
with_default(layer, || {
337+
tracing::info!("should be enabled");
338+
tracing::debug!("should be disabled");
339+
tracing::debug!(target: "hello", "should be enabled");
340+
});
341+
342+
finished.assert_finished();
343+
}
344+
345+
#[test]
346+
fn more_specific_static_filter_less_verbose() {
347+
let filter = EnvFilter::new("info,hello=warn");
348+
let (subscriber, finished) = subscriber::mock()
349+
.event(expect::event().at_level(Level::INFO))
350+
.event(
351+
expect::event()
352+
.at_level(Level::WARN)
353+
.with_target("env_filter"),
354+
)
355+
.only()
356+
.run_with_handle();
357+
let layer = subscriber.with(filter);
358+
359+
with_default(layer, || {
360+
tracing::info!("should be enabled");
361+
tracing::warn!("should be enabled");
362+
tracing::info!(target: "hello", "should be disabled");
363+
});
364+
365+
finished.assert_finished();
366+
}
367+
368+
#[test]
369+
fn more_specific_dynamic_filter_more_verbose() {
370+
let filter = EnvFilter::new("info,[{hello=4}]=debug");
371+
let (subscriber, finished) = subscriber::mock()
372+
.new_span(expect::span().at_level(Level::INFO))
373+
.drop_span("enabled info")
374+
.new_span(
375+
expect::span()
376+
.at_level(Level::DEBUG)
377+
.with_fields(expect::field("hello").with_value(&4_u64)),
378+
)
379+
.drop_span("enabled debug")
380+
.event(expect::event().with_fields(expect::msg("marker")))
381+
.only()
382+
.run_with_handle();
383+
let layer = subscriber.with(filter);
384+
385+
with_default(layer, || {
386+
tracing::info_span!("enabled info");
387+
tracing::debug_span!("disabled debug");
388+
tracing::debug_span!("enabled debug", hello = &4_u64);
389+
390+
// .only() doesn't work when we don't enter/exit spans
391+
tracing::info!("marker");
392+
});
393+
394+
finished.assert_finished();
395+
}
396+
397+
/// This is a negative test. This functionality should work, but doesn't.
398+
///
399+
/// If an improvement to `EnvFilter` fixes this test, then the `#[should_panic]`
400+
/// can be removed and the test kept as it is. If the test requires some sort of
401+
/// modification, then care should be taken.
402+
///
403+
/// Fixing this test would resolve https://github.com/tokio-rs/tracing/issues/1388
404+
/// (and probably a few more issues as well).
405+
#[test]
406+
#[should_panic(
407+
expected = "[more_specific_dynamic_filter_less_verbose] expected a new span \
408+
at level `Level(Warn)`,\n[more_specific_dynamic_filter_less_verbose] but \
409+
got one at level `Level(Info)` instead."
410+
)]
411+
fn more_specific_dynamic_filter_less_verbose() {
412+
let filter = EnvFilter::new("info,[{hello=4}]=warn");
413+
let (subscriber, finished) = subscriber::mock()
414+
.new_span(expect::span().at_level(Level::INFO))
415+
.drop_span("enabled info")
416+
.new_span(
417+
expect::span()
418+
.at_level(Level::WARN)
419+
.with_fields(expect::field("hello").with_value(&100_u64)),
420+
)
421+
.drop_span("enabled hello=100 warn")
422+
.new_span(
423+
expect::span()
424+
.at_level(Level::WARN)
425+
.with_fields(expect::field("hello").with_value(&4_u64)),
426+
)
427+
.drop_span("enabled hello=4 warn")
428+
.event(expect::event().with_fields(expect::msg("marker")))
429+
.only()
430+
.run_with_handle();
431+
let layer = subscriber.with(filter);
432+
433+
with_default(layer, || {
434+
tracing::info_span!("enabled info");
435+
tracing::warn_span!("enabled hello=100 warn", hello = &100_u64);
436+
tracing::info_span!("disabled hello=4 info", hello = &4_u64);
437+
tracing::warn_span!("enabled hello=4 warn", hello = &4_u64);
438+
439+
// .only() doesn't work when we don't enter/exit spans
440+
tracing::info!("marker");
441+
});
442+
443+
finished.assert_finished();
444+
}
445+
239446
// contains the same tests as the first half of this file
240447
// but using EnvFilter as a `Filter`, not as a `Layer`
241448
mod per_layer_filter {

0 commit comments

Comments
 (0)