rush_sync_server/output/
logging.rs1use crate::commands::log_level::LogLevelManager;
3use crate::core::prelude::*;
4use log::{Level, Log, Metadata, Record};
5use once_cell::sync::Lazy;
6use std::sync::{Arc, Mutex};
7
8const MAX_LOG_BUFFER: usize = 1000;
9const DRAIN_COUNT: usize = 100;
10
11static LOG_MESSAGES: Lazy<Arc<Mutex<Vec<LogMessage>>>> =
12 Lazy::new(|| Arc::new(Mutex::new(Vec::new())));
13
14#[derive(Debug, Clone)]
15pub struct LogMessage {
16 pub level: Option<Level>,
17 pub message: String,
18}
19
20impl LogMessage {
21 pub fn new<L: Into<Option<Level>>, S: Into<String>>(level: L, message: S) -> Self {
22 Self {
23 level: level.into(),
24 message: message.into(),
25 }
26 }
27
28 pub fn formatted(&self) -> String {
30 match self.level {
31 Some(level) => format!("[{}] {}", level.to_string().to_uppercase(), self.message),
32 None => self.message.clone(),
33 }
34 }
35}
36
37pub struct AppLogger;
38
39impl AppLogger {
40 pub fn log(level: Level, message: impl Into<String>) {
41 let mut logs = LOG_MESSAGES.lock().unwrap_or_else(|poisoned| {
42 log::warn!("Recovered from poisoned mutex");
43 poisoned.into_inner()
44 });
45
46 if logs.len() >= MAX_LOG_BUFFER {
48 logs.drain(0..DRAIN_COUNT);
50
51 logs.push(LogMessage::new(
53 Some(Level::Warn),
54 format!(
55 "[SYSTEM] Dropped {} old log messages to prevent memory overflow",
56 DRAIN_COUNT
57 ),
58 ));
59 }
60
61 logs.push(LogMessage::new(Some(level), message));
62 }
63
64 pub fn log_plain(message: impl Into<String>) {
65 let mut logs = LOG_MESSAGES.lock().unwrap_or_else(|poisoned| {
66 log::warn!("Recovered from poisoned mutex");
67 poisoned.into_inner()
68 });
69
70 if logs.len() >= MAX_LOG_BUFFER {
72 logs.drain(0..DRAIN_COUNT);
73 }
74
75 logs.push(LogMessage::new(None, message));
76 }
77
78 pub fn get_messages() -> Result<Vec<LogMessage>> {
79 let mut logs = LOG_MESSAGES.lock().unwrap_or_else(|poisoned| {
80 log::warn!("Recovered from poisoned mutex");
81 poisoned.into_inner()
82 });
83 let msgs = logs.clone();
84 logs.clear();
85 Ok(msgs)
86 }
87}
88
89struct GlobalLogger;
91
92impl Log for GlobalLogger {
93 fn enabled(&self, metadata: &Metadata) -> bool {
94 metadata.level() <= Level::Trace
95 }
96
97 fn log(&self, record: &Record) {
98 AppLogger::log(record.level(), record.args().to_string());
100 }
101
102 fn flush(&self) {}
103}
104
105pub async fn init() -> Result<()> {
106 if log::set_boxed_logger(Box::new(GlobalLogger)).is_ok() {
107 let config_level = LogLevelManager::load_from_config().await;
109 LogLevelManager::init_with_level(config_level);
110 }
111 Ok(())
112}