diff --git a/src/args.rs b/src/args.rs index 1b1cbaf..97c2262 100644 --- a/src/args.rs +++ b/src/args.rs @@ -4,12 +4,22 @@ use super::commands::Command; use super::error::Error; use clap::Parser; +use tracing::level_filters::LevelFilter; #[derive(Clone, Debug, Parser)] #[command(version, disable_help_subcommand = true)] pub struct Args { #[command(subcommand)] pub command: Command, + + /// Verbosity: 0-5 or a level name ("off", "error", "warn", "info", "debug" or "trace") + #[arg( + short = 'v', + long = "verbosity", + value_name = "level", + default_value_t = LevelFilter::from_level(tracing::Level::WARN), + )] + pub verbosity: LevelFilter, } impl Args { @@ -20,6 +30,9 @@ impl Args { impl From for Args { fn from(value: Command) -> Self { - Args { command: value } + Args { + command: value, + verbosity: LevelFilter::from_level(tracing::Level::WARN), + } } } diff --git a/src/bin/ldns.rs b/src/bin/ldns.rs index 4204530..30a2cd9 100644 --- a/src/bin/ldns.rs +++ b/src/bin/ldns.rs @@ -6,21 +6,37 @@ use std::process::ExitCode; +use dnst::env::Env; +use dnst::log::LogFormatter; use dnst::try_ldns_compatibility; +use tracing::level_filters::LevelFilter; fn main() -> ExitCode { let env = dnst::env::RealEnv; + run(env) +} + +fn run(env: impl Env) -> ExitCode { + let mut args = env.args_os(); + let argv0 = args.next().unwrap(); + let stderr = env.stderr(); + let subscriber = tracing_subscriber::FmtSubscriber::builder() + .with_ansi(stderr.is_terminal()) + .with_writer(stderr) + .with_max_level(LevelFilter::WARN) + .event_format(LogFormatter { + program: argv0.to_string_lossy().to_string(), + }); - let mut args = std::env::args_os(); - args.next().unwrap(); let args = try_ldns_compatibility(args).map(|args| args.expect("ldns commmand lacks ldns- prefix")); - - match args.and_then(|args| args.execute(&env)) { - Ok(()) => ExitCode::SUCCESS, - Err(err) => { - err.pretty_print(env); - ExitCode::FAILURE + tracing::subscriber::with_default(subscriber.finish(), || { + match args.and_then(|args| args.execute(&env)) { + Ok(()) => ExitCode::SUCCESS, + Err(err) => { + err.pretty_print(env); + ExitCode::FAILURE + } } - } + }) } diff --git a/src/commands/signzone.rs b/src/commands/signzone.rs index 29896c4..f4d4d88 100644 --- a/src/commands/signzone.rs +++ b/src/commands/signzone.rs @@ -1612,12 +1612,8 @@ impl SignZone { Self::write_iterations_warning(env, "NSEC3 iterations larger than 0 increases performance cost while providing only moderate protection!"); } - fn write_iterations_warning(env: &impl Env, text: &str) { - warn!("{text}"); - writeln!( - env.stderr(), - "See: https://www.rfc-editor.org/rfc/rfc9276.html" - ); + fn write_iterations_warning(_env: &impl Env, text: &str) { + warn!("{text}\nSee: https://www.rfc-editor.org/rfc/rfc9276.html"); } /// Create the ZONEMD digest for the SIMPLE scheme. diff --git a/src/error.rs b/src/error.rs index ea382a4..948d6a8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -74,11 +74,11 @@ impl Error { PrimaryError::Other(error) => error, }; - error!("{msg}"); - let mut err = env.stderr(); + let mut buf = String::new(); for context in &self.0.context { - writeln!(err, "... while {context}"); + buf.push_str(&format!("... while {context}\n")); } + error!("{msg}\n{buf}"); } pub fn exit_code(&self) -> u8 { diff --git a/src/lib.rs b/src/lib.rs index 4a15310..d9de7cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ use domain::base::zonefile_fmt::DisplayKind; use env::Env; use error::Error; use log::LogFormatter; +use tracing::level_filters::LevelFilter; pub use self::args::Args; @@ -99,22 +100,23 @@ fn parse_args(env: impl Env) -> Result { pub fn run(env: impl Env) -> u8 { let stderr = env.stderr(); - let subscriber = tracing_subscriber::FmtSubscriber::builder() + let mut subscriber = tracing_subscriber::FmtSubscriber::builder() .with_ansi(stderr.is_terminal()) .with_writer(stderr) + .with_max_level(LevelFilter::WARN) .event_format(LogFormatter { program: env.args_os().next().unwrap().to_string_lossy().to_string(), - }) - .finish(); - - tracing::subscriber::with_default(subscriber, || { - let res = parse_args(&env).and_then(|args| args.execute(&env)); - match res { - Ok(()) => 0, - Err(err) => { + }); + let res = parse_args(&env); + if let Ok(args) = &res { + subscriber = subscriber.with_max_level(args.verbosity); + } + tracing::subscriber::with_default(subscriber.finish(), || { + res.and_then(|args| args.execute(&env)) + .map(|()| 0) + .unwrap_or_else(|err| { err.pretty_print(&env); err.exit_code() - } - } + }) }) }