steer_core/utils/
tracing.rs

1use chrono::Local;
2use dirs;
3use std::io;
4use tracing_appender::rolling::{self};
5use tracing_subscriber::{
6    EnvFilter,
7    fmt::{self, format::FmtSpan},
8    prelude::*,
9};
10
11/// Initialize the tracing system with either stdout or file logging.
12///
13/// Configuration behavior:
14/// - In normal operation: Logs to file in ~/.steer directory
15/// - Logging level is controlled by the RUST_LOG environment variable
16pub fn init_tracing() -> io::Result<()> {
17    // Default log file in the user's home directory with timestamp
18    let now = Local::now();
19    let timestamp = now.format("%Y%m%d_%H%M%S");
20
21    // Configure the filter based on RUST_LOG env var, with sensible defaults
22    let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| {
23        // Default: warn for all crates
24        EnvFilter::new("info")
25    });
26
27    if let Some(home_dir) = dirs::home_dir() {
28        // Normal operation - log to file
29        // Create the .steer directory if it doesn't exist
30        let log_dir = home_dir.join(".steer");
31        std::fs::create_dir_all(&log_dir)?;
32
33        // Create the file appender directly (synchronous writing)
34        let file_appender = rolling::never(log_dir.clone(), format!("{timestamp}.log"));
35
36        let subscriber = tracing_subscriber::registry()
37            .with(
38                fmt::Layer::new()
39                    .with_writer(file_appender)
40                    .with_ansi(false)
41                    .with_span_events(FmtSpan::CLOSE)
42                    .with_file(true)
43                    .with_line_number(true),
44            )
45            .with(filter);
46
47        tracing::subscriber::set_global_default(subscriber)
48            .expect("Failed to set global default subscriber");
49
50        tracing::debug!(
51            target: "steer_core::utils::tracing",
52            path = %log_dir.join(format!("{timestamp}.log")).display(),
53            "Tracing initialized with file output. Filter configured via RUST_LOG env var."
54        );
55    } else {
56        // Fallback to stdout if home directory not available
57        let subscriber = tracing_subscriber::registry()
58            .with(fmt::Layer::default().with_ansi(true).with_target(true))
59            .with(filter);
60
61        tracing::subscriber::set_global_default(subscriber)
62            .expect("Failed to set global default subscriber");
63
64        tracing::debug!(
65            target: "steer_core::utils::tracing",
66            "Tracing initialized with stdout output. Filter configured via RUST_LOG env var."
67        );
68    }
69
70    Ok(())
71}