From 53b0316d52de60046d85d57a9711bfbfed358c2d Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Sat, 16 Nov 2024 18:39:08 -0800 Subject: [PATCH] feat: Add support for `tracing` crate It is no longer necessary to have to depend on both log and tracing-log to use clap-verbosity-flag with the tracing crate. This commit adds support for the tracing crate directly. - Add `tracing-core` as a dependency - Add `tracing` as a feature - Add `tracing` module - Remove `tracing-log` as a dependency for the `tracing` example --- Cargo.lock | 2 +- Cargo.toml | 7 ++-- examples/tracing.rs | 3 +- src/lib.rs | 17 +++++++++ src/tracing.rs | 91 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 src/tracing.rs diff --git a/Cargo.lock b/Cargo.lock index 137e3d8..00afb42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,7 +77,7 @@ dependencies = [ "env_logger", "log", "tracing", - "tracing-log", + "tracing-core", "tracing-subscriber", ] diff --git a/Cargo.toml b/Cargo.toml index b2cb7b4..a12f60b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -116,17 +116,18 @@ codecov = { repository = "clap-rs/clap-verbosity-flag" } [features] default = ["log"] log = ["dep:log"] +tracing = ["dep:tracing-core"] [dependencies] -log = { version = "0.4.1", optional = true } clap = { version = "4.0.0", default-features = false, features = ["std", "derive"] } +log = { version = "0.4.1", optional = true } +tracing-core = { version = "0.1", optional = true } [dev-dependencies] clap = { version = "4.5.4", default-features = false, features = ["help", "usage"] } env_logger = "0.11.3" tracing = "0.1" tracing-subscriber = "0.3" -tracing-log = "0.2" [lints] workspace = true @@ -141,4 +142,4 @@ required-features = ["log"] [[example]] name = "tracing" -required-features = ["log"] \ No newline at end of file +required-features = ["tracing"] \ No newline at end of file diff --git a/examples/tracing.rs b/examples/tracing.rs index 6710361..a34246e 100644 --- a/examples/tracing.rs +++ b/examples/tracing.rs @@ -1,6 +1,5 @@ use clap::Parser; use clap_verbosity_flag::Verbosity; -use tracing_log::AsTrace; /// Foo #[derive(Debug, Parser)] @@ -13,7 +12,7 @@ fn main() { let cli = Cli::parse(); tracing_subscriber::fmt() - .with_max_level(cli.verbose.log_level_filter().as_trace()) + .with_max_level(cli.verbose.tracing_level_filter()) .init(); tracing::error!("Engines exploded"); diff --git a/src/lib.rs b/src/lib.rs index c99db56..9a5b5f4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,6 +66,8 @@ use std::fmt; #[cfg(feature = "log")] pub mod log; +#[cfg(feature = "tracing")] +pub mod tracing; /// Logging flags to `#[command(flatten)]` into your CLI #[derive(clap::Args, Debug, Clone, Default)] @@ -139,6 +141,21 @@ impl Verbosity { } } +#[cfg(feature = "tracing")] +impl Verbosity { + /// Get the tracing level. + /// + /// `None` means all output is disabled. + pub fn tracing_level(&self) -> Option { + self.filter().into() + } + + /// Get the tracing level filter. + pub fn tracing_level_filter(&self) -> tracing_core::LevelFilter { + self.filter().into() + } +} + impl fmt::Display for Verbosity { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.filter().fmt(f) diff --git a/src/tracing.rs b/src/tracing.rs new file mode 100644 index 0000000..3715f52 --- /dev/null +++ b/src/tracing.rs @@ -0,0 +1,91 @@ +// These re-exports of the tracing crate types it easy to use this crate without having to depend on +// the tracing crate directly. See for +// more information. +pub use tracing_core::{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 tracing_level() { + let v = Verbosity::::default(); + assert_eq!(v.tracing_level(), None); + assert_eq!(v.tracing_level_filter(), LevelFilter::OFF); + + let v = Verbosity::::default(); + assert_eq!(v.tracing_level(), Some(Level::ERROR)); + assert_eq!(v.tracing_level_filter(), LevelFilter::ERROR); + + let v = Verbosity::::default(); + assert_eq!(v.tracing_level(), Some(Level::WARN)); + assert_eq!(v.tracing_level_filter(), LevelFilter::WARN); + + let v = Verbosity::::default(); + assert_eq!(v.tracing_level(), Some(Level::INFO)); + assert_eq!(v.tracing_level_filter(), LevelFilter::INFO); + + let v = Verbosity::::default(); + assert_eq!(v.tracing_level(), Some(Level::DEBUG)); + assert_eq!(v.tracing_level_filter(), LevelFilter::DEBUG); + + let v = Verbosity::::default(); + assert_eq!(v.tracing_level(), Some(Level::TRACE)); + assert_eq!(v.tracing_level_filter(), LevelFilter::TRACE); + } +}