rush_sync_server/commands/log_level/
manager.rs

1use log::LevelFilter;
2use std::sync::Mutex;
3
4pub struct LogLevelManager;
5
6static CURRENT_LOG_LEVEL: Mutex<LevelFilter> = Mutex::new(LevelFilter::Info);
7
8impl LogLevelManager {
9    pub fn show_status() -> String {
10        let current = Self::get_current_level();
11        let current_name = Self::level_to_name(current);
12        let current_number = Self::level_to_number(current);
13
14        format!(
15            "Current log level: {} ({})\n{}",
16            current_name,
17            current_number,
18            Self::show_help()
19        )
20    }
21
22    pub fn set_level_persistent(level_input: &str) -> Result<String, String> {
23        let level_filter = match level_input {
24            "1" => LevelFilter::Error,
25            "2" => LevelFilter::Warn,
26            "3" => LevelFilter::Info,
27            "4" => LevelFilter::Debug,
28            "5" => LevelFilter::Trace,
29            "error" | "ERROR" => LevelFilter::Error,
30            "warn" | "WARN" | "warning" => LevelFilter::Warn,
31            "info" | "INFO" => LevelFilter::Info,
32            "debug" | "DEBUG" => LevelFilter::Debug,
33            "trace" | "TRACE" => LevelFilter::Trace,
34            _ => {
35                return Err(format!("Invalid log level: {}", level_input));
36            }
37        };
38
39        Self::set_level_runtime(level_filter);
40
41        tokio::spawn(async move {
42            if let Err(e) = Self::save_to_config(level_filter).await {
43                log::warn!("Failed to save log level to config: {}", e);
44            } else {
45                log::debug!("Log level saved to config successfully");
46            }
47        });
48
49        let level_name = Self::level_to_name(level_filter);
50        let level_number = Self::level_to_number(level_filter);
51
52        Ok(format!(
53            "✅ Log level changed to: {} ({}) - Persistent saved",
54            level_name, level_number
55        ))
56    }
57
58    pub fn set_level_runtime(level_filter: LevelFilter) {
59        if let Ok(mut current) = CURRENT_LOG_LEVEL.lock() {
60            *current = level_filter;
61        }
62        log::set_max_level(level_filter);
63    }
64
65    pub async fn load_from_config() -> LevelFilter {
66        match crate::core::config::Config::load_with_messages(false).await {
67            Ok(config) => match Self::string_to_level_filter(&config.log_level) {
68                Ok(level) => {
69                    log::debug!("Log level loaded from config: {}", config.log_level);
70                    level
71                }
72                Err(_) => {
73                    log::warn!(
74                        "Invalid log level in config: '{}', using INFO",
75                        config.log_level
76                    );
77                    LevelFilter::Info
78                }
79            },
80            Err(_) => {
81                log::debug!("No config found, using default log level: INFO");
82                LevelFilter::Info
83            }
84        }
85    }
86
87    async fn save_to_config(level_filter: LevelFilter) -> Result<(), String> {
88        match crate::core::config::Config::load_with_messages(false).await {
89            Ok(mut config) => {
90                config.log_level = Self::level_filter_to_string(level_filter);
91                config
92                    .save()
93                    .await
94                    .map_err(|e| format!("Config save error: {}", e))
95            }
96            Err(e) => Err(format!("Config load error: {}", e)),
97        }
98    }
99
100    pub fn get_current_level() -> LevelFilter {
101        if let Ok(current) = CURRENT_LOG_LEVEL.lock() {
102            *current
103        } else {
104            log::max_level()
105        }
106    }
107
108    pub fn init_with_level(level: LevelFilter) {
109        if let Ok(mut current) = CURRENT_LOG_LEVEL.lock() {
110            *current = level;
111        }
112        log::set_max_level(level);
113    }
114
115    pub fn show_help() -> String {
116        "Available log levels:\n  1 = ERROR   (Only critical errors)\n  2 = WARN    (Warnings and errors)\n  3 = INFO    (General information) [DEFAULT]\n  4 = DEBUG   (Debug information)\n  5 = TRACE   (Very detailed tracing)\n\nUsage:\n  log-level           Show current level\n  log-level 3         Set to INFO level\n  log-level DEBUG     Set to DEBUG level\n  log-level -h        Show this help".to_string()
117    }
118
119    fn string_to_level_filter(s: &str) -> Result<LevelFilter, ()> {
120        match s.to_lowercase().as_str() {
121            "error" | "1" => Ok(LevelFilter::Error),
122            "warn" | "warning" | "2" => Ok(LevelFilter::Warn),
123            "info" | "3" => Ok(LevelFilter::Info),
124            "debug" | "4" => Ok(LevelFilter::Debug),
125            "trace" | "5" => Ok(LevelFilter::Trace),
126            "off" | "0" => Ok(LevelFilter::Off),
127            _ => Err(()),
128        }
129    }
130
131    fn level_filter_to_string(level: LevelFilter) -> String {
132        match level {
133            LevelFilter::Error => "error".to_string(),
134            LevelFilter::Warn => "warn".to_string(),
135            LevelFilter::Info => "info".to_string(),
136            LevelFilter::Debug => "debug".to_string(),
137            LevelFilter::Trace => "trace".to_string(),
138            LevelFilter::Off => "off".to_string(),
139        }
140    }
141
142    fn level_to_name(level: LevelFilter) -> String {
143        match level {
144            LevelFilter::Error => "ERROR".to_string(),
145            LevelFilter::Warn => "WARN".to_string(),
146            LevelFilter::Info => "INFO".to_string(),
147            LevelFilter::Debug => "DEBUG".to_string(),
148            LevelFilter::Trace => "TRACE".to_string(),
149            LevelFilter::Off => "OFF".to_string(),
150        }
151    }
152
153    fn level_to_number(level: LevelFilter) -> String {
154        match level {
155            LevelFilter::Error => "1".to_string(),
156            LevelFilter::Warn => "2".to_string(),
157            LevelFilter::Info => "3".to_string(),
158            LevelFilter::Debug => "4".to_string(),
159            LevelFilter::Trace => "5".to_string(),
160            LevelFilter::Off => "0".to_string(),
161        }
162    }
163}