use chrono::{SecondsFormat, Utc}; use std::sync::OnceLock; use tracing_subscriber::EnvFilter; static INITIALIZED: OnceLock<()> = OnceLock::new(); /// Inicializa logs JSON. Cada evento emitido pelas funções deste módulo contém /// horário UTC, módulo, request_id, nível e mensagem. pub fn init() { INITIALIZED.get_or_init(|| { let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("backend=info")); let _ = tracing_subscriber::fmt() .with_env_filter(filter) .json() .with_current_span(false) .with_span_list(false) .try_init(); }); } pub fn info(module: &str, request_id: &str, message: impl AsRef) { let timestamp = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true); tracing::info!( timestamp = %timestamp, module = %module, request_id = %request_id, message = %message.as_ref() ); } pub fn warn(module: &str, request_id: &str, message: impl AsRef) { let timestamp = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true); tracing::warn!( timestamp = %timestamp, module = %module, request_id = %request_id, message = %message.as_ref() ); } pub fn error(module: &str, request_id: &str, message: impl AsRef) { let timestamp = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true); tracing::error!( timestamp = %timestamp, module = %module, request_id = %request_id, message = %message.as_ref() ); } #[cfg(test)] mod tests { #[test] fn logger_can_be_initialized_more_than_once() { super::init(); super::init(); super::info("logs", "test-request", "logger pronto"); } }