1use crate::handler::Handler;
2use crate::types::Level;
3use chrono::Local;
4use std::collections::HashMap;
5use std::error::Error;
6use std::sync::OnceLock;
7use std::sync::atomic::{AtomicU8, Ordering};
8use std::sync::{Arc, Mutex, RwLock};
9use std::thread;
10
11type Handlers = RwLock<Vec<Arc<dyn Handler>>>;
12
13static LOGGERS: OnceLock<Mutex<HashMap<String, Arc<Logger>>>> = OnceLock::new();
15fn loggers() -> &'static Mutex<HashMap<String, Arc<Logger>>> {
16 LOGGERS.get_or_init(|| Mutex::new(HashMap::new()))
17}
18
19pub struct Logger {
28 name: &'static str,
29 handlers: Handlers,
30 level: AtomicU8,
31}
32
33static ROOT_LOGGER_NAME: &str = "root";
34static ROOT_LOGGER: OnceLock<Arc<Logger>> = OnceLock::new();
35
36impl Logger {
37 pub fn new(name: &'static str) -> Self {
41 if name == ROOT_LOGGER_NAME {
42 Self {
43 name: ROOT_LOGGER_NAME,
44 handlers: RwLock::new(Vec::new()),
45 level: AtomicU8::new(Level::Info as u8),
46 }
47 } else {
48 Self {
49 name,
50 handlers: RwLock::new(Self::root().handlers()),
51 level: AtomicU8::new(Self::root().level() as u8),
52 }
53 }
54 }
55
56 pub fn get(name: &'static str) -> Arc<Self> {
59 let mut loggers = loggers().lock().unwrap();
60 loggers
61 .entry(name.to_string())
62 .or_insert_with(|| Arc::new(Logger::new(name)))
63 .clone()
64 }
65
66 pub fn root() -> Arc<Self> {
69 ROOT_LOGGER
70 .get_or_init(|| Arc::new(Self::new(ROOT_LOGGER_NAME)))
71 .clone()
72 }
73
74 pub fn handlers(&self) -> Vec<Arc<dyn Handler>> {
76 self.handlers.read().unwrap().clone()
77 }
78
79 pub fn set_level(&self, level: Level) {
81 self.level.store(level as u8, Ordering::Relaxed);
82 }
83
84 pub fn level(&self) -> Level {
86 Level::from_u8(self.level.load(Ordering::Relaxed))
87 }
88
89 pub fn add_handler(&self, handler: impl Handler + 'static) -> Result<(), Box<dyn Error>> {
92 self.handlers
93 .write()
94 .map_err(|_| "Handlers mutex was poisoned")?
95 .push(Arc::new(handler));
96 Ok(())
97 }
98
99 pub fn log(&self, level: Level, message: &str) {
103 if level.to_u8() < self.level.load(Ordering::Relaxed) {
104 return;
105 }
106 let handlers = self
107 .handlers
108 .read()
109 .unwrap_or_else(|poisoned| poisoned.into_inner());
110 for handler in handlers.iter() {
111 let formatter = handler.formatter();
112 handler.handle(&HashMap::from([
113 ("message", message),
114 ("level", level.to_str()),
115 (
116 "timestamp",
117 Local::now()
118 .format(formatter.time_format)
119 .to_string()
120 .as_str(),
121 ),
122 ("name", self.name),
123 ("thread", thread::current().name().unwrap_or("unknown")),
124 ]));
125 }
126 }
127
128 pub fn debug(&self, message: &str) {
130 self.log(Level::Debug, message)
131 }
132
133 pub fn info(&self, message: &str) {
135 self.log(Level::Info, message)
136 }
137
138 pub fn warning(&self, message: &str) {
140 self.log(Level::Warning, message)
141 }
142
143 pub fn error(&self, message: &str) {
145 self.log(Level::Error, message)
146 }
147
148 pub fn critical(&self, message: &str) {
150 self.log(Level::Critical, message)
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157 use crate::handler::StreamHandler;
158 use std::io::Write;
159 use std::sync::Arc;
160
161 #[derive(Clone)]
162 struct SharedBuf(Arc<Mutex<Vec<u8>>>);
163
164 impl Write for SharedBuf {
165 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
166 self.0.lock().unwrap().extend_from_slice(buf);
167 Ok(buf.len())
168 }
169 fn flush(&mut self) -> std::io::Result<()> {
170 Ok(())
171 }
172 }
173
174 static REGISTRY_LOCK: Mutex<()> = Mutex::new(());
200
201 struct RegistryGuard {
202 _lock: std::sync::MutexGuard<'static, ()>,
205 saved_map: HashMap<String, Arc<Logger>>,
206 saved_root_level: Level,
207 saved_root_handlers: Vec<Arc<dyn Handler>>,
208 }
209
210 impl RegistryGuard {
211 fn acquire() -> Self {
212 let lock = REGISTRY_LOCK
215 .lock()
216 .unwrap_or_else(|poisoned| poisoned.into_inner());
217
218 let saved_map = loggers().lock().unwrap().clone();
219 let root = Logger::root();
220 let guard = Self {
221 _lock: lock,
222 saved_map,
223 saved_root_level: root.level(),
224 saved_root_handlers: root.handlers(),
225 };
226 loggers().lock().unwrap().clear();
228 root.set_level(Level::Info);
229 *root.handlers.write().unwrap() = Vec::new();
230 guard
231 }
232 }
233
234 impl Drop for RegistryGuard {
235 fn drop(&mut self) {
236 *loggers().lock().unwrap() = std::mem::take(&mut self.saved_map);
238 let root = Logger::root();
239 root.set_level(self.saved_root_level);
240 *root.handlers.write().unwrap() = std::mem::take(&mut self.saved_root_handlers);
241 }
242 }
243
244 #[test]
245 fn get_returns_the_same_cached_instance() {
246 let _guard = RegistryGuard::acquire();
247
248 let first = Logger::get("cached");
249 let second = Logger::get("cached");
250 assert!(Arc::ptr_eq(&first, &second));
252 }
253
254 #[test]
255 fn child_inherits_root_level_at_creation() {
256 let _guard = RegistryGuard::acquire();
257
258 Logger::root().set_level(Level::Error);
259 let child = Logger::new("child_level");
261 assert_eq!(child.level(), Level::Error);
262 }
263
264 #[test]
265 fn child_inherits_root_handlers_at_creation() {
266 let _guard = RegistryGuard::acquire();
267
268 let buf = Arc::new(Mutex::new(Vec::new()));
269 Logger::root()
270 .add_handler(StreamHandler::with_pattern(
271 SharedBuf(buf.clone()),
272 "%(message)",
273 ))
274 .unwrap();
275
276 let child = Logger::new("child_handlers");
278 child.set_level(Level::Debug);
279 child.info("via inherited handler");
280
281 let written = String::from_utf8(buf.lock().unwrap().clone()).unwrap();
282 assert_eq!(written, "via inherited handler\n");
283 }
284
285 #[test]
286 fn level_get_set_round_trips() {
287 let _guard = RegistryGuard::acquire();
290
291 let logger = Logger::new("test_level");
292 logger.set_level(Level::Error);
293 assert_eq!(logger.level(), Level::Error);
294 }
295
296 #[test]
297 fn messages_below_level_are_dropped() {
298 let _guard = RegistryGuard::acquire();
299
300 let buf = Arc::new(Mutex::new(Vec::new()));
301 let logger = Logger::new("test_filter");
302 logger.set_level(Level::Warning);
303 logger
304 .add_handler(StreamHandler::with_pattern(
305 SharedBuf(buf.clone()),
306 "%(message)",
307 ))
308 .unwrap();
309
310 logger.info("dropped"); logger.warning("kept"); let written = String::from_utf8(buf.lock().unwrap().clone()).unwrap();
314 assert_eq!(written, "kept\n");
315 }
316
317 #[test]
318 fn record_includes_level_and_message() {
319 let _guard = RegistryGuard::acquire();
320
321 let buf = Arc::new(Mutex::new(Vec::new()));
322 let logger = Logger::new("test_record");
323 logger.set_level(Level::Debug);
324 logger
325 .add_handler(StreamHandler::with_pattern(
326 SharedBuf(buf.clone()),
327 "%(level) %(name) %(message)",
328 ))
329 .unwrap();
330
331 logger.error("boom");
332
333 let written = String::from_utf8(buf.lock().unwrap().clone()).unwrap();
334 assert_eq!(written, "ERROR test_record boom\n");
335 }
336}