1use crate::config::PipelineConfig;
6use crate::error::CliResult;
7use faucet_core::{ObservabilityConfig, PrometheusConfig, TracingConfig, install_observability};
8
9pub fn resolve_tracing_level(cli_flag: Option<&str>, yaml_level: Option<&str>) -> Option<String> {
13 if let Some(l) = cli_flag {
14 return Some(l.to_string());
15 }
16 if let Ok(l) = std::env::var("FAUCET_LOG")
17 && !l.is_empty()
18 {
19 return Some(l);
20 }
21 if let Ok(l) = std::env::var("RUST_LOG")
22 && !l.is_empty()
23 {
24 return Some(l);
25 }
26 yaml_level.map(|s| s.to_string())
27}
28
29pub fn install(cfg: &PipelineConfig) -> CliResult<()> {
32 let level = resolve_tracing_level(
33 None,
34 cfg.observability
35 .as_ref()
36 .and_then(|o| o.tracing.as_ref())
37 .and_then(|t| t.level.as_deref()),
38 );
39 let obs_cfg = ObservabilityConfig {
40 prometheus: cfg
41 .observability
42 .as_ref()
43 .and_then(|o| o.prometheus.as_ref())
44 .map(|p| PrometheusConfig {
45 listen: p.listen.clone(),
46 buckets: p.buckets.clone(),
47 }),
48 tracing: level.map(|l| TracingConfig { level: l }),
49 };
50 let report = install_observability(&obs_cfg)?;
51 if let Some(addr) = report.prometheus_listen.as_deref() {
52 tracing::info!("Prometheus /metrics listening on {addr}");
53 }
54 if report.prometheus_already_installed {
55 tracing::warn!(
56 "Prometheus recorder already installed; metrics route through the existing recorder"
57 );
58 }
59 if report.tracing_already_installed {
60 tracing::warn!(
61 "tracing subscriber already installed; logs route through the existing subscriber"
62 );
63 }
64 Ok(())
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use std::sync::Mutex;
71 static ENV_LOCK: Mutex<()> = Mutex::new(());
72
73 fn with_clean_env<F: FnOnce()>(f: F) {
74 let _g = ENV_LOCK.lock().unwrap();
75 unsafe {
76 std::env::remove_var("FAUCET_LOG");
77 std::env::remove_var("RUST_LOG");
78 }
79 f();
80 }
81
82 #[test]
83 fn cli_flag_beats_env_and_yaml() {
84 with_clean_env(|| {
85 unsafe {
86 std::env::set_var("FAUCET_LOG", "debug");
87 std::env::set_var("RUST_LOG", "trace");
88 }
89 assert_eq!(
90 resolve_tracing_level(Some("error"), Some("info")).as_deref(),
91 Some("error")
92 );
93 });
94 }
95
96 #[test]
97 fn faucet_log_beats_rust_log_and_yaml() {
98 with_clean_env(|| {
99 unsafe {
100 std::env::set_var("FAUCET_LOG", "debug");
101 std::env::set_var("RUST_LOG", "trace");
102 }
103 assert_eq!(
104 resolve_tracing_level(None, Some("info")).as_deref(),
105 Some("debug")
106 );
107 });
108 }
109
110 #[test]
111 fn rust_log_beats_yaml() {
112 with_clean_env(|| {
113 unsafe {
114 std::env::set_var("RUST_LOG", "trace");
115 }
116 assert_eq!(
117 resolve_tracing_level(None, Some("info")).as_deref(),
118 Some("trace")
119 );
120 });
121 }
122
123 #[test]
124 fn yaml_used_when_no_flag_or_env() {
125 with_clean_env(|| {
126 assert_eq!(
127 resolve_tracing_level(None, Some("info")).as_deref(),
128 Some("info")
129 );
130 });
131 }
132
133 #[test]
134 fn none_returned_when_nothing_set() {
135 with_clean_env(|| {
136 assert_eq!(resolve_tracing_level(None, None), None);
137 });
138 }
139}