Skip to main content

matrix_bot_sdk/
logging.rs

1use std::collections::HashSet;
2use std::sync::{Arc, RwLock};
3
4use tracing::Level;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
7pub enum LogLevel {
8    Trace = 0,
9    Debug = 1,
10    #[default]
11    Info = 2,
12    Warn = 3,
13    Error = 4,
14    Silent = 5,
15}
16
17pub trait ILogger: Send + Sync {
18    fn log(&self, level: Level, module: &str, message: &str);
19
20    fn trace(&self, module: &str, message: &str) {
21        self.log(Level::TRACE, module, message);
22    }
23
24    fn debug(&self, module: &str, message: &str) {
25        self.log(Level::DEBUG, module, message);
26    }
27
28    fn info(&self, module: &str, message: &str) {
29        self.log(Level::INFO, module, message);
30    }
31
32    fn warn(&self, module: &str, message: &str) {
33        self.log(Level::WARN, module, message);
34    }
35
36    fn error(&self, module: &str, message: &str) {
37        self.log(Level::ERROR, module, message);
38    }
39}
40
41#[derive(Default)]
42pub struct ConsoleLogger;
43
44impl ConsoleLogger {
45    pub fn new() -> Self {
46        Self
47    }
48}
49
50impl ILogger for ConsoleLogger {
51    fn log(&self, level: Level, module: &str, message: &str) {
52        match level {
53            Level::TRACE => tracing::trace!("[{module}] {message}"),
54            Level::DEBUG => tracing::debug!("[{module}] {message}"),
55            Level::INFO => tracing::info!("[{module}] {message}"),
56            Level::WARN => tracing::warn!("[{module}] {message}"),
57            Level::ERROR => tracing::error!("[{module}] {message}"),
58        }
59    }
60}
61
62#[derive(Default)]
63pub struct RichConsoleLogger;
64
65impl RichConsoleLogger {
66    pub fn new() -> Self {
67        Self
68    }
69}
70
71impl ILogger for RichConsoleLogger {
72    fn log(&self, level: Level, module: &str, message: &str) {
73        let (prefix, color) = match level {
74            Level::TRACE => ("TRACE", "\x1b[90m"),
75            Level::DEBUG => ("DEBUG", "\x1b[36m"),
76            Level::INFO => ("INFO ", "\x1b[32m"),
77            Level::WARN => ("WARN ", "\x1b[33m"),
78            Level::ERROR => ("ERROR", "\x1b[31m"),
79        };
80        println!("{color}[{prefix}] [{module}] {message}\x1b[0m");
81    }
82}
83
84#[derive(Clone)]
85pub struct LogService {
86    logger: Arc<dyn ILogger>,
87    level: Arc<RwLock<LogLevel>>,
88    muted_modules: Arc<RwLock<HashSet<String>>>,
89}
90
91impl LogService {
92    pub fn new(logger: Arc<dyn ILogger>) -> Self {
93        Self {
94            logger,
95            level: Arc::new(RwLock::new(LogLevel::default())),
96            muted_modules: Arc::new(RwLock::new(HashSet::new())),
97        }
98    }
99
100    pub fn logger(&self) -> Arc<dyn ILogger> {
101        Arc::clone(&self.logger)
102    }
103
104    pub fn set_level(&self, level: LogLevel) {
105        *self.level.write().unwrap() = level;
106    }
107
108    pub fn level(&self) -> LogLevel {
109        *self.level.read().unwrap()
110    }
111
112    pub fn mute_module(&self, module: &str) {
113        self.muted_modules
114            .write()
115            .unwrap()
116            .insert(module.to_owned());
117    }
118
119    pub fn unmute_module(&self, module: &str) {
120        self.muted_modules.write().unwrap().remove(module);
121    }
122
123    pub fn is_muted(&self, module: &str) -> bool {
124        self.muted_modules.read().unwrap().contains(module)
125    }
126
127    fn should_log(&self, level: LogLevel, module: &str) -> bool {
128        if self.is_muted(module) {
129            return false;
130        }
131        let current_level = self.level();
132        level >= current_level
133    }
134
135    pub fn trace(&self, module: &str, message: &str) {
136        if self.should_log(LogLevel::Trace, module) {
137            self.logger.trace(module, message);
138        }
139    }
140
141    pub fn debug(&self, module: &str, message: &str) {
142        if self.should_log(LogLevel::Debug, module) {
143            self.logger.debug(module, message);
144        }
145    }
146
147    pub fn info(&self, module: &str, message: &str) {
148        if self.should_log(LogLevel::Info, module) {
149            self.logger.info(module, message);
150        }
151    }
152
153    pub fn warn(&self, module: &str, message: &str) {
154        if self.should_log(LogLevel::Warn, module) {
155            self.logger.warn(module, message);
156        }
157    }
158
159    pub fn error(&self, module: &str, message: &str) {
160        if self.should_log(LogLevel::Error, module) {
161            self.logger.error(module, message);
162        }
163    }
164}