rush_sync_server/commands/log_level/
manager.rs1use log::LevelFilter;
2use std::sync::Mutex;
3
4pub struct LogLevelManager;
6
7static CURRENT_LOG_LEVEL: Mutex<LevelFilter> = Mutex::new(LevelFilter::Info);
9
10impl LogLevelManager {
11 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 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 Self::set_level_runtime(level_filter);
49
50 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 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 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 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 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 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 pub fn show_help() -> String {
132 crate::i18n::get_command_translation("system.commands.log_level.help", &[])
133 }
134
135 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 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 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 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}