/ crates / distrox-cli / src / logging.rs
logging.rs
 1  use std::collections::HashSet;
 2  
 3  use tracing_subscriber::Layer;
 4  use tracing_subscriber::layer::SubscriberExt;
 5  
 6  use crate::cli::Logger;
 7  
 8  pub fn setup(cli: &crate::cli::Cli) -> LoggingGuards {
 9      let mut env_filter = tracing_subscriber::EnvFilter::from_default_env();
10      let log_level = cli.verbosity;
11      let loggers = cli.logger.iter().flatten().copied().collect::<HashSet<_>>();
12  
13      if let Some(level_filter) = log_level
14          .is_present()
15          .then(|| log_level.tracing_level_filter())
16      {
17          let directive = tracing_subscriber::filter::Directive::from(level_filter);
18          env_filter = env_filter.add_directive(directive);
19      }
20  
21      let (file_writer, guard) = {
22          let tpl = loggers.contains(&Logger::File).then(|| {
23              tracing_appender::non_blocking({
24                  let cwd = std::env::current_dir().expect("to get the current dirtectory");
25                  let pid = std::process::id();
26                  let filepath = cwd.join(format!("distrox-cli.{pid}.log"));
27  
28                  std::fs::OpenOptions::new()
29                      .append(true)
30                      .create(true)
31                      .create_new(true)
32                      .open(filepath)
33                      .expect("to open a file for log output")
34              })
35          });
36  
37          match tpl {
38              Some((writer, guard)) => (Some(writer), Some(guard)),
39              _ => (None, None),
40          }
41      };
42  
43      let filter = format!("{env_filter}");
44      let subscriber = tracing_subscriber::registry::Registry::default().with(
45          tracing_subscriber::fmt::layer()
46              .with_writer(std::io::stderr)
47              .with_filter(env_filter),
48      );
49  
50      let subscriber = {
51          #[cfg(feature = "tracy")]
52          {
53              subscriber.with(
54                  loggers
55                      .contains(&Logger::Tracy)
56                      .then(tracing_tracy::TracyLayer::default),
57              )
58          }
59  
60          #[cfg(not(feature = "tracy"))]
61          {
62              subscriber
63          }
64      };
65  
66      // This is fucked up, feel free to improve
67      if let Err(e) = match file_writer {
68          None => tracing::subscriber::set_global_default(subscriber),
69          Some(file_writer) => {
70              let subscriber =
71                  subscriber.with(tracing_subscriber::fmt::layer().with_writer(file_writer));
72              tracing::subscriber::set_global_default(subscriber)
73          }
74      } {
75          eprintln!("Failed to set global logging subscriber: {e:?}");
76          std::process::exit(1)
77      };
78  
79      tracing::info!("Logging setup done with following filter: {filter}");
80      LoggingGuards { guard }
81  }
82  
83  pub struct LoggingGuards {
84      #[expect(unused, reason = "Guard type")]
85      guard: Option<tracing_appender::non_blocking::WorkerGuard>,
86  }