use std::{
fs::{self, OpenOptions},
path::Path,
sync::{Mutex, OnceLock},
};
use anyhow::{Context, Result};
use tracing_log::LogTracer;
use tracing_subscriber::{fmt, prelude::*, util::SubscriberInitExt};
static LOG_FILE: OnceLock<Mutex<std::fs::File>> = OnceLock::new();
pub fn init_logging(workspace_root: &Path) -> Result<()> {
let log_dir = workspace_root.join("target");
fs::create_dir_all(&log_dir)
.with_context(|| format!("failed to create log directory {}", log_dir.display()))?;
let log_path = log_dir.join("xtask.ans");
let file = OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(&log_path)
.with_context(|| format!("failed to open log file {}", log_path.display()))?;
let writer = LOG_FILE.get_or_init(|| Mutex::new(file));
let _ = LogTracer::init();
let _ = tracing_subscriber::registry()
.with(
fmt::layer()
.with_ansi(false)
.with_writer(move || LogWriter { file: writer })
.with_target(false),
)
.try_init();
Ok(())
}
#[derive(Clone, Copy)]
struct LogWriter<'a> {
file: &'a Mutex<std::fs::File>,
}
impl std::io::Write for LogWriter<'_> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.file
.lock()
.expect("log file mutex poisoned")
.write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
self.file.lock().expect("log file mutex poisoned").flush()
}
}