1use std::env;
9
10use clap::Parser;
11use tracing::Level;
12use tracing::metadata::LevelFilter;
13use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
14
15fn get_levels(bin: &str, cli_level: Option<Level>) -> String {
16 let env_level = env::var("RUST_LOG").ok();
17
18 let Some(cli_level) = cli_level else {
19 return env_level.unwrap_or_default();
20 };
21
22 let level_str = format!(
23 "{bin}={level},hickory={level}",
24 level = cli_level.to_string().to_lowercase(),
25 );
26
27 match env_level {
28 Some(env_level) => format!("{level_str},{env_level}"),
29 None => level_str,
30 }
31}
32
33pub fn logger(bin: &str, cli_level: Option<Level>) {
39 let subscriber = EnvFilter::builder()
41 .with_default_directive(LevelFilter::OFF.into())
42 .parse(get_levels(bin, cli_level))
43 .expect("failed to configure tracing/logging");
44
45 tracing_subscriber::registry()
46 .with(tracing_subscriber::fmt::layer().compact())
47 .with(subscriber)
48 .init();
49}
50
51#[derive(Debug, Parser)]
53pub struct LogConfig {
54 #[clap(long)]
56 trace: bool,
57
58 #[clap(long)]
60 debug: bool,
61
62 #[clap(long)]
64 info: bool,
65
66 #[clap(long)]
68 warn: bool,
69
70 #[clap(long)]
72 error: bool,
73}
74
75impl LogConfig {
76 pub fn level(&self) -> Option<Level> {
77 Some(if self.trace {
78 Level::TRACE
79 } else if self.debug {
80 Level::DEBUG
81 } else if self.info {
82 Level::INFO
83 } else if self.warn {
84 Level::WARN
85 } else if self.error {
86 Level::ERROR
87 } else {
88 return None;
89 })
90 }
91}