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(|_| "warn".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!(
53 "Warning: Unrecognized APERTURE_LOG_FORMAT '{log_format}'. Valid values: 'json', 'text'. Using 'text'."
54 );
55 }
56
57 let writer = std::env::var("APERTURE_LOG_FILE").ok().map_or_else(
58 || FileOrStderr { file: None },
59 |path| match OpenOptions::new().create(true).append(true).open(&path) {
60 Ok(file) => FileOrStderr {
61 file: Some(Mutex::new(file)),
62 },
63 Err(e) => {
64 eprintln!("Warning: Could not open log file '{path}': {e}. Using stderr.");
67 FileOrStderr { file: None }
68 }
69 },
70 );
71
72 if log_format == "json" {
73 let json_layer = tracing_subscriber::fmt::layer()
74 .json()
75 .with_span_list(false)
76 .with_target(true)
77 .with_thread_ids(false)
78 .with_line_number(true)
79 .with_writer(writer);
80 tracing_subscriber::registry()
81 .with(env_filter)
82 .with(json_layer)
83 .init();
84 } else {
85 let fmt_layer = tracing_subscriber::fmt::layer()
86 .pretty()
87 .with_span_events(FmtSpan::CLOSE)
88 .with_target(false)
89 .with_thread_ids(false)
90 .with_line_number(false)
91 .with_writer(writer);
92 tracing_subscriber::registry()
93 .with(env_filter)
94 .with(fmt_layer)
95 .init();
96 }
97}