mod syslog;
use std::os::unix::net::UnixDatagram;
use std::sync::Arc;
use anyhow::{Context, Result};
use tracing_appender::non_blocking::WorkerGuard;
use tracing_appender::rolling::{RollingFileAppender, Rotation};
use tracing_subscriber::EnvFilter;
use syslog::SyslogMakeWriter;
pub enum LogGuard {
None,
NonBlocking(#[allow(dead_code)] WorkerGuard),
}
pub fn init() -> Result<LogGuard> {
let target = std::env::var("YSR_LOG_TARGET").unwrap_or_else(|_| "stdout".into());
let env_filter = EnvFilter::from_default_env();
match target.as_str() {
"stdout" => {
tracing_subscriber::fmt()
.with_env_filter(env_filter)
.json()
.init();
Ok(LogGuard::None)
}
"single" | "daily" => {
let dir = std::env::var("YSR_LOG_DIR").unwrap_or_else(|_| ".".into());
let rotation = if target == "daily" {
Rotation::DAILY
} else {
Rotation::NEVER
};
let appender = RollingFileAppender::new(rotation, &dir, "yorishiro.log");
let (writer, guard) = tracing_appender::non_blocking(appender);
tracing_subscriber::fmt()
.with_env_filter(env_filter)
.json()
.with_writer(writer)
.with_ansi(false)
.init();
Ok(LogGuard::NonBlocking(guard))
}
"syslog" => {
let socket_path =
std::env::var("YSR_SYSLOG_SOCKET").unwrap_or_else(|_| "/dev/log".into());
let socket = UnixDatagram::unbound().context("failed to create syslog socket")?;
socket
.connect(&socket_path)
.with_context(|| format!("failed to connect to syslog socket at {socket_path}"))?;
tracing_subscriber::fmt()
.with_env_filter(env_filter)
.json()
.with_writer(SyslogMakeWriter {
socket: Arc::new(socket),
})
.with_ansi(false)
.init();
Ok(LogGuard::None)
}
other => {
anyhow::bail!(
"unknown YSR_LOG_TARGET '{other}' (expected 'stdout', 'single', 'daily', or 'syslog')"
)
}
}
}