rush_sync_server/commands/log_level/
manager.rs

1use log::LevelFilter;
2use std::sync::Mutex;
3
4/// Globaler Log-Level Manager für Runtime-Änderungen + Persistenz
5pub struct LogLevelManager;
6
7// Globaler STATE für aktuelles Log-Level
8static CURRENT_LOG_LEVEL: Mutex<LevelFilter> = Mutex::new(LevelFilter::Info);
9
10impl LogLevelManager {
11    /// Zeigt aktuelles Log-Level und verfügbare Optionen
12    pub fn show_status() -> String {
13        let current = Self::get_current_level();
14        let current_name = Self::level_to_name(current);
15        let current_number = Self::level_to_number(current);
16
17        format!(
18            "{}: {} ({})\n{}",
19            crate::i18n::get_command_translation("system.commands.log_level.current", &[]),
20            current_name,
21            current_number,
22            Self::show_help()
23        )
24    }
25
26    /// Setzt neues Log-Level UND speichert in Config
27    pub fn set_level_persistent(level_input: &str) -> Result<String, String> {
28        let level_filter = match level_input {
29            "1" => LevelFilter::Error,
30            "2" => LevelFilter::Warn,
31            "3" => LevelFilter::Info,
32            "4" => LevelFilter::Debug,
33            "5" => LevelFilter::Trace,
34            "error" | "ERROR" => LevelFilter::Error,
35            "warn" | "WARN" | "warning" => LevelFilter::Warn,
36            "info" | "INFO" => LevelFilter::Info,
37            "debug" | "DEBUG" => LevelFilter::Debug,
38            "trace" | "TRACE" => LevelFilter::Trace,
39            _ => {
40                return Err(crate::i18n::get_command_translation(
41                    "system.commands.log_level.invalid",
42                    &[level_input],
43                ));
44            }
45        };
46
47        // ✅ 1. SETZE RUNTIME LOG-LEVEL sofort
48        Self::set_level_runtime(level_filter);
49
50        // ✅ 2. SPAWN BACKGROUND-TASK für Config-Save
51        tokio::spawn(async move {
52            if let Err(e) = Self::save_to_config(level_filter).await {
53                log::warn!("Failed to save log level to config: {}", e);
54            } else {
55                log::debug!("Log level saved to config successfully");
56            }
57        });
58
59        let level_name = Self::level_to_name(level_filter);
60        let level_number = Self::level_to_number(level_filter);
61
62        Ok(crate::i18n::get_command_translation(
63            "system.commands.log_level.changed_persistent",
64            &[&level_name, &level_number],
65        ))
66    }
67
68    /// Setzt nur Runtime Log-Level (ohne Config-Save)
69    pub fn set_level_runtime(level_filter: LevelFilter) {
70        if let Ok(mut current) = CURRENT_LOG_LEVEL.lock() {
71            *current = level_filter;
72        }
73        log::set_max_level(level_filter);
74    }
75
76    /// Lädt Log-Level aus Config beim Startup
77    pub async fn load_from_config() -> LevelFilter {
78        match crate::core::config::Config::load_with_messages(false).await {
79            Ok(config) => match Self::string_to_level_filter(&config.log_level) {
80                Ok(level) => {
81                    log::debug!("Log level loaded from config: {}", config.log_level);
82                    level
83                }
84                Err(_) => {
85                    log::warn!(
86                        "Invalid log level in config: '{}', using INFO",
87                        config.log_level
88                    );
89                    LevelFilter::Info
90                }
91            },
92            Err(_) => {
93                log::debug!("No config found, using default log level: INFO");
94                LevelFilter::Info
95            }
96        }
97    }
98
99    /// Speichert Log-Level in Config-Datei
100    async fn save_to_config(level_filter: LevelFilter) -> Result<(), String> {
101        match crate::core::config::Config::load_with_messages(false).await {
102            Ok(mut config) => {
103                config.log_level = Self::level_filter_to_string(level_filter);
104                config
105                    .save()
106                    .await
107                    .map_err(|e| format!("Config save error: {}", e))
108            }
109            Err(e) => Err(format!("Config load error: {}", e)),
110        }
111    }
112
113    /// Aktuelles Log-Level abrufen
114    pub fn get_current_level() -> LevelFilter {
115        if let Ok(current) = CURRENT_LOG_LEVEL.lock() {
116            *current
117        } else {
118            log::max_level()
119        }
120    }
121
122    /// Initialisiert Log-Level (für startup)
123    pub fn init_with_level(level: LevelFilter) {
124        if let Ok(mut current) = CURRENT_LOG_LEVEL.lock() {
125            *current = level;
126        }
127        log::set_max_level(level);
128    }
129
130    /// Hilfe-Text
131    pub fn show_help() -> String {
132        crate::i18n::get_command_translation("system.commands.log_level.help", &[])
133    }
134
135    // ✅ HELPER: String zu LevelFilter
136    fn string_to_level_filter(s: &str) -> Result<LevelFilter, ()> {
137        match s.to_lowercase().as_str() {
138            "error" | "1" => Ok(LevelFilter::Error),
139            "warn" | "warning" | "2" => Ok(LevelFilter::Warn),
140            "info" | "3" => Ok(LevelFilter::Info),
141            "debug" | "4" => Ok(LevelFilter::Debug),
142            "trace" | "5" => Ok(LevelFilter::Trace),
143            "off" | "0" => Ok(LevelFilter::Off),
144            _ => Err(()),
145        }
146    }
147
148    // ✅ HELPER: LevelFilter zu String
149    fn level_filter_to_string(level: LevelFilter) -> String {
150        match level {
151            LevelFilter::Error => "error".to_string(),
152            LevelFilter::Warn => "warn".to_string(),
153            LevelFilter::Info => "info".to_string(),
154            LevelFilter::Debug => "debug".to_string(),
155            LevelFilter::Trace => "trace".to_string(),
156            LevelFilter::Off => "off".to_string(),
157        }
158    }
159
160    // ✅ HELPER: Level zu Name (Display)
161    fn level_to_name(level: LevelFilter) -> String {
162        match level {
163            LevelFilter::Error => "ERROR".to_string(),
164            LevelFilter::Warn => "WARN".to_string(),
165            LevelFilter::Info => "INFO".to_string(),
166            LevelFilter::Debug => "DEBUG".to_string(),
167            LevelFilter::Trace => "TRACE".to_string(),
168            LevelFilter::Off => "OFF".to_string(),
169        }
170    }
171
172    // ✅ HELPER: Level zu Nummer
173    fn level_to_number(level: LevelFilter) -> String {
174        match level {
175            LevelFilter::Error => "1".to_string(),
176            LevelFilter::Warn => "2".to_string(),
177            LevelFilter::Info => "3".to_string(),
178            LevelFilter::Debug => "4".to_string(),
179            LevelFilter::Trace => "5".to_string(),
180            LevelFilter::Off => "0".to_string(),
181        }
182    }
183}