From dddcca03bd419e50144be38356b74e42eb597d98 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Wed, 13 Nov 2024 17:05:20 -0800 Subject: [PATCH] Implement VerbosityFilter This allows more code to be shared between tracing and log impls --- src/lib.rs | 83 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/log.rs | 48 +++++++++++++---------------- src/tracing.rs | 45 ++++++++++++++------------- 3 files changed, 124 insertions(+), 52 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b6c7d9e..627b39a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -102,7 +102,11 @@ pub struct Verbosity { phantom: std::marker::PhantomData, } -impl Verbosity { +impl Verbosity +where + VerbosityFilter: From, + ::LevelFilter: From, +{ /// Create a new verbosity instance by explicitly setting the values pub fn new(verbose: u8, quiet: u8) -> Self { Verbosity { @@ -118,14 +122,34 @@ impl Verbosity { self.verbose != 0 || self.quiet != 0 } + /// If the user requested complete silence (i.e. not just no-logging). + pub fn is_silent(&self) -> bool { + self.verbosity_filter() == VerbosityFilter::Off + } + fn verbosity_offset(&self) -> i16 { self.verbose as i16 - self.quiet as i16 } + + fn verbosity_filter(&self) -> VerbosityFilter { + VerbosityFilter::from(L::default()).with_offset(self.verbosity_offset()) + } + + /// Get the log level filter. + pub fn log_level_filter(&self) -> L::LevelFilter { + VerbosityFilter::from(L::default()) + .with_offset(self.verbosity_offset()) + .into() + } } -impl fmt::Display for Verbosity { +impl fmt::Display for Verbosity +where + VerbosityFilter: From, + ::LevelFilter: From, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.verbosity_offset()) + write!(f, "{}", self.verbosity_filter()) } } @@ -157,6 +181,59 @@ pub trait LogLevel { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum VerbosityFilter { + Off, + Error, + Warn, + Info, + Debug, + Trace, +} + +impl fmt::Display for VerbosityFilter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Off => write!(f, "OFF"), + Self::Error => write!(f, "ERROR"), + Self::Warn => write!(f, "WARN"), + Self::Info => write!(f, "INFO"), + Self::Debug => write!(f, "DEBUG"), + Self::Trace => write!(f, "TRACE"), + } + } +} + +impl VerbosityFilter { + fn with_offset(&self, offset: i16) -> VerbosityFilter { + let value = self.value() + offset; + Self::from_value(value) + } + + fn value(&self) -> i16 { + match self { + Self::Off => 0, + Self::Error => 1, + Self::Warn => 2, + Self::Info => 3, + Self::Debug => 4, + Self::Trace => 5, + } + } + + fn from_value(value: i16) -> Self { + match value.clamp(0, 5) { + 0 => Self::Off, + 1 => Self::Error, + 2 => Self::Warn, + 3 => Self::Info, + 4 => Self::Debug, + 5 => Self::Trace, + _ => unreachable!(), + } + } +} + // #[cfg(test)] // mod test { // use super::*; diff --git a/src/log.rs b/src/log.rs index 9b73a80..b2f3444 100644 --- a/src/log.rs +++ b/src/log.rs @@ -1,7 +1,7 @@ pub use log::Level; pub use log::LevelFilter; -use crate::{LogLevel, Verbosity}; +use crate::{LogLevel, Verbosity, VerbosityFilter}; impl> Verbosity { /// Get the log level. @@ -10,34 +10,29 @@ impl> Verbosity { pub fn log_level(&self) -> Option { self.log_level_filter().to_level() } +} - /// Get the log level filter. - pub fn log_level_filter(&self) -> LevelFilter { - let verbosity = Self::log_verbosity() as i16 + self.verbosity_offset(); - match verbosity.clamp(0, 5) { - 0 => LevelFilter::Off, - 1 => LevelFilter::Error, - 2 => LevelFilter::Warn, - 3 => LevelFilter::Info, - 4 => LevelFilter::Debug, - 5 => LevelFilter::Trace, - _ => unreachable!(), +impl From for LevelFilter { + fn from(verbosity: VerbosityFilter) -> Self { + match verbosity { + VerbosityFilter::Off => LevelFilter::Off, + VerbosityFilter::Error => LevelFilter::Error, + VerbosityFilter::Warn => LevelFilter::Warn, + VerbosityFilter::Info => LevelFilter::Info, + VerbosityFilter::Debug => LevelFilter::Debug, + VerbosityFilter::Trace => LevelFilter::Trace, } } - - /// If the user requested complete silence (i.e. not just no-logging). - pub fn is_silent(&self) -> bool { - self.log_level().is_none() - } - - fn log_verbosity() -> u8 { - match L::default() { - LevelFilter::Off => 0, - LevelFilter::Error => 1, - LevelFilter::Warn => 2, - LevelFilter::Info => 3, - LevelFilter::Debug => 4, - LevelFilter::Trace => 5, +} +impl From for VerbosityFilter { + fn from(level: LevelFilter) -> Self { + match level { + LevelFilter::Off => VerbosityFilter::Off, + LevelFilter::Error => VerbosityFilter::Error, + LevelFilter::Warn => VerbosityFilter::Warn, + LevelFilter::Info => VerbosityFilter::Info, + LevelFilter::Debug => VerbosityFilter::Debug, + LevelFilter::Trace => VerbosityFilter::Trace, } } } @@ -98,7 +93,6 @@ impl LogLevel for TraceLevel { } /// Default to no logging (i.e. `None` or [`log::LevelFilter::Off`]) -#[allow(clippy::exhaustive_structs)] #[derive(Copy, Clone, Debug, Default)] pub struct OffLevel; diff --git a/src/tracing.rs b/src/tracing.rs index 488aff8..0304a96 100644 --- a/src/tracing.rs +++ b/src/tracing.rs @@ -1,36 +1,37 @@ -use crate::{LogLevel, Verbosity}; +use crate::{LogLevel, Verbosity, VerbosityFilter}; use tracing_core::{Level, LevelFilter}; impl> Verbosity { - /// Get the log level. + /// Get the level. /// /// `None` means all output is disabled. pub fn tracing_level(&self) -> Option { - self.tracing_level_filter().into_level() + self.log_level_filter().into() } - /// Get the log level filter. - pub fn tracing_level_filter(&self) -> LevelFilter { - let verbosity = Self::tracing_verbosity() as i16 + self.verbosity_offset(); +} - match verbosity.clamp(0, 5) { - 0 => LevelFilter::OFF, - 1 => LevelFilter::ERROR, - 2 => LevelFilter::WARN, - 3 => LevelFilter::INFO, - 4 => LevelFilter::DEBUG, - 5 => LevelFilter::TRACE, - _ => unreachable!(), +impl From for LevelFilter { + fn from(verbosity: VerbosityFilter) -> Self { + match verbosity { + VerbosityFilter::Off => LevelFilter::OFF, + VerbosityFilter::Error => LevelFilter::ERROR, + VerbosityFilter::Warn => LevelFilter::WARN, + VerbosityFilter::Info => LevelFilter::INFO, + VerbosityFilter::Debug => LevelFilter::DEBUG, + VerbosityFilter::Trace => LevelFilter::TRACE, } } +} - fn tracing_verbosity() -> u8 { - match L::default() { - LevelFilter::OFF => 0, - LevelFilter::ERROR => 1, - LevelFilter::WARN => 2, - LevelFilter::INFO => 3, - LevelFilter::DEBUG => 4, - LevelFilter::TRACE => 5, +impl From for VerbosityFilter { + fn from(level: LevelFilter) -> Self { + match level { + LevelFilter::OFF => VerbosityFilter::Off, + LevelFilter::ERROR => VerbosityFilter::Error, + LevelFilter::WARN => VerbosityFilter::Warn, + LevelFilter::INFO => VerbosityFilter::Info, + LevelFilter::DEBUG => VerbosityFilter::Debug, + LevelFilter::TRACE => VerbosityFilter::Trace, } } }