chore: Allow custom default log level

This PR moves the definition of the `log_filter` default value from the `structopt` annotation
to the `trogging::Builder`. This allows users of `trogging` to define their own default value
for the log level.
pull/24376/head
Marko Mikulicic 2021-06-16 10:48:36 +02:00
parent a429de4784
commit 58e1494ca2
No known key found for this signature in database
GPG Key ID: D02A41F91A687DB3
2 changed files with 126 additions and 13 deletions

View File

@ -1,6 +1,6 @@
///! Common CLI flags for logging and tracing ///! Common CLI flags for logging and tracing
use crate::{config::*, Builder, Result, TracingGuard}; use crate::{config::*, Builder, Result, TracingGuard};
use observability_deps::tracing_subscriber::fmt::writer::BoxMakeWriter; use observability_deps::tracing_subscriber::fmt::{writer::BoxMakeWriter, MakeWriter};
use std::num::NonZeroU16; use std::num::NonZeroU16;
use structopt::StructOpt; use structopt::StructOpt;
@ -20,8 +20,13 @@ pub struct TracingConfig {
/// ///
/// Extended syntax provided by `tracing-subscriber` includes span/field /// Extended syntax provided by `tracing-subscriber` includes span/field
/// filters. See <https://docs.rs/tracing-subscriber/0.2.17/tracing_subscriber/filter/struct.EnvFilter.html> for more details. /// filters. See <https://docs.rs/tracing-subscriber/0.2.17/tracing_subscriber/filter/struct.EnvFilter.html> for more details.
#[structopt(long = "--log-filter", env = "LOG_FILTER", default_value = "warn")] ///
pub log_filter: String, /// Overridden by `-v`.
///
/// If None, [`crate::Builder`] sets a default, by default [`crate::Builder::DEFAULT_LOG_FILTER`],
/// but overrideable with [`crate::Builder::with_default_log_filter`].
#[structopt(long = "--log-filter", env = "LOG_FILTER")]
pub log_filter: Option<String>,
/// Logs: filter short-hand /// Logs: filter short-hand
/// ///
@ -236,7 +241,14 @@ pub struct TracingConfig {
impl TracingConfig { impl TracingConfig {
pub fn to_builder(&self) -> Builder<BoxMakeWriter> { pub fn to_builder(&self) -> Builder<BoxMakeWriter> {
Builder::new() self.with_builder(Builder::new())
}
pub fn with_builder<W>(&self, builder: Builder<W>) -> Builder<BoxMakeWriter>
where
W: MakeWriter + Send + Sync + Clone + 'static,
{
builder
.with_log_filter(&self.log_filter) .with_log_filter(&self.log_filter)
// with_verbose_count goes after with_log_filter because our CLI flag state // with_verbose_count goes after with_log_filter because our CLI flag state
// that --v overrides --log-filter. // that --v overrides --log-filter.
@ -263,6 +275,21 @@ impl TracingConfig {
} }
} }
/// Extends the trogging [`crate::Builder`] API.
pub trait TracingConfigBuilderExt {
/// Applies all config entries from a [`TracingConfig`] to a [`crate::Builder`].
fn with_config(self, config: &TracingConfig) -> Builder<BoxMakeWriter>;
}
impl<W> TracingConfigBuilderExt for Builder<W>
where
W: MakeWriter + Send + Sync + Clone + 'static,
{
fn with_config(self, config: &TracingConfig) -> Builder<BoxMakeWriter> {
config.with_builder(self)
}
}
impl From<TracingConfig> for Builder<BoxMakeWriter> { impl From<TracingConfig> for Builder<BoxMakeWriter> {
fn from(config: TracingConfig) -> Self { fn from(config: TracingConfig) -> Self {
config.to_builder() config.to_builder()
@ -330,6 +357,44 @@ WARN woo
INFO bar INFO bar
DEBUG baz DEBUG baz
TRACE trax TRACE trax
"#
.trim_start(),
);
}
#[test]
fn test_custom_default_log_level() {
let cfg = TracingConfig::from_iter_safe(to_vec(&["cli"])).unwrap();
assert_eq!(
simple_test(
Builder::new()
.with_default_log_filter("debug")
.with_config(&cfg)
)
.without_timestamps(),
r#"
ERROR foo
WARN woo
INFO bar
DEBUG baz
"#
.trim_start(),
);
let cfg = TracingConfig::from_iter_safe(to_vec(&["cli", "--log-filter=info"])).unwrap();
assert_eq!(
simple_test(
Builder::new()
.with_default_log_filter("debug")
.with_config(&cfg)
)
.without_timestamps(),
r#"
ERROR foo
WARN woo
INFO bar
"# "#
.trim_start(), .trim_start(),
); );

View File

@ -39,7 +39,9 @@ pub type Result<T, E = Error> = std::result::Result<T, E>;
/// Builder for tracing and logging. /// Builder for tracing and logging.
pub struct Builder<W = fn() -> io::Stdout> { pub struct Builder<W = fn() -> io::Stdout> {
log_format: LogFormat, log_format: LogFormat,
log_filter: EnvFilter, log_filter: Option<EnvFilter>,
// used when log_filter is none.
default_log_filter: EnvFilter,
traces_filter: Option<EnvFilter>, traces_filter: Option<EnvFilter>,
traces_exporter: TracesExporter, traces_exporter: TracesExporter,
traces_sampler: TracesSampler, traces_sampler: TracesSampler,
@ -55,7 +57,8 @@ impl Default for Builder {
fn default() -> Self { fn default() -> Self {
Self { Self {
log_format: LogFormat::Full, log_format: LogFormat::Full,
log_filter: EnvFilter::try_new(Self::DEFAULT_LOG_FILTER).unwrap(), log_filter: None,
default_log_filter: EnvFilter::try_new(Self::DEFAULT_LOG_FILTER).unwrap(),
traces_filter: None, traces_filter: None,
traces_exporter: TracesExporter::None, traces_exporter: TracesExporter::None,
traces_sampler: TracesSampler::ParentBasedTraceIdRatio, traces_sampler: TracesSampler::ParentBasedTraceIdRatio,
@ -86,6 +89,7 @@ impl<W> Builder<W> {
// cannot use `..self` because W type parameter changes // cannot use `..self` because W type parameter changes
log_format: self.log_format, log_format: self.log_format,
log_filter: self.log_filter, log_filter: self.log_filter,
default_log_filter: self.default_log_filter,
traces_filter: self.traces_filter, traces_filter: self.traces_filter,
traces_exporter: self.traces_exporter, traces_exporter: self.traces_exporter,
traces_sampler: self.traces_sampler, traces_sampler: self.traces_sampler,
@ -103,7 +107,7 @@ impl<W> Builder<W>
where where
W: MakeWriter + Send + Sync + 'static, W: MakeWriter + Send + Sync + 'static,
{ {
const DEFAULT_LOG_FILTER: &'static str = "warn"; pub const DEFAULT_LOG_FILTER: &'static str = "warn";
/// Set log_filter using a simple numeric "verbosity level". /// Set log_filter using a simple numeric "verbosity level".
/// ///
@ -111,18 +115,28 @@ where
pub fn with_log_verbose_count(self, log_verbose_count: u8) -> Self { pub fn with_log_verbose_count(self, log_verbose_count: u8) -> Self {
let log_filter = match log_verbose_count { let log_filter = match log_verbose_count {
0 => self.log_filter, 0 => self.log_filter,
1 => EnvFilter::try_new("info").unwrap(), 1 => Some(EnvFilter::try_new("info").unwrap()),
2 => EnvFilter::try_new("debug,hyper::proto::h1=info,h2=info").unwrap(), 2 => Some(EnvFilter::try_new("debug,hyper::proto::h1=info,h2=info").unwrap()),
_ => EnvFilter::try_new("trace,hyper::proto::h1=info,h2=info").unwrap(), _ => Some(EnvFilter::try_new("trace,hyper::proto::h1=info,h2=info").unwrap()),
}; };
Self { log_filter, ..self } Self { log_filter, ..self }
} }
pub fn with_log_filter(self, log_filter: impl AsRef<str>) -> Self { pub fn with_log_filter(self, log_filter: &Option<String>) -> Self {
let log_filter = EnvFilter::try_new(log_filter).unwrap(); let log_filter = log_filter
.as_ref()
.map(|log_filter| EnvFilter::try_new(log_filter).unwrap());
Self { log_filter, ..self } Self { log_filter, ..self }
} }
pub fn with_default_log_filter(self, default_log_filter: impl AsRef<str>) -> Self {
let default_log_filter = EnvFilter::try_new(default_log_filter).unwrap();
Self {
default_log_filter,
..self
}
}
pub fn with_log_format(self, log_format: LogFormat) -> Self { pub fn with_log_format(self, log_format: LogFormat) -> Self {
Self { log_format, ..self } Self { log_format, ..self }
} }
@ -141,6 +155,7 @@ where
// cannot use `..self` because W type parameter changes // cannot use `..self` because W type parameter changes
log_format: self.log_format, log_format: self.log_format,
log_filter: self.log_filter, log_filter: self.log_filter,
default_log_filter: self.default_log_filter,
traces_filter: self.traces_filter, traces_filter: self.traces_filter,
traces_exporter: self.traces_exporter, traces_exporter: self.traces_exporter,
traces_sampler: self.traces_sampler, traces_sampler: self.traces_sampler,
@ -354,7 +369,7 @@ where
}; };
let subscriber = tracing_subscriber::Registry::default() let subscriber = tracing_subscriber::Registry::default()
.with(self.log_filter) .with(self.log_filter.unwrap_or(self.default_log_filter))
.with(log_format_full) .with(log_format_full)
.with(log_format_pretty) .with(log_format_pretty)
.with(log_format_json) .with(log_format_json)
@ -539,6 +554,39 @@ WARN woo
INFO bar INFO bar
DEBUG baz DEBUG baz
TRACE trax TRACE trax
"#
.trim_start(),
);
}
#[test]
fn test_override_default_log_filter() {
const DEFAULT_LOG_FILTER: &str = "error";
assert_eq!(
simple_test(
Builder::new()
.with_default_log_filter(DEFAULT_LOG_FILTER)
.with_log_verbose_count(0)
)
.without_timestamps(),
r#"
ERROR foo
"#
.trim_start(),
);
assert_eq!(
simple_test(
Builder::new()
.with_default_log_filter(DEFAULT_LOG_FILTER)
.with_log_verbose_count(1)
)
.without_timestamps(),
r#"
ERROR foo
WARN woo
INFO bar
"# "#
.trim_start(), .trim_start(),
); );