use std::path::Path;
use tracing_appender::rolling;
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
pub fn init_daemon_logging(
log_dir: &Path,
foreground: bool,
) -> tracing_appender::non_blocking::WorkerGuard {
let file_appender = rolling::daily(log_dir, "daemon.log");
let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
let env_filter =
EnvFilter::try_from_env("OPENLATCH_LOG").unwrap_or_else(|_| EnvFilter::new("info"));
let file_layer = fmt::layer()
.json()
.with_writer(non_blocking)
.with_target(true)
.with_thread_ids(false)
.with_file(false)
.with_line_number(false);
let stderr_layer = foreground.then(|| {
fmt::layer()
.with_writer(std::io::stderr)
.with_target(false)
.with_thread_ids(false)
.with_file(false)
.with_line_number(false)
.with_ansi(std::io::IsTerminal::is_terminal(&std::io::stderr()))
});
tracing_subscriber::registry()
.with(env_filter)
.with(file_layer)
.with(stderr_layer)
.init();
guard
}
pub fn log_startup(version: &str, port: u16, pid: u32, os: &str, arch: &str) {
tracing::info!(
version = version,
port = port,
pid = pid,
os = os,
arch = arch,
event = "daemon_startup",
"openlatch daemon started"
);
}
pub fn log_observability_status(
telemetry_enabled: bool,
telemetry_decided_by: &str,
crash_report_enabled: bool,
crash_report_decided_by: &str,
) {
tracing::info!(
telemetry_enabled = telemetry_enabled,
telemetry_decided_by = telemetry_decided_by,
crash_report_enabled = crash_report_enabled,
crash_report_decided_by = crash_report_decided_by,
event = "observability_status",
"observability subsystems initialized"
);
}
pub fn log_shutdown(uptime_secs: u64, events_processed: u64) {
tracing::info!(
uptime_secs = uptime_secs,
events_processed = events_processed,
event = "daemon_shutdown",
"openlatch daemon stopped"
);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[ignore = "tracing subscriber is global state — verified in Plan 01-06 integration tests"]
fn test_init_daemon_logging_returns_guard() {
let dir = tempfile::TempDir::new().unwrap();
let _guard: tracing_appender::non_blocking::WorkerGuard =
init_daemon_logging(dir.path(), false);
}
#[test]
#[ignore = "tracing subscriber is global state — verified in Plan 01-06 integration tests"]
fn test_openlatch_log_env_var_respected() {
std::env::set_var("OPENLATCH_LOG", "debug");
let dir = tempfile::TempDir::new().unwrap();
let _guard = init_daemon_logging(dir.path(), false);
}
#[test]
#[ignore = "tracing subscriber is global state — verified in Plan 01-06 integration tests"]
fn test_default_log_level_is_info() {
std::env::remove_var("OPENLATCH_LOG");
let dir = tempfile::TempDir::new().unwrap();
let _guard = init_daemon_logging(dir.path(), false);
}
#[test]
fn test_log_helpers_compile() {
let _ = std::hint::black_box(log_startup as fn(&str, u16, u32, &str, &str));
let _ = std::hint::black_box(log_shutdown as fn(u64, u64));
}
}