use anyhow::{Context, Result};
use std::path::PathBuf;
use tracing::Level;
use tracing_subscriber::{
fmt::{self, format::FmtSpan},
layer::SubscriberExt,
util::SubscriberInitExt,
EnvFilter, Layer,
};
pub fn init_logger(level: &str, format: &str, log_file: Option<PathBuf>) -> Result<()> {
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| {
EnvFilter::new(level)
});
let registry = tracing_subscriber::registry().with(filter);
match format {
"json" => {
if let Some(file_path) = log_file {
let file = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(&file_path)
.context("Failed to open log file")?;
let file_layer = fmt::layer()
.json()
.with_writer(std::sync::Arc::new(file))
.with_span_events(FmtSpan::CLOSE);
registry.with(file_layer).init();
} else {
let stdout_layer = fmt::layer()
.json()
.with_span_events(FmtSpan::CLOSE);
registry.with(stdout_layer).init();
}
}
"compact" => {
if let Some(file_path) = log_file {
let file = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(&file_path)
.context("Failed to open log file")?;
let file_layer = fmt::layer()
.compact()
.with_writer(std::sync::Arc::new(file))
.with_span_events(FmtSpan::CLOSE);
registry.with(file_layer).init();
} else {
let stdout_layer = fmt::layer()
.compact()
.with_span_events(FmtSpan::CLOSE);
registry.with(stdout_layer).init();
}
}
_ => {
if let Some(file_path) = log_file {
let file = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(&file_path)
.context("Failed to open log file")?;
let file_layer = fmt::layer()
.pretty()
.with_writer(std::sync::Arc::new(file))
.with_span_events(FmtSpan::CLOSE);
registry.with(file_layer).init();
} else {
let stdout_layer = fmt::layer()
.pretty()
.with_span_events(FmtSpan::CLOSE);
registry.with(stdout_layer).init();
}
}
}
Ok(())
}
pub fn parse_level(level: &str) -> Level {
match level.to_lowercase().as_str() {
"trace" => Level::TRACE,
"debug" => Level::DEBUG,
"info" => Level::INFO,
"warn" | "warning" => Level::WARN,
"error" => Level::ERROR,
_ => Level::INFO,
}
}
pub fn default_log_path() -> Result<PathBuf> {
if nix::unistd::geteuid().is_root() {
Ok(PathBuf::from("/var/log/smirrors/smirrors.log"))
} else {
let dirs = directories::ProjectDirs::from("com", "smirrors", "smirrors")
.context("Could not determine project directories")?;
let log_dir = dirs.data_local_dir().join("logs");
std::fs::create_dir_all(&log_dir)
.context("Failed to create log directory")?;
Ok(log_dir.join("smirrors.log"))
}
}
pub fn init_service_logger() -> Result<()> {
let log_path = default_log_path()?;
if let Some(parent) = log_path.parent() {
std::fs::create_dir_all(parent)
.context("Failed to create log directory")?;
}
init_logger("info", "json", Some(log_path))
}
pub fn init_cli_logger(level: &str) -> Result<()> {
init_logger(level, "pretty", None)
}