use std::path::Path;
use tracing_appender::non_blocking::{NonBlocking, WorkerGuard};
use super::config::*;
pub(crate) fn create_stdout_writer() -> (NonBlocking, WorkerGuard) {
tracing_appender::non_blocking(std::io::stdout())
}
pub(crate) fn create_rolling_file_writer(opts: &FileLayerOptions) -> (NonBlocking, WorkerGuard) {
let (dir, file_name) = parse_file_path(&opts.path);
ensure_log_directory_exists(dir);
let rolling_appender = match opts.rotation {
Some(RotationPeriod::Daily) => tracing_appender::rolling::daily(dir, file_name),
Some(RotationPeriod::Hourly) => tracing_appender::rolling::hourly(dir, file_name),
Some(RotationPeriod::Weekly) => tracing_appender::rolling::weekly(dir, file_name),
None => tracing_appender::rolling::never(dir, file_name),
};
tracing_appender::non_blocking(rolling_appender)
}
fn parse_file_path(path: &str) -> (&Path, &str) {
let path = Path::new(path);
let dir = path.parent().unwrap_or(Path::new("."));
let file_name = path
.file_name()
.and_then(|s| s.to_str())
.unwrap_or("app.log");
(dir, file_name)
}
fn ensure_log_directory_exists(path: &Path) {
if !path.as_os_str().is_empty() {
std::fs::create_dir_all(path)
.unwrap_or_else(|e| panic!("Failed to create log directory '{:?}': {}", path, e));
}
}
#[cfg(test)]
mod tests {
use std::path::Path;
use super::*;
#[test]
fn test_parse_file_path() {
let (dir, name) = parse_file_path("logs/app.log");
assert_eq!(dir, Path::new("logs"));
assert_eq!(name, "app.log");
let (dir, name) = parse_file_path("app.log");
assert_eq!(dir.to_str().unwrap_or(""), "");
assert_eq!(name, "app.log");
let (dir, name) = parse_file_path("/var/log/myapp");
assert_eq!(dir, Path::new("/var/log"));
assert_eq!(name, "myapp");
}
}