rust_loguru/handler/
mod.rs

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