Skip to main content

mega_evme/common/
logging.rs

1//! Logging configuration for the mega-evme CLI tool.
2//!
3//! Provides CLI arguments for configuring tracing/logging output with support for:
4//! - Verbosity levels via `-v/-vv/-vvv` flags
5//! - Custom log filters via `RUST_LOG` environment variable
6//! - Log file output via `--log.file` flag
7//! - Colorful console output via `--log.color` flag
8
9use std::path::PathBuf;
10
11use clap::Parser;
12use tracing::Level;
13use tracing_subscriber::{fmt, EnvFilter};
14
15/// Logging configuration arguments.
16#[derive(Debug, Clone, Default, Parser)]
17pub struct LogArgs {
18    /// Increase logging verbosity (-v = error, -vv = warn, -vvv = info, -vvvv = debug, -vvvvv =
19    /// trace)
20    #[arg(short = 'v', action = clap::ArgAction::Count, global = true)]
21    pub verbose: u8,
22
23    /// Log file path. If specified, logs are written to this file instead of stderr.
24    #[arg(long = "log.file", visible_aliases = ["log-file"], global = true)]
25    pub log_file: Option<PathBuf>,
26
27    /// Disable colorful console logging. Only applies when logging to stderr (no --log.file).
28    #[arg(long = "log.no-color", visible_aliases = ["log-no-color"], global = true)]
29    pub log_no_color: bool,
30}
31
32impl LogArgs {
33    /// Initialize the tracing subscriber based on the logging configuration.
34    ///
35    /// The log level is determined in the following order of precedence:
36    /// 1. `RUST_LOG` environment variable (if set)
37    /// 2. `-v` flags (increases from ERROR to WARN/INFO/DEBUG/TRACE)
38    /// 3. Default is no logging (OFF)
39    ///
40    /// Log target is only shown for DEBUG level and above.
41    /// If `--log.file` is specified, logs are written to the file instead of stderr.
42    pub fn init(&self) {
43        let filter = if std::env::var("RUST_LOG").is_ok() {
44            // Use RUST_LOG if set
45            EnvFilter::from_default_env()
46        } else if self.verbose == 0 {
47            // No verbosity: no logs
48            EnvFilter::new("off")
49        } else {
50            // Verbosity-based level
51            let level = match self.verbose {
52                1 => Level::ERROR,
53                2 => Level::WARN,
54                3 => Level::INFO,
55                4 => Level::DEBUG,
56                _ => Level::TRACE,
57            };
58            EnvFilter::new(format!("mega_evme={level},mega_evm={level}"))
59        };
60
61        // Show target only for DEBUG level and above (verbose >= 4)
62        let show_target = self.verbose >= 4;
63
64        if let Some(ref log_file) = self.log_file {
65            // Write logs to file (always without ANSI colors)
66            match std::fs::File::create(log_file) {
67                Ok(file) => {
68                    fmt()
69                        .with_env_filter(filter)
70                        .with_target(show_target)
71                        .with_writer(file)
72                        .with_ansi(false)
73                        .init();
74                }
75                Err(e) => {
76                    eprintln!("Failed to create log file '{}': {}", log_file.display(), e);
77                    fmt()
78                        .with_env_filter(filter)
79                        .with_target(show_target)
80                        .with_writer(std::io::stderr)
81                        .with_ansi(!self.log_no_color)
82                        .init();
83                }
84            }
85        } else {
86            // Write logs to stderr
87            fmt()
88                .with_env_filter(filter)
89                .with_target(show_target)
90                .with_writer(std::io::stderr)
91                .with_ansi(!self.log_no_color)
92                .init();
93        }
94    }
95}