use std::sync::Mutex;
static LOGGER: Mutex<Option<Logger>> = Mutex::new(None);
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub enum LogLevel {
Error = 0,
Warn = 1,
Info = 2,
Debug = 3,
Trace = 4,
}
impl LogLevel {
pub fn default() -> Self {
LogLevel::Info
}
pub fn from_str(s: &str) -> Option<Self> {
match s.to_lowercase().as_str() {
"error" => Some(LogLevel::Error),
"warn" | "warning" => Some(LogLevel::Warn),
"info" => Some(LogLevel::Info),
"debug" => Some(LogLevel::Debug),
"trace" => Some(LogLevel::Trace),
_ => None,
}
}
}
#[derive(Clone)]
pub struct Logger {
level: LogLevel,
}
impl Logger {
pub fn new(level: LogLevel) -> Self {
Logger { level }
}
pub fn default() -> Self {
Logger::new(LogLevel::default())
}
pub fn set_level(&mut self, level: LogLevel) {
self.level = level;
}
pub fn level(&self) -> LogLevel {
self.level
}
pub fn log(&self, level: LogLevel, message: &str) {
if level <= self.level {
let prefix = match level {
LogLevel::Error => "ERROR",
LogLevel::Warn => "WARN",
LogLevel::Info => "INFO",
LogLevel::Debug => "DEBUG",
LogLevel::Trace => "TRACE",
};
eprintln!("[sqlite_wasm_reader] {}: {}", prefix, message);
}
}
pub fn error(&self, message: &str) {
self.log(LogLevel::Error, message);
}
pub fn warn(&self, message: &str) {
self.log(LogLevel::Warn, message);
}
pub fn info(&self, message: &str) {
self.log(LogLevel::Info, message);
}
pub fn debug(&self, message: &str) {
self.log(LogLevel::Debug, message);
}
pub fn trace(&self, message: &str) {
self.log(LogLevel::Trace, message);
}
}
pub fn init_logger(level: LogLevel) {
let mut guard = LOGGER.lock().unwrap();
*guard = Some(Logger::new(level));
}
pub fn init_default_logger() {
init_logger(LogLevel::default());
}
pub fn get_logger() -> Logger {
let guard = LOGGER.lock().unwrap();
if let Some(ref logger) = *guard {
logger.clone()
} else {
drop(guard);
init_default_logger();
let guard = LOGGER.lock().unwrap();
guard.as_ref().unwrap().clone()
}
}
pub fn set_log_level(level: LogLevel) {
let mut guard = LOGGER.lock().unwrap();
if let Some(ref mut logger) = *guard {
logger.set_level(level);
} else {
*guard = Some(Logger::new(level));
}
}
pub fn log_error(message: &str) {
get_logger().error(message);
}
pub fn log_warn(message: &str) {
get_logger().warn(message);
}
pub fn log_info(message: &str) {
get_logger().info(message);
}
pub fn log_debug(message: &str) {
get_logger().debug(message);
}
pub fn log_trace(message: &str) {
get_logger().trace(message);
}
pub fn is_enabled(level: LogLevel) -> bool {
level <= get_logger().level()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_log_level_creation() {
assert_eq!(LogLevel::Error as u8, 0);
assert_eq!(LogLevel::Warn as u8, 1);
assert_eq!(LogLevel::Info as u8, 2);
assert_eq!(LogLevel::Debug as u8, 3);
assert_eq!(LogLevel::Trace as u8, 4);
}
#[test]
fn test_log_level_default() {
assert_eq!(LogLevel::default(), LogLevel::Info);
}
#[test]
fn test_log_level_from_str() {
assert_eq!(LogLevel::from_str("error"), Some(LogLevel::Error));
assert_eq!(LogLevel::from_str("warn"), Some(LogLevel::Warn));
assert_eq!(LogLevel::from_str("warning"), Some(LogLevel::Warn));
assert_eq!(LogLevel::from_str("info"), Some(LogLevel::Info));
assert_eq!(LogLevel::from_str("debug"), Some(LogLevel::Debug));
assert_eq!(LogLevel::from_str("trace"), Some(LogLevel::Trace));
assert_eq!(LogLevel::from_str("ERROR"), Some(LogLevel::Error));
assert_eq!(LogLevel::from_str("Debug"), Some(LogLevel::Debug));
assert_eq!(LogLevel::from_str("invalid"), None);
assert_eq!(LogLevel::from_str(""), None);
}
#[test]
fn test_log_level_comparison() {
assert!(LogLevel::Error < LogLevel::Warn);
assert!(LogLevel::Warn < LogLevel::Info);
assert!(LogLevel::Info < LogLevel::Debug);
assert!(LogLevel::Debug < LogLevel::Trace);
assert!(LogLevel::Trace > LogLevel::Debug);
assert!(LogLevel::Debug > LogLevel::Info);
assert!(LogLevel::Info > LogLevel::Warn);
assert!(LogLevel::Warn > LogLevel::Error);
}
#[test]
fn test_logger_creation() {
let logger = Logger::new(LogLevel::Debug);
assert_eq!(logger.level(), LogLevel::Debug);
let default_logger = Logger::default();
assert_eq!(default_logger.level(), LogLevel::Info);
}
#[test]
fn test_logger_level_setting() {
let mut logger = Logger::new(LogLevel::Info);
assert_eq!(logger.level(), LogLevel::Info);
logger.set_level(LogLevel::Debug);
assert_eq!(logger.level(), LogLevel::Debug);
}
#[test]
fn test_global_logger_initialization() {
init_default_logger();
let logger = get_logger();
assert_eq!(logger.level(), LogLevel::Info);
}
#[test]
fn test_global_log_level_setting() {
init_default_logger();
set_log_level(LogLevel::Debug);
let logger = get_logger();
assert_eq!(logger.level(), LogLevel::Debug);
}
#[test]
fn test_logging_functions() {
init_default_logger();
set_log_level(LogLevel::Debug);
log_error("Test error message");
log_warn("Test warning message");
log_info("Test info message");
log_debug("Test debug message");
log_trace("Test trace message");
}
#[test]
fn test_is_enabled() {
init_default_logger();
set_log_level(LogLevel::Info);
assert!(is_enabled(LogLevel::Error));
assert!(is_enabled(LogLevel::Warn));
assert!(is_enabled(LogLevel::Info));
assert!(!is_enabled(LogLevel::Debug));
assert!(!is_enabled(LogLevel::Trace));
set_log_level(LogLevel::Trace);
assert!(is_enabled(LogLevel::Error));
assert!(is_enabled(LogLevel::Warn));
assert!(is_enabled(LogLevel::Info));
assert!(is_enabled(LogLevel::Debug));
assert!(is_enabled(LogLevel::Trace));
}
}