sqlite_wasm_reader/
logging.rs

1//! Logging functionality for sqlite_wasm_reader
2
3use std::sync::Mutex;
4
5static LOGGER: Mutex<Option<Logger>> = Mutex::new(None);
6
7/// Log levels in order of increasing verbosity
8#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
9pub enum LogLevel {
10    /// Only critical errors that prevent operation
11    Error = 0,
12    /// Important warnings and errors
13    Warn = 1,
14    /// General information about operations
15    Info = 2,
16    /// Detailed debugging information
17    Debug = 3,
18    /// Very detailed tracing information
19    Trace = 4,
20}
21
22impl LogLevel {
23    /// Get the default log level
24    pub fn default() -> Self {
25        LogLevel::Info
26    }
27    
28    /// Parse log level from string
29    pub fn from_str(s: &str) -> Option<Self> {
30        match s.to_lowercase().as_str() {
31            "error" => Some(LogLevel::Error),
32            "warn" | "warning" => Some(LogLevel::Warn),
33            "info" => Some(LogLevel::Info),
34            "debug" => Some(LogLevel::Debug),
35            "trace" => Some(LogLevel::Trace),
36            _ => None,
37        }
38    }
39}
40
41/// Logger implementation
42#[derive(Clone)]
43pub struct Logger {
44    level: LogLevel,
45}
46
47impl Logger {
48    /// Create a new logger with the specified level
49    pub fn new(level: LogLevel) -> Self {
50        Logger { level }
51    }
52    
53    /// Create a logger with default level (Info)
54    pub fn default() -> Self {
55        Logger::new(LogLevel::default())
56    }
57    
58    /// Set the log level
59    pub fn set_level(&mut self, level: LogLevel) {
60        self.level = level;
61    }
62    
63    /// Get the current log level
64    pub fn level(&self) -> LogLevel {
65        self.level
66    }
67    
68    /// Log a message if the level is enabled
69    pub fn log(&self, level: LogLevel, message: &str) {
70        if level <= self.level {
71            let prefix = match level {
72                LogLevel::Error => "ERROR",
73                LogLevel::Warn => "WARN",
74                LogLevel::Info => "INFO",
75                LogLevel::Debug => "DEBUG",
76                LogLevel::Trace => "TRACE",
77            };
78            eprintln!("[sqlite_wasm_reader] {}: {}", prefix, message);
79        }
80    }
81    
82    /// Log an error message
83    pub fn error(&self, message: &str) {
84        self.log(LogLevel::Error, message);
85    }
86    
87    /// Log a warning message
88    pub fn warn(&self, message: &str) {
89        self.log(LogLevel::Warn, message);
90    }
91    
92    /// Log an info message
93    pub fn info(&self, message: &str) {
94        self.log(LogLevel::Info, message);
95    }
96    
97    /// Log a debug message
98    pub fn debug(&self, message: &str) {
99        self.log(LogLevel::Debug, message);
100    }
101    
102    /// Log a trace message
103    pub fn trace(&self, message: &str) {
104        self.log(LogLevel::Trace, message);
105    }
106}
107
108/// Initialize the global logger
109pub fn init_logger(level: LogLevel) {
110    let mut guard = LOGGER.lock().unwrap();
111    *guard = Some(Logger::new(level));
112}
113
114/// Initialize the global logger with default level (Info)
115pub fn init_default_logger() {
116    init_logger(LogLevel::default());
117}
118
119/// Get the global logger instance
120pub fn get_logger() -> Logger {
121    let guard = LOGGER.lock().unwrap();
122    if let Some(ref logger) = *guard {
123        logger.clone()
124    } else {
125        drop(guard);
126        init_default_logger();
127        let guard = LOGGER.lock().unwrap();
128        guard.as_ref().unwrap().clone()
129    }
130}
131
132/// Set the global log level
133pub fn set_log_level(level: LogLevel) {
134    let mut guard = LOGGER.lock().unwrap();
135    if let Some(ref mut logger) = *guard {
136        logger.set_level(level);
137    } else {
138        *guard = Some(Logger::new(level));
139    }
140}
141
142/// Convenience functions for global logging
143pub fn log_error(message: &str) {
144    get_logger().error(message);
145}
146
147pub fn log_warn(message: &str) {
148    get_logger().warn(message);
149}
150
151pub fn log_info(message: &str) {
152    get_logger().info(message);
153}
154
155pub fn log_debug(message: &str) {
156    get_logger().debug(message);
157}
158
159pub fn log_trace(message: &str) {
160    get_logger().trace(message);
161}
162
163/// Check if a log level is enabled
164pub fn is_enabled(level: LogLevel) -> bool {
165    level <= get_logger().level()
166}
167
168#[cfg(test)]
169mod tests {
170    use super::*;
171
172    #[test]
173    fn test_log_level_creation() {
174        assert_eq!(LogLevel::Error as u8, 0);
175        assert_eq!(LogLevel::Warn as u8, 1);
176        assert_eq!(LogLevel::Info as u8, 2);
177        assert_eq!(LogLevel::Debug as u8, 3);
178        assert_eq!(LogLevel::Trace as u8, 4);
179    }
180
181    #[test]
182    fn test_log_level_default() {
183        assert_eq!(LogLevel::default(), LogLevel::Info);
184    }
185
186    #[test]
187    fn test_log_level_from_str() {
188        assert_eq!(LogLevel::from_str("error"), Some(LogLevel::Error));
189        assert_eq!(LogLevel::from_str("warn"), Some(LogLevel::Warn));
190        assert_eq!(LogLevel::from_str("warning"), Some(LogLevel::Warn));
191        assert_eq!(LogLevel::from_str("info"), Some(LogLevel::Info));
192        assert_eq!(LogLevel::from_str("debug"), Some(LogLevel::Debug));
193        assert_eq!(LogLevel::from_str("trace"), Some(LogLevel::Trace));
194        
195        // Case insensitive
196        assert_eq!(LogLevel::from_str("ERROR"), Some(LogLevel::Error));
197        assert_eq!(LogLevel::from_str("Debug"), Some(LogLevel::Debug));
198        
199        // Invalid values
200        assert_eq!(LogLevel::from_str("invalid"), None);
201        assert_eq!(LogLevel::from_str(""), None);
202    }
203
204    #[test]
205    fn test_log_level_comparison() {
206        assert!(LogLevel::Error < LogLevel::Warn);
207        assert!(LogLevel::Warn < LogLevel::Info);
208        assert!(LogLevel::Info < LogLevel::Debug);
209        assert!(LogLevel::Debug < LogLevel::Trace);
210        
211        assert!(LogLevel::Trace > LogLevel::Debug);
212        assert!(LogLevel::Debug > LogLevel::Info);
213        assert!(LogLevel::Info > LogLevel::Warn);
214        assert!(LogLevel::Warn > LogLevel::Error);
215    }
216
217    #[test]
218    fn test_logger_creation() {
219        let logger = Logger::new(LogLevel::Debug);
220        assert_eq!(logger.level(), LogLevel::Debug);
221        
222        let default_logger = Logger::default();
223        assert_eq!(default_logger.level(), LogLevel::Info);
224    }
225
226    #[test]
227    fn test_logger_level_setting() {
228        let mut logger = Logger::new(LogLevel::Info);
229        assert_eq!(logger.level(), LogLevel::Info);
230        
231        logger.set_level(LogLevel::Debug);
232        assert_eq!(logger.level(), LogLevel::Debug);
233    }
234
235    #[test]
236    fn test_global_logger_initialization() {
237        // Test that we can initialize the global logger
238        init_default_logger();
239        let logger = get_logger();
240        assert_eq!(logger.level(), LogLevel::Info);
241    }
242
243    #[test]
244    fn test_global_log_level_setting() {
245        init_default_logger();
246        set_log_level(LogLevel::Debug);
247        let logger = get_logger();
248        assert_eq!(logger.level(), LogLevel::Debug);
249    }
250
251    #[test]
252    fn test_logging_functions() {
253        init_default_logger();
254        set_log_level(LogLevel::Debug);
255        
256        // These should not panic
257        log_error("Test error message");
258        log_warn("Test warning message");
259        log_info("Test info message");
260        log_debug("Test debug message");
261        log_trace("Test trace message");
262    }
263
264    #[test]
265    fn test_is_enabled() {
266        init_default_logger();
267        set_log_level(LogLevel::Info);
268        
269        assert!(is_enabled(LogLevel::Error));
270        assert!(is_enabled(LogLevel::Warn));
271        assert!(is_enabled(LogLevel::Info));
272        assert!(!is_enabled(LogLevel::Debug));
273        assert!(!is_enabled(LogLevel::Trace));
274        
275        set_log_level(LogLevel::Trace);
276        assert!(is_enabled(LogLevel::Error));
277        assert!(is_enabled(LogLevel::Warn));
278        assert!(is_enabled(LogLevel::Info));
279        assert!(is_enabled(LogLevel::Debug));
280        assert!(is_enabled(LogLevel::Trace));
281    }
282}