use crate::config::{LogFormat, LoggingConfig};
pub fn init_logging(cfg: &LoggingConfig) {
use tracing_subscriber::EnvFilter;
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(&cfg.level));
match cfg.format {
LogFormat::Json => {
if let Some(path) = &cfg.file {
let file = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(path)
.expect("failed to open log file");
tracing_subscriber::fmt()
.json()
.with_env_filter(filter)
.with_writer(move || file.try_clone().expect("file writer"))
.init();
} else {
tracing_subscriber::fmt()
.json()
.with_env_filter(filter)
.init();
}
}
_ => {
tracing_subscriber::fmt()
.with_env_filter(filter)
.with_target(true)
.compact()
.init();
}
}
}
#[macro_export]
macro_rules! log_component {
($level:ident, $component:expr, $msg:expr) => {
tracing::$level!(component = $component, $msg)
};
($level:ident, $component:expr, $msg:expr, $($key:ident = $val:expr),+ $(,)?) => {
tracing::$level!(component = $component, $($key = $val,)+ $msg)
};
}
#[cfg(test)]
mod tests {
use crate::config::{LogFormat, LoggingConfig};
#[test]
fn test_default_logging_config() {
let cfg = LoggingConfig::default();
assert_eq!(cfg.format, LogFormat::Component);
assert_eq!(cfg.level, "info");
assert!(cfg.file.is_none());
}
#[test]
fn test_log_format_deserialize_json() {
let cfg: LoggingConfig =
serde_json::from_str(r#"{"format":"json","level":"debug"}"#).unwrap();
assert_eq!(cfg.format, LogFormat::Json);
assert_eq!(cfg.level, "debug");
}
#[test]
fn test_log_format_deserialize_pretty() {
let cfg: LoggingConfig = serde_json::from_str(r#"{"format":"pretty"}"#).unwrap();
assert_eq!(cfg.format, LogFormat::Pretty);
assert_eq!(cfg.level, "info"); }
#[test]
fn test_log_format_deserialize_component() {
let cfg: LoggingConfig = serde_json::from_str(r#"{"format":"component"}"#).unwrap();
assert_eq!(cfg.format, LogFormat::Component);
}
#[test]
fn test_logging_config_roundtrip() {
let cfg = LoggingConfig {
format: LogFormat::Json,
file: Some("/tmp/zeptoclaw.log".to_string()),
level: "debug".to_string(),
};
let json = serde_json::to_string(&cfg).unwrap();
let restored: LoggingConfig = serde_json::from_str(&json).unwrap();
assert_eq!(restored.format, LogFormat::Json);
assert_eq!(restored.file.as_deref(), Some("/tmp/zeptoclaw.log"));
assert_eq!(restored.level, "debug");
}
#[test]
fn test_log_format_partial_config_uses_defaults() {
let cfg: LoggingConfig = serde_json::from_str(r#"{"level":"trace"}"#).unwrap();
assert_eq!(cfg.format, LogFormat::Component);
assert!(cfg.file.is_none());
assert_eq!(cfg.level, "trace");
}
}