use std::io::Write;
use std::sync::atomic::{AtomicBool, Ordering};
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
static TUI_ACTIVE: AtomicBool = AtomicBool::new(false);
pub fn init_tracing() {
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("warn"));
if let Ok(log_file_path) = std::env::var("DEBTMAP_LOG_FILE") {
if let Ok(file) = std::fs::File::create(&log_file_path) {
let file = std::sync::Mutex::new(file);
tracing_subscriber::registry()
.with(
fmt::layer()
.with_target(false)
.with_ansi(false)
.with_writer(move || FileWriter {
file: &file as *const _,
}),
)
.with(filter)
.init();
return;
}
}
tracing_subscriber::registry()
.with(
fmt::layer()
.with_target(false)
.with_writer(|| TuiAwareWriter),
)
.with(filter)
.init();
}
pub fn init_tracing_with_filter(filter: &str) {
let filter = EnvFilter::new(filter);
tracing_subscriber::registry()
.with(
fmt::layer()
.with_target(false)
.with_writer(|| TuiAwareWriter),
)
.with(filter)
.init();
}
pub fn set_tui_active(active: bool) {
TUI_ACTIVE.store(active, Ordering::Relaxed);
}
pub fn is_tui_active() -> bool {
TUI_ACTIVE.load(Ordering::Relaxed)
}
pub fn is_debug_enabled() -> bool {
tracing::enabled!(tracing::Level::DEBUG)
}
struct TuiAwareWriter;
impl Write for TuiAwareWriter {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
if TUI_ACTIVE.load(Ordering::Relaxed) {
Ok(buf.len())
} else {
std::io::stderr().write(buf)
}
}
fn flush(&mut self) -> std::io::Result<()> {
if TUI_ACTIVE.load(Ordering::Relaxed) {
Ok(())
} else {
std::io::stderr().flush()
}
}
}
impl<'a> tracing_subscriber::fmt::MakeWriter<'a> for TuiAwareWriter {
type Writer = TuiAwareWriter;
fn make_writer(&'a self) -> Self::Writer {
TuiAwareWriter
}
}
struct FileWriter {
file: *const std::sync::Mutex<std::fs::File>,
}
unsafe impl Send for FileWriter {}
impl Write for FileWriter {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let file = unsafe { &*self.file };
let mut guard = file.lock().unwrap();
guard.write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
let file = unsafe { &*self.file };
let mut guard = file.lock().unwrap();
guard.flush()
}
}
impl<'a> tracing_subscriber::fmt::MakeWriter<'a> for FileWriter {
type Writer = FileWriter;
fn make_writer(&'a self) -> Self::Writer {
FileWriter { file: self.file }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tui_active_flag() {
assert!(!is_tui_active());
set_tui_active(true);
assert!(is_tui_active());
set_tui_active(false);
assert!(!is_tui_active());
}
}