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 }
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) => level,
69 Err(_) => {
70 log::warn!(
71 "Invalid log level in config: '{}', using INFO",
72 config.log_level
73 );
74 LevelFilter::Info
75 }
76 },
77 Err(_) => LevelFilter::Info,
78 }
79 }
80
81 async fn save_to_config(level_filter: LevelFilter) -> Result<(), String> {
82 match crate::core::config::Config::load_with_messages(false).await {
83 Ok(mut config) => {
84 config.log_level = Self::level_filter_to_string(level_filter);
85 config
86 .save()
87 .await
88 .map_err(|e| format!("Config save error: {}", e))
89 }
90 Err(e) => Err(format!("Config load error: {}", e)),
91 }
92 }
93
94 pub fn get_current_level() -> LevelFilter {
95 if let Ok(current) = CURRENT_LOG_LEVEL.lock() {
96 *current
97 } else {
98 log::max_level()
99 }
100 }
101
102 pub fn init_with_level(level: LevelFilter) {
103 if let Ok(mut current) = CURRENT_LOG_LEVEL.lock() {
104 *current = level;
105 }
106 log::set_max_level(level);
107 }
108
109 pub fn show_help() -> String {
110 "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()
111 }
112
113 fn string_to_level_filter(s: &str) -> Result<LevelFilter, ()> {
114 match s.to_lowercase().as_str() {
115 "error" | "1" => Ok(LevelFilter::Error),
116 "warn" | "warning" | "2" => Ok(LevelFilter::Warn),
117 "info" | "3" => Ok(LevelFilter::Info),
118 "debug" | "4" => Ok(LevelFilter::Debug),
119 "trace" | "5" => Ok(LevelFilter::Trace),
120 "off" | "0" => Ok(LevelFilter::Off),
121 _ => Err(()),
122 }
123 }
124
125 fn level_filter_to_string(level: LevelFilter) -> String {
126 match level {
127 LevelFilter::Error => "error".to_string(),
128 LevelFilter::Warn => "warn".to_string(),
129 LevelFilter::Info => "info".to_string(),
130 LevelFilter::Debug => "debug".to_string(),
131 LevelFilter::Trace => "trace".to_string(),
132 LevelFilter::Off => "off".to_string(),
133 }
134 }
135
136 fn level_to_name(level: LevelFilter) -> String {
137 match level {
138 LevelFilter::Error => "ERROR".to_string(),
139 LevelFilter::Warn => "WARN".to_string(),
140 LevelFilter::Info => "INFO".to_string(),
141 LevelFilter::Debug => "DEBUG".to_string(),
142 LevelFilter::Trace => "TRACE".to_string(),
143 LevelFilter::Off => "OFF".to_string(),
144 }
145 }
146
147 fn level_to_number(level: LevelFilter) -> String {
148 match level {
149 LevelFilter::Error => "1".to_string(),
150 LevelFilter::Warn => "2".to_string(),
151 LevelFilter::Info => "3".to_string(),
152 LevelFilter::Debug => "4".to_string(),
153 LevelFilter::Trace => "5".to_string(),
154 LevelFilter::Off => "0".to_string(),
155 }
156 }
157}