rust_loguru/handler/
mod.rs

1use parking_lot::RwLock;
2use std::fmt;
3use std::sync::Arc;
4
5use crate::formatters::Formatter;
6use crate::level::LogLevel;
7use crate::record::Record;
8
9pub type HandlerFilter = Arc<dyn Fn(&Record) -> bool + Send + Sync>;
10
11/// A trait for handlers that handle log records
12pub trait Handler: Send + Sync + fmt::Debug {
13    /// Get the log level
14    fn level(&self) -> LogLevel;
15
16    /// Set the log level
17    fn set_level(&mut self, level: LogLevel);
18
19    /// Check if the handler is enabled
20    fn is_enabled(&self) -> bool;
21
22    /// Set whether the handler is enabled
23    fn set_enabled(&mut self, enabled: bool);
24
25    /// Get the formatter
26    fn formatter(&self) -> &Formatter;
27
28    /// Set the formatter
29    fn set_formatter(&mut self, formatter: Formatter);
30
31    /// Set a filter closure for this handler (optional, default: no filter)
32    fn set_filter(&mut self, filter: Option<HandlerFilter>);
33
34    /// Get the filter closure for this handler (optional)
35    fn filter(&self) -> Option<&HandlerFilter>;
36
37    /// Handle a log record
38    fn handle(&self, record: &Record) -> Result<(), String>;
39
40    /// Handle a batch of log records (default: call handle for each)
41    fn handle_batch(&self, records: &[Record]) -> Result<(), String> {
42        for record in records {
43            self.handle(record)?;
44        }
45        Ok(())
46    }
47
48    /// Lifecycle: initialize the handler (default: no-op)
49    fn init(&mut self) -> Result<(), String> {
50        Ok(())
51    }
52    /// Lifecycle: flush the handler (default: no-op)
53    fn flush(&self) -> Result<(), String> {
54        Ok(())
55    }
56    /// Lifecycle: shutdown the handler (default: no-op)
57    fn shutdown(&mut self) -> Result<(), String> {
58        Ok(())
59    }
60}
61
62/// A handler that does nothing
63pub struct NullHandler {
64    /// The log level
65    level: LogLevel,
66    /// Whether the handler is enabled
67    enabled: bool,
68    /// The formatter to use
69    formatter: Formatter,
70    /// Optional filter closure
71    filter: Option<HandlerFilter>,
72}
73
74impl Default for NullHandler {
75    fn default() -> Self {
76        Self {
77            level: LogLevel::Info,
78            enabled: true,
79            formatter: Formatter::text(),
80            filter: None,
81        }
82    }
83}
84
85impl Handler for NullHandler {
86    fn level(&self) -> LogLevel {
87        self.level
88    }
89
90    fn set_level(&mut self, level: LogLevel) {
91        self.level = level;
92    }
93
94    fn is_enabled(&self) -> bool {
95        self.enabled
96    }
97
98    fn set_enabled(&mut self, enabled: bool) {
99        self.enabled = enabled;
100    }
101
102    fn formatter(&self) -> &Formatter {
103        &self.formatter
104    }
105
106    fn set_formatter(&mut self, formatter: Formatter) {
107        self.formatter = formatter;
108    }
109
110    fn set_filter(&mut self, filter: Option<HandlerFilter>) {
111        self.filter = filter;
112    }
113
114    fn filter(&self) -> Option<&HandlerFilter> {
115        self.filter.as_ref()
116    }
117
118    fn handle(&self, _record: &Record) -> Result<(), String> {
119        Ok(())
120    }
121}
122
123impl NullHandler {
124    pub fn new(level: LogLevel) -> Self {
125        Self {
126            level,
127            enabled: true,
128            formatter: Formatter::text(),
129            filter: None,
130        }
131    }
132}
133
134impl fmt::Debug for NullHandler {
135    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136        f.debug_struct("NullHandler")
137            .field("level", &self.level)
138            .field("enabled", &self.enabled)
139            .field("formatter", &self.formatter)
140            .finish()
141    }
142}
143
144pub mod console;
145pub mod file;
146pub mod network;
147
148/// A type alias for a thread-safe handler reference.
149pub type HandlerRef = Arc<RwLock<dyn Handler>>;
150
151/// Creates a new handler reference from a handler.
152pub fn new_handler_ref<H: Handler + 'static>(handler: H) -> HandlerRef {
153    Arc::new(RwLock::new(handler))
154}
155
156/// Base handler implementation
157pub struct BaseHandler {
158    /// The log level
159    level: LogLevel,
160    /// Whether the handler is enabled
161    enabled: bool,
162    /// The formatter
163    formatter: Formatter,
164    /// Optional filter closure
165    filter: Option<HandlerFilter>,
166}
167
168impl BaseHandler {
169    /// Create a new handler
170    pub fn new(level: LogLevel) -> Self {
171        Self {
172            level,
173            enabled: true,
174            formatter: Formatter::text(),
175            filter: None,
176        }
177    }
178}
179
180impl Handler for BaseHandler {
181    fn level(&self) -> LogLevel {
182        self.level
183    }
184
185    fn set_level(&mut self, level: LogLevel) {
186        self.level = level;
187    }
188
189    fn is_enabled(&self) -> bool {
190        self.enabled
191    }
192
193    fn set_enabled(&mut self, enabled: bool) {
194        self.enabled = enabled;
195    }
196
197    fn formatter(&self) -> &Formatter {
198        &self.formatter
199    }
200
201    fn set_formatter(&mut self, formatter: Formatter) {
202        self.formatter = formatter;
203    }
204
205    fn set_filter(&mut self, filter: Option<HandlerFilter>) {
206        self.filter = filter;
207    }
208
209    fn filter(&self) -> Option<&HandlerFilter> {
210        self.filter.as_ref()
211    }
212
213    fn handle(&self, record: &Record) -> Result<(), String> {
214        if !self.enabled || record.level() < self.level {
215            return Ok(());
216        }
217        Ok(())
218    }
219}
220
221impl fmt::Debug for BaseHandler {
222    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223        f.debug_struct("BaseHandler")
224            .field("level", &self.level)
225            .field("enabled", &self.enabled)
226            .field("formatter", &self.formatter)
227            .finish()
228    }
229}
230
231#[cfg(test)]
232mod tests {
233    use super::*;
234
235    #[test]
236    fn test_base_handler() {
237        let mut handler = BaseHandler::new(LogLevel::Info);
238        assert_eq!(handler.level(), LogLevel::Info);
239        assert!(handler.is_enabled());
240
241        // Test disabled handler
242        handler.set_enabled(false);
243        assert!(!handler.is_enabled());
244        let record = Record::new(LogLevel::Info, "test", None::<String>, None::<String>, None);
245        assert!(handler.handle(&record).is_ok());
246
247        // Test level filtering
248        handler.set_enabled(true);
249        let debug_record = Record::new(
250            LogLevel::Debug,
251            "test",
252            None::<String>,
253            None::<String>,
254            None,
255        );
256        assert!(handler.handle(&debug_record).is_ok()); // Should succeed but not log (Debug < Info)
257
258        let info_record = Record::new(LogLevel::Info, "test", None::<String>, None::<String>, None);
259        assert!(handler.handle(&info_record).is_ok()); // Should succeed and log
260
261        // Test formatter
262        let formatter = Formatter::text();
263        handler.set_formatter(formatter);
264        assert!(handler.formatter().format(&info_record).contains("test"));
265    }
266}