use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use tracing_subscriber::EnvFilter;
#[cfg(feature = "tui")]
mod tui {
use std::fs::{File, OpenOptions};
use std::io;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use tracing_subscriber::fmt::MakeWriter;
#[derive(Clone, Debug)]
pub(super) struct DynamicLogger {
file: Arc<File>,
tui_mode: Arc<AtomicBool>,
}
impl DynamicLogger {
pub fn try_new(
file_name: String,
tui_mode: Arc<AtomicBool>,
) -> io::Result<DynamicLogger> {
OpenOptions::new()
.append(true)
.create(true)
.open(&file_name)
.map(|file| Self {
file: Arc::new(file),
tui_mode,
})
}
}
impl<'a> MakeWriter<'a> for DynamicLogger {
type Writer = Self;
fn make_writer(&self) -> Self::Writer {
self.clone()
}
}
impl io::Write for DynamicLogger {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if self.tui_mode.load(Ordering::Acquire) {
self.file.write_all(buf)?
} else {
io::stderr().write_all(buf)?
}
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
if self.tui_mode.load(Ordering::Acquire) {
self.file.flush()
} else {
io::stderr().flush()
}
}
}
}
pub fn init_logging(
#[allow(unused_variables)] tui_mode: Arc<AtomicBool>,
) -> Result<(), Box<dyn std::error::Error>> {
let env_filter =
EnvFilter::try_from_default_env().or_else(|_| EnvFilter::try_new("warn"))?;
#[cfg(feature = "tui")]
let writer = {
let dir_name = "logs";
std::fs::create_dir_all(dir_name)?;
let file_name = format!("{dir_name}/ballista-tui.log");
tui::DynamicLogger::try_new(file_name, tui_mode)?
};
#[cfg(not(feature = "tui"))]
let writer = std::io::stderr;
match tracing_subscriber::fmt()
.with_env_filter(env_filter)
.with_writer(writer)
.with_ansi(true)
.try_init()
{
Ok(_) => {}
Err(e) => eprintln!("Failed to initialize the logger: {:?}", e),
}
Ok(())
}