use std::sync::Mutex;
use std::thread;
use crate::core::config::{LoggerConfig, LogLevel, Pattern};
use crate::core::writers::{TextWriter, JsonWriter};
use crate::format::LogInfo;
use crate::rotation::{SizeBasedRotation, RotationResult};
use crate::error::{write_error_to_log, LoggerError};
pub struct Logger {
config: LoggerConfig,
text_writer: TextWriter,
json_writer: JsonWriter,
rotation: SizeBasedRotation,
write_mutex: Mutex<()>,
}
impl Logger {
pub fn new(config: LoggerConfig) -> Self {
let rotation = SizeBasedRotation::new(
config.max_file_size,
config.max_backup_files,
);
Self {
config,
text_writer: TextWriter::new(),
json_writer: JsonWriter::new(),
rotation,
write_mutex: Mutex::new(()),
}
}
pub fn error(&self, message: &str) {
self.log(LogLevel::Error, message, file!(), line!());
}
pub fn warning(&self, message: &str) {
self.log(LogLevel::Warning, message, file!(), line!());
}
pub fn info(&self, message: &str) {
self.log(LogLevel::Info, message, file!(), line!());
}
pub fn debug(&self, message: &str) {
self.log(LogLevel::Debug, message, file!(), line!());
}
pub fn trace(&self, message: &str) {
self.log(LogLevel::Trace, message, file!(), line!());
}
fn log(&self, level: LogLevel, message: &str, file: &str, line: u32) {
if !self.config.should_log_level(level) {
return; }
let _lock = match self.write_mutex.lock() {
Ok(lock) => lock,
Err(_) => {
self.handle_error(LoggerError::RotationFailed {
current_file: "mutex".to_string(),
backup_file: "poisoned".to_string(),
reason: "Mutex poisoned during logging".to_string(),
});
return;
}
};
let timestamp = self.get_current_timestamp();
let thread_name = self.get_current_thread_name();
let log_info = LogInfo::new(message, level, ×tamp)
.with_location(file, line)
.with_thread(&thread_name);
let log_file_path = match self.config.pattern {
Pattern::Json => {
self.config.file_path.join(format!("{}.json", self.config.file_name))
}
_ => {
self.config.get_log_file_path()
}
};
match self.rotation.check_and_rotate(&log_file_path) {
RotationResult::Failed(error) => {
self.handle_error(error);
}
_ => {
}
}
self.write_log_entry(&log_info, &log_file_path);
}
fn write_log_entry(&self, log_info: &LogInfo, file_path: &std::path::Path) {
match self.config.pattern {
Pattern::Json => {
if let Err(error) = self.json_writer.write_log_entry(log_info, file_path) {
self.handle_error(error);
}
}
_ => {
let formatted_message = self.config.pattern.format(log_info);
if let Err(error) = self.text_writer.write_message(&formatted_message, file_path) {
self.handle_error(error);
}
}
}
}
fn get_current_timestamp(&self) -> String {
use chrono::{Local, DateTime};
let now: DateTime<Local> = Local::now();
now.format("%Y-%m-%d %H:%M:%S").to_string()
}
fn get_current_thread_name(&self) -> String {
thread::current()
.name()
.unwrap_or("unnamed")
.to_string()
}
fn handle_error(&self, error: LoggerError) {
write_error_to_log(&error, &self.config.file_path);
}
}
unsafe impl Send for Logger {}
unsafe impl Sync for Logger {}