rush_sync_server/commands/log_level/
manager.rs1use 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}