Skip to main content

oven_cli/
logging.rs

1use std::path::Path;
2
3use tracing_appender::non_blocking::WorkerGuard;
4use tracing_subscriber::{EnvFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt};
5
6/// Initialize stderr-only logging for commands that don't need file output.
7/// Used by prep, look, report, clean, ticket.
8pub fn init_stderr_only() {
9    tracing_subscriber::registry()
10        .with(EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("oven_cli=info")))
11        .with(fmt::layer().with_writer(std::io::stderr))
12        .init();
13}
14
15/// Initialize dual-output logging: human-readable to stderr, JSON to a file.
16///
17/// Used by `oven on`. The returned `WorkerGuard` must be held until shutdown
18/// to ensure the background writer thread flushes and stops cleanly.
19pub fn init_with_file(log_dir: &Path, verbose: bool) -> WorkerGuard {
20    let file_appender = tracing_appender::rolling::never(log_dir, "pipeline.log");
21    let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
22
23    let env_filter = if verbose {
24        EnvFilter::new("oven_cli=debug")
25    } else {
26        EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("oven_cli=info"))
27    };
28
29    tracing_subscriber::registry()
30        .with(env_filter)
31        .with(fmt::layer().with_writer(std::io::stderr))
32        .with(fmt::layer().json().with_writer(non_blocking))
33        .init();
34
35    guard
36}
37
38#[cfg(test)]
39mod tests {
40    // Logging initialization is global and can only happen once per process,
41    // so we verify the functions compile and the guard pattern is sound.
42    // Full integration testing of log output is deferred to CLI integration tests.
43
44    #[test]
45    fn init_stderr_only_compiles() {
46        // Just verify the function signature and types are correct.
47        // Can't actually call it in tests because tracing::subscriber::set_global_default
48        // can only be called once per process.
49        let _ = std::io::stderr;
50    }
51
52    #[test]
53    fn guard_is_send() {
54        fn assert_send<T: Send>() {}
55        assert_send::<tracing_appender::non_blocking::WorkerGuard>();
56    }
57}