use super::sinks::{console::create_console_appender, file::create_file_appender};
use log::LevelFilter;
use log4rs::config::runtime::{ConfigBuilder, RootBuilder};
use log4rs::{
config::{Appender, Config, Logger, Root},
filter::threshold::ThresholdFilter,
};
use std::path::Path;
pub struct LoggingBuilder {
config_builder: ConfigBuilder,
root_builder: RootBuilder,
appenders: Vec<String>,
level: LevelFilter,
}
impl LoggingBuilder {
pub fn new() -> Self {
Self {
config_builder: Config::builder(),
root_builder: Root::builder(),
appenders: Vec::new(),
level: LevelFilter::Info,
}
}
pub fn with_console(mut self, name: &str, level: LevelFilter) -> Self {
let console = create_console_appender();
let appender = Appender::builder()
.filter(Box::new(ThresholdFilter::new(level)))
.build(name, Box::new(console));
self.config_builder = self.config_builder.appender(appender);
self.appenders.push(name.to_string());
self.root_builder = self.root_builder.appender(name);
self
}
pub fn with_file(mut self, name: &str, path: &str, level: LevelFilter) -> Self {
let path = Path::new(path);
if let Some(parent_dir) = path.parent() {
std::fs::create_dir_all(parent_dir).unwrap_or_else(|_| {
eprintln!(
"Failed to create directories for log file: {:?}",
parent_dir
);
});
}
let file = create_file_appender(path);
let appender = Appender::builder()
.filter(Box::new(ThresholdFilter::new(level)))
.build(name, Box::new(file));
self.config_builder = self.config_builder.appender(appender);
self.appenders.push(name.to_string());
self.root_builder = self.root_builder.appender(name);
self
}
pub fn with_level(mut self, level: LevelFilter) -> Self {
self.level = level;
self
}
pub fn with_module_level(mut self, module: &str, level: LevelFilter) -> Self {
let logger = Logger::builder().build(module, level);
self.config_builder = self.config_builder.logger(logger);
self
}
pub fn build(self) -> Result<Config, String> {
if self.appenders.is_empty() {
return Err("At least one appender must be configured".to_string());
}
let root = self.root_builder.build(self.level);
match self.config_builder.build(root) {
Ok(config) => Ok(config),
Err(e) => Err(format!("Failed to build log configuration: {}", e)),
}
}
}