From 61c1bc688719fee599d891de89762d7fbd55e6f9 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Sat, 16 Nov 2024 18:23:45 -0800 Subject: [PATCH] feat!: Make log crate optional - Add log feature flag (enabled by default) - Move log specific code to `log` module - Move top level re-exports of log types to `log` module BREAKING CHANGE: The log crate is now an optional dependency, enabled by default. The `log::Level` and `log::LevelFilter` types are now re-exported from the `log` module rather than the crate root. If you were using these types directly, you will need to update your imports. ```diff -use clap_verbosity_flag::{Level, LevelFilter}; +use clap_verbosity_flag::log::{Level, LevelFilter}; ``` --- Cargo.toml | 18 ++++++++- src/lib.rs | 111 +++++++++-------------------------------------------- src/log.rs | 91 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 94 deletions(-) create mode 100644 src/log.rs diff --git a/Cargo.toml b/Cargo.toml index 289c73e..b2cb7b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -113,8 +113,12 @@ pre-release-replacements = [ [badges] codecov = { repository = "clap-rs/clap-verbosity-flag" } +[features] +default = ["log"] +log = ["dep:log"] + [dependencies] -log = "0.4.1" +log = { version = "0.4.1", optional = true } clap = { version = "4.0.0", default-features = false, features = ["std", "derive"] } [dev-dependencies] @@ -126,3 +130,15 @@ tracing-log = "0.2" [lints] workspace = true + +[[example]] +name = "log" +required-features = ["log"] + +[[example]] +name = "log_level" +required-features = ["log"] + +[[example]] +name = "tracing" +required-features = ["log"] \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 3c1b169..c99db56 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,7 @@ //! # verbose: Verbosity, //! # } //! let cli = Cli::parse(); +//! # #[cfg(feature = "log")] //! env_logger::Builder::new() //! .filter_level(cli.verbose.log_level_filter()) //! .init(); @@ -63,8 +64,8 @@ use std::fmt; -pub use log::Level; -pub use log::LevelFilter; +#[cfg(feature = "log")] +pub mod log; /// Logging flags to `#[command(flatten)]` into your CLI #[derive(clap::Args, Debug, Clone, Default)] @@ -111,18 +112,6 @@ impl Verbosity { self.verbose != 0 || self.quiet != 0 } - /// Get the log level. - /// - /// `None` means all output is disabled. - pub fn log_level(&self) -> Option { - self.filter().into() - } - - /// Get the log level filter. - pub fn log_level_filter(&self) -> LevelFilter { - self.filter().into() - } - /// If the user requested complete silence (i.e. not just no-logging). pub fn is_silent(&self) -> bool { self.filter() == VerbosityFilter::Off @@ -135,6 +124,21 @@ impl Verbosity { } } +#[cfg(feature = "log")] +impl Verbosity { + /// Get the log level. + /// + /// `None` means all output is disabled. + pub fn log_level(&self) -> Option { + self.filter().into() + } + + /// Get the log level filter. + pub fn log_level_filter(&self) -> log::LevelFilter { + self.filter().into() + } +} + impl fmt::Display for Verbosity { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.filter().fmt(f) @@ -217,58 +221,6 @@ impl fmt::Display for VerbosityFilter { } } -impl From for LevelFilter { - fn from(filter: VerbosityFilter) -> Self { - match filter { - VerbosityFilter::Off => LevelFilter::Off, - VerbosityFilter::Error => LevelFilter::Error, - VerbosityFilter::Warn => LevelFilter::Warn, - VerbosityFilter::Info => LevelFilter::Info, - VerbosityFilter::Debug => LevelFilter::Debug, - VerbosityFilter::Trace => LevelFilter::Trace, - } - } -} - -impl From for VerbosityFilter { - fn from(level: LevelFilter) -> Self { - match level { - LevelFilter::Off => Self::Off, - LevelFilter::Error => Self::Error, - LevelFilter::Warn => Self::Warn, - LevelFilter::Info => Self::Info, - LevelFilter::Debug => Self::Debug, - LevelFilter::Trace => Self::Trace, - } - } -} - -impl From for Option { - fn from(filter: VerbosityFilter) -> Self { - match filter { - VerbosityFilter::Off => None, - VerbosityFilter::Error => Some(Level::Error), - VerbosityFilter::Warn => Some(Level::Warn), - VerbosityFilter::Info => Some(Level::Info), - VerbosityFilter::Debug => Some(Level::Debug), - VerbosityFilter::Trace => Some(Level::Trace), - } - } -} - -impl From> for VerbosityFilter { - fn from(level: Option) -> Self { - match level { - None => Self::Off, - Some(Level::Error) => Self::Error, - Some(Level::Warn) => Self::Warn, - Some(Level::Info) => Self::Info, - Some(Level::Debug) => Self::Debug, - Some(Level::Trace) => Self::Trace, - } - } -} - /// Default to [`VerbosityFilter::Error`] #[derive(Copy, Clone, Debug, Default)] pub struct ErrorLevel; @@ -345,33 +297,6 @@ mod test { Cli::command().debug_assert(); } - #[test] - fn log_level() { - let v = Verbosity::::default(); - assert_eq!(v.log_level(), None); - assert_eq!(v.log_level_filter(), LevelFilter::Off); - - let v = Verbosity::::default(); - assert_eq!(v.log_level(), Some(Level::Error)); - assert_eq!(v.log_level_filter(), LevelFilter::Error); - - let v = Verbosity::::default(); - assert_eq!(v.log_level(), Some(Level::Warn)); - assert_eq!(v.log_level_filter(), LevelFilter::Warn); - - let v = Verbosity::::default(); - assert_eq!(v.log_level(), Some(Level::Info)); - assert_eq!(v.log_level_filter(), LevelFilter::Info); - - let v = Verbosity::::default(); - assert_eq!(v.log_level(), Some(Level::Debug)); - assert_eq!(v.log_level_filter(), LevelFilter::Debug); - - let v = Verbosity::::default(); - assert_eq!(v.log_level(), Some(Level::Trace)); - assert_eq!(v.log_level_filter(), LevelFilter::Trace); - } - /// Asserts that the filter is correct for the given verbosity and quiet values. #[track_caller] fn assert_filter(verbose: u8, quiet: u8, expected: VerbosityFilter) { diff --git a/src/log.rs b/src/log.rs new file mode 100644 index 0000000..94d87d2 --- /dev/null +++ b/src/log.rs @@ -0,0 +1,91 @@ +// These re-exports of the log crate make it easy to use this crate without having to depend on the +// log crate directly. See for more +// information. +pub use log::{Level, LevelFilter}; + +use crate::VerbosityFilter; + +impl From for LevelFilter { + fn from(filter: VerbosityFilter) -> Self { + match filter { + VerbosityFilter::Off => LevelFilter::Off, + VerbosityFilter::Error => LevelFilter::Error, + VerbosityFilter::Warn => LevelFilter::Warn, + VerbosityFilter::Info => LevelFilter::Info, + VerbosityFilter::Debug => LevelFilter::Debug, + VerbosityFilter::Trace => LevelFilter::Trace, + } + } +} + +impl From for VerbosityFilter { + fn from(level: LevelFilter) -> Self { + match level { + LevelFilter::Off => Self::Off, + LevelFilter::Error => Self::Error, + LevelFilter::Warn => Self::Warn, + LevelFilter::Info => Self::Info, + LevelFilter::Debug => Self::Debug, + LevelFilter::Trace => Self::Trace, + } + } +} + +impl From for Option { + fn from(filter: VerbosityFilter) -> Self { + match filter { + VerbosityFilter::Off => None, + VerbosityFilter::Error => Some(Level::Error), + VerbosityFilter::Warn => Some(Level::Warn), + VerbosityFilter::Info => Some(Level::Info), + VerbosityFilter::Debug => Some(Level::Debug), + VerbosityFilter::Trace => Some(Level::Trace), + } + } +} + +impl From> for VerbosityFilter { + fn from(level: Option) -> Self { + match level { + None => Self::Off, + Some(Level::Error) => Self::Error, + Some(Level::Warn) => Self::Warn, + Some(Level::Info) => Self::Info, + Some(Level::Debug) => Self::Debug, + Some(Level::Trace) => Self::Trace, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{DebugLevel, ErrorLevel, InfoLevel, OffLevel, TraceLevel, Verbosity, WarnLevel}; + + #[test] + fn log_level() { + let v = Verbosity::::default(); + assert_eq!(v.log_level(), None); + assert_eq!(v.log_level_filter(), LevelFilter::Off); + + let v = Verbosity::::default(); + assert_eq!(v.log_level(), Some(Level::Error)); + assert_eq!(v.log_level_filter(), LevelFilter::Error); + + let v = Verbosity::::default(); + assert_eq!(v.log_level(), Some(Level::Warn)); + assert_eq!(v.log_level_filter(), LevelFilter::Warn); + + let v = Verbosity::::default(); + assert_eq!(v.log_level(), Some(Level::Info)); + assert_eq!(v.log_level_filter(), LevelFilter::Info); + + let v = Verbosity::::default(); + assert_eq!(v.log_level(), Some(Level::Debug)); + assert_eq!(v.log_level_filter(), LevelFilter::Debug); + + let v = Verbosity::::default(); + assert_eq!(v.log_level(), Some(Level::Trace)); + assert_eq!(v.log_level_filter(), LevelFilter::Trace); + } +}