use tracing_subscriber::filter::EnvFilter;
use tracing_subscriber::prelude::*;
const MAX_LOG_BYTES: u64 = 5 * 1024 * 1024;
fn rotate_if_oversized(path: &std::path::Path) {
if let Ok(md) = std::fs::metadata(path)
&& md.len() > MAX_LOG_BYTES
{
let _ = std::fs::rename(path, path.with_extension("log.old"));
}
}
pub fn init(mode: &str) -> crate::AppResult<()> {
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("eqtui=info"));
let is_tui = matches!(mode, "attach" | "");
let subscriber = tracing_subscriber::registry().with(filter);
if is_tui {
let log_dir = dirs::data_dir()
.ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::NotFound,
"cannot determine user data directory (XDG_DATA_HOME)",
)
})?
.join("eqtui");
std::fs::create_dir_all(&log_dir)?;
let log_path = log_dir.join("eqtui-tui.log");
rotate_if_oversized(&log_path);
let log_file = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(&log_path)?;
subscriber
.with(
tracing_subscriber::fmt::layer()
.with_ansi(false)
.with_writer(std::sync::Mutex::new(log_file)),
)
.with(tracing_error::ErrorLayer::default())
.init();
} else {
subscriber
.with(tracing_subscriber::fmt::layer().with_writer(std::io::stderr))
.with(tracing_error::ErrorLayer::default())
.init();
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn oversized_log_is_rotated() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("eqtui-tui.log");
std::fs::write(&path, vec![b'x'; (MAX_LOG_BYTES as usize) + 1]).unwrap();
rotate_if_oversized(&path);
let old = path.with_extension("log.old");
assert!(old.exists(), "oversized log must be rotated to .old");
assert!(!path.exists(), "original renamed away");
}
#[test]
fn small_log_is_not_rotated() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("eqtui-tui.log");
std::fs::write(&path, vec![b'x'; 1024]).unwrap();
rotate_if_oversized(&path);
let old = path.with_extension("log.old");
assert!(path.exists(), "small log must stay in place");
assert!(!old.exists(), "no .old should be created for a small log");
}
}