use anyhow::Result;
use log::{Level, error, info, warn};
use std::sync::Once;
static INIT: Once = Once::new();
pub struct LogMessage {
pub message: String,
pub module: &'static str,
pub context: Option<Vec<(&'static str, String)>>,
}
pub fn init() -> Result<()> {
let mut result = Ok(());
INIT.call_once(|| {
match setup_telemetry() {
Ok(_) => {
info!("Logging initialized with stderr output");
}
Err(e) => {
eprintln!("Failed to initialize logging: {}", e);
result = Err(e);
}
}
});
result
}
pub fn log_with_context(level: Level, msg: LogMessage) {
match level {
Level::Error => {
error!(target: msg.module, "{}", format_context(&msg));
}
Level::Warn => {
warn!(target: msg.module, "{}", format_context(&msg));
}
Level::Info => {
info!(target: msg.module, "{}", format_context(&msg));
}
Level::Debug => {
log::debug!(target: msg.module, "{}", format_context(&msg));
}
Level::Trace => {
log::trace!(target: msg.module, "{}", format_context(&msg));
}
}
}
fn format_context(msg: &LogMessage) -> String {
if let Some(context) = &msg.context {
let context_str = context
.iter()
.map(|(k, v)| format!("{}={}", k, v))
.collect::<Vec<_>>()
.join(", ");
format!("{} [{}]", msg.message, context_str)
} else {
msg.message.clone()
}
}
fn setup_telemetry() -> Result<()> {
env_logger::Builder::new()
.filter(None, log::LevelFilter::Info)
.format_timestamp(None)
.format_target(true)
.format_module_path(false)
.init();
Ok(())
}