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}