Skip to content

Commit

Permalink
Implement VerbosityFilter
Browse files Browse the repository at this point in the history
This allows more code to be shared between tracing and log impls
  • Loading branch information
joshka committed Nov 14, 2024
1 parent 7c910fb commit dddcca0
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 52 deletions.
83 changes: 80 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,11 @@ pub struct Verbosity<L: LogLevel = ErrorLevel> {
phantom: std::marker::PhantomData<L>,
}

impl<L: LogLevel> Verbosity<L> {
impl<L: LogLevel> Verbosity<L>
where
VerbosityFilter: From<L::LevelFilter>,
<L as LogLevel>::LevelFilter: From<VerbosityFilter>,
{
/// Create a new verbosity instance by explicitly setting the values
pub fn new(verbose: u8, quiet: u8) -> Self {
Verbosity {
Expand All @@ -118,14 +122,34 @@ impl<L: LogLevel> Verbosity<L> {
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<L: LogLevel> fmt::Display for Verbosity<L> {
impl<L: LogLevel> fmt::Display for Verbosity<L>
where
VerbosityFilter: From<L::LevelFilter>,
<L as LogLevel>::LevelFilter: From<VerbosityFilter>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.verbosity_offset())
write!(f, "{}", self.verbosity_filter())
}
}

Expand Down Expand Up @@ -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::*;
Expand Down
48 changes: 21 additions & 27 deletions src/log.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pub use log::Level;
pub use log::LevelFilter;

use crate::{LogLevel, Verbosity};
use crate::{LogLevel, Verbosity, VerbosityFilter};

impl<L: LogLevel<LevelFilter = LevelFilter>> Verbosity<L> {
/// Get the log level.
Expand All @@ -10,34 +10,29 @@ impl<L: LogLevel<LevelFilter = LevelFilter>> Verbosity<L> {
pub fn log_level(&self) -> Option<Level> {
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<VerbosityFilter> 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<LevelFilter> 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,
}
}
}
Expand Down Expand Up @@ -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;

Expand Down
45 changes: 23 additions & 22 deletions src/tracing.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,37 @@
use crate::{LogLevel, Verbosity};
use crate::{LogLevel, Verbosity, VerbosityFilter};
use tracing_core::{Level, LevelFilter};

impl<L: LogLevel<LevelFilter = LevelFilter>> Verbosity<L> {
/// Get the log level.
/// Get the level.
///
/// `None` means all output is disabled.
pub fn tracing_level(&self) -> Option<Level> {
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<VerbosityFilter> 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<LevelFilter> 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,
}
}
}
Expand Down

0 comments on commit dddcca0

Please sign in to comment.