use std::sync::atomic::{AtomicBool, Ordering};
use tracing::{Event, Level, Subscriber};
use tracing_subscriber::{
EnvFilter,
fmt::{self, FmtContext, FormatEvent, FormatFields, format::Writer},
prelude::*,
registry::LookupSpan,
};
static TRACING_INITIALIZED: AtomicBool = AtomicBool::new(false);
struct NautilusFormatter;
impl<S, N> FormatEvent<S, N> for NautilusFormatter
where
S: Subscriber + for<'a> LookupSpan<'a>,
N: for<'a> FormatFields<'a> + 'static,
{
fn format_event(
&self,
ctx: &FmtContext<'_, S, N>,
mut writer: Writer<'_>,
event: &Event<'_>,
) -> std::fmt::Result {
let now = chrono::Utc::now();
let timestamp = now.format("%Y-%m-%dT%H:%M:%S%.9fZ");
let level = match *event.metadata().level() {
Level::TRACE => "[TRACE]",
Level::DEBUG => "[DEBUG]",
Level::INFO => "[INFO]",
Level::WARN => "[WARN]",
Level::ERROR => "[ERROR]",
};
let target = event.metadata().target();
write!(writer, "{timestamp} {level} {target}: ")?;
ctx.field_format().format_fields(writer.by_ref(), event)?;
writeln!(writer)
}
}
#[must_use]
pub fn tracing_is_initialized() -> bool {
TRACING_INITIALIZED.load(Ordering::Relaxed)
}
pub fn init_tracing() -> anyhow::Result<()> {
if TRACING_INITIALIZED.load(Ordering::SeqCst) {
anyhow::bail!("Tracing subscriber already initialized");
}
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("warn"));
let subscriber = tracing_subscriber::registry()
.with(filter)
.with(fmt::layer().event_format(NautilusFormatter));
tracing::subscriber::set_global_default(subscriber)
.map_err(|e| anyhow::anyhow!("Failed to initialize tracing subscriber: {e}"))?;
TRACING_INITIALIZED.store(true, Ordering::SeqCst);
Ok(())
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
#[rstest]
fn test_tracing_is_initialized_returns_bool() {
let _ = tracing_is_initialized();
}
}