//! Tracing subscriber initialisation with JSON output. //! //! Uses `tracing_subscriber::fmt` with a custom `Make` impl that injects //! `instance_id` into every log line. use once_cell::sync::Lazy; use std::str::FromStr; use tracing_subscriber::{ fmt::{self, format::FmtSpan}, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, }; /// Global instance identifier, resolved once at startup. /// Priority: `INSTANCE_ID` env var → system hostname → `"unknown"`. pub static INSTANCE_ID: Lazy = Lazy::new(|| { std::env::var("INSTANCE_ID") .ok() .filter(|s| !s.is_empty()) .or_else(|| { hostname::get() .ok() .and_then(|h| h.into_string().ok()) .filter(|s| !s.is_empty()) }) .unwrap_or_else(|| "unknown".to_string()) }); /// Returns the platform-wide instance identifier for this process. pub fn instance_id() -> String { INSTANCE_ID.clone() } /// Initialises the global tracing subscriber with JSON-formatted output to stderr. /// /// Each JSON line includes `ts`, `level`, `target` (module), `fields` (structured kv), /// `line`, `file`, and `instance_id`. /// `RUST_LOG` env var controls the log level filter. pub fn init_tracing_subscriber(level: &str) { let env_filter = EnvFilter::try_from_default_env() .or_else(|_| EnvFilter::from_str(level)) .expect("invalid log level"); let fmt_layer = fmt::layer() .json() .with_target(true) .with_thread_ids(false) .with_file(true) .with_line_number(true) .with_span_events(FmtSpan::CLOSE) .flatten_event(true); let registry = tracing_subscriber::registry() .with(env_filter) .with(fmt_layer); // try_init only fails if a global is already set — this is safe when // init_otlp() is also called (it rebuilds the subscriber with OTLP layers). let _ = registry.try_init(); }