aperture_cli/cli/
tracing_init.rs1use tracing_subscriber::EnvFilter;
4
5struct FileOrStderr {
7 file: Option<std::sync::Mutex<std::fs::File>>,
8}
9
10impl<'a> tracing_subscriber::fmt::MakeWriter<'a> for FileOrStderr {
11 type Writer = Box<dyn std::io::Write + 'a>;
12
13 fn make_writer(&'a self) -> Self::Writer {
14 self.file
15 .as_ref()
16 .and_then(|mutex| mutex.lock().ok())
17 .and_then(|file| file.try_clone().ok())
18 .map_or_else(
19 || Box::new(std::io::stderr()) as Self::Writer,
20 |cloned| Box::new(cloned) as Self::Writer,
21 )
22 }
23}
24
25pub fn init_tracing(verbosity: u8) {
27 use std::fs::OpenOptions;
28 use std::sync::Mutex;
29 use tracing_subscriber::fmt::format::FmtSpan;
30 use tracing_subscriber::layer::SubscriberExt;
31 use tracing_subscriber::util::SubscriberInitExt;
32
33 let log_level_str = if verbosity > 0 {
34 match verbosity {
35 1 => "debug".to_string(),
36 _ => "trace".to_string(),
37 }
38 } else {
39 std::env::var("APERTURE_LOG").unwrap_or_else(|_| "error".to_string())
40 };
41
42 let env_filter = EnvFilter::try_new(&log_level_str)
43 .or_else(|_| EnvFilter::try_new("error"))
44 .unwrap_or_else(|_| EnvFilter::new("error"));
45
46 let log_format = std::env::var("APERTURE_LOG_FORMAT")
47 .map_or_else(|_| "text".to_string(), |s| s.to_lowercase());
48
49 if log_format != "json" && log_format != "text" {
50 eprintln!(
51 "Warning: Unrecognized APERTURE_LOG_FORMAT '{log_format}'. Valid values: 'json', 'text'. Using 'text'."
52 );
53 }
54
55 let writer = std::env::var("APERTURE_LOG_FILE").ok().map_or_else(
56 || FileOrStderr { file: None },
57 |path| match OpenOptions::new().create(true).append(true).open(&path) {
58 Ok(file) => FileOrStderr {
59 file: Some(Mutex::new(file)),
60 },
61 Err(e) => {
62 eprintln!("Warning: Could not open log file '{path}': {e}. Using stderr.");
63 FileOrStderr { file: None }
64 }
65 },
66 );
67
68 if log_format == "json" {
69 let json_layer = tracing_subscriber::fmt::layer()
70 .json()
71 .with_span_list(false)
72 .with_target(true)
73 .with_thread_ids(false)
74 .with_line_number(true)
75 .with_writer(writer);
76 tracing_subscriber::registry()
77 .with(env_filter)
78 .with(json_layer)
79 .init();
80 } else {
81 let fmt_layer = tracing_subscriber::fmt::layer()
82 .pretty()
83 .with_span_events(FmtSpan::CLOSE)
84 .with_target(false)
85 .with_thread_ids(false)
86 .with_line_number(false)
87 .with_writer(writer);
88 tracing_subscriber::registry()
89 .with(env_filter)
90 .with(fmt_layer)
91 .init();
92 }
93}