use std::sync::{Arc, Once};
use std::path::Path;
pub mod error;
pub mod core;
pub mod format;
pub mod rotation;
pub use core::{LogLevel, Pattern, LoggerConfig, Logger};
pub use error::LoggerError;
static mut GLOBAL_LOGGER: Option<Arc<Logger>> = None;
static INIT_ONCE: Once = Once::new();
pub fn log_init<P: AsRef<Path>>(pattern: Pattern, file_path: P, file_name: &str) {
let path_buf = file_path.as_ref().to_path_buf();
let config = LoggerConfig::basic(pattern, path_buf, file_name.to_string());
log_init_with_config(config);
}
pub fn log_init_with_level<P: AsRef<Path>>(
pattern: Pattern,
file_path: P,
file_name: &str,
log_level: LogLevel
) {
let path_buf = file_path.as_ref().to_path_buf();
let config = LoggerConfig::with_level(pattern, path_buf, file_name.to_string(), log_level);
log_init_with_config(config);
}
pub fn log_init_with_rotation<P: AsRef<Path>>(
pattern: Pattern,
file_path: P,
file_name: &str,
log_level: LogLevel,
max_file_size: u64,
max_backup_files: u32,
) {
let path_buf = file_path.as_ref().to_path_buf();
let config = LoggerConfig::with_rotation(
pattern,
path_buf,
file_name.to_string(),
log_level,
max_file_size,
max_backup_files
);
log_init_with_config(config);
}
fn log_init_with_config(config: LoggerConfig) {
INIT_ONCE.call_once(|| {
let logger = Logger::new(config);
unsafe {
GLOBAL_LOGGER = Some(Arc::new(logger));
}
});
}
#[allow(static_mut_refs)]
fn get_logger() -> &'static Arc<Logger> {
unsafe {
GLOBAL_LOGGER
.as_ref()
.expect("Logger not initialized - call logger::init() first")
}
}
pub fn log_error(message: &str) {
get_logger().error(message);
}
pub fn log_warning(message: &str) {
get_logger().warning(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);
}
#[macro_export]
macro_rules! log_error {
($msg:expr) => {
$crate::log_error($msg);
};
($fmt:expr, $($arg:expr),+ $(,)?) => {
$crate::log_error(&format!($fmt, $($arg),+));
};
}
#[macro_export]
macro_rules! log_warning {
($msg:expr) => {
$crate::log_warning($msg);
};
($fmt:expr, $($arg:expr),+ $(,)?) => {
$crate::log_warning(&format!($fmt, $($arg),+));
};
}
#[macro_export]
macro_rules! log_info {
($msg:expr) => {
$crate::log_info($msg);
};
($fmt:expr, $($arg:expr),+ $(,)?) => {
$crate::log_info(&format!($fmt, $($arg),+));
};
}
#[macro_export]
macro_rules! log_debug {
($msg:expr) => {
$crate::log_debug($msg);
};
($fmt:expr, $($arg:expr),+ $(,)?) => {
$crate::log_debug(&format!($fmt, $($arg),+));
};
}
#[macro_export]
macro_rules! log_trace {
($msg:expr) => {
$crate::log_trace($msg);
};
($fmt:expr, $($arg:expr),+ $(,)?) => {
$crate::log_trace(&format!($fmt, $($arg),+));
};
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::tempdir;
use std::fs;
use std::path::PathBuf;
#[test]
fn test_basic_logging_integration() {
let temp_dir = tempdir().unwrap();
log_init(Pattern::Basic, temp_dir.path(), "test");
log_info("Test info message");
log_warning("Test warning message");
log_error("Test error message");
let database_path = PathBuf::from("/var/lib/myapp/database.db");
let user_id = 12345;
let status = "active";
log_debug!("Database path: {:?}", database_path);
log_info!("User {} has status: {}", user_id, status);
log_warning!("Processing {} items", 42);
log_error!("Failed to connect to {}", "localhost:5432");
log_debug!("Simple debug message");
log_info!("Simple info message");
let log_file = temp_dir.path().join("test.log");
assert!(log_file.exists());
let content = fs::read_to_string(&log_file).unwrap();
assert!(content.contains("INFO: Test info message"));
assert!(content.contains("WARNING: Test warning message"));
assert!(content.contains("ERROR: Test error message"));
assert!(content.contains("Database path:"));
assert!(content.contains("User 12345 has status: active"));
assert!(content.contains("Processing 42 items"));
assert!(content.contains("Failed to connect to localhost:5432"));
assert!(content.contains("Simple debug message"));
}
}