1use std::env;
7
8pub fn is_trace_enabled() -> bool {
14 let trace_env = env::var("COMMAND_STREAM_TRACE").ok();
15 let verbose_env = env::var("COMMAND_STREAM_VERBOSE")
16 .map(|v| v == "true")
17 .unwrap_or(false);
18
19 match trace_env.as_deref() {
20 Some("false") => false,
21 Some("true") => true,
22 _ => verbose_env,
23 }
24}
25
26pub fn trace(category: &str, message: &str) {
39 if !is_trace_enabled() {
40 return;
41 }
42
43 let timestamp = chrono::Utc::now().to_rfc3339();
44 eprintln!("[TRACE {}] [{}] {}", timestamp, category, message);
45}
46
47pub fn trace_lazy<F>(category: &str, message_fn: F)
63where
64 F: FnOnce() -> String,
65{
66 if !is_trace_enabled() {
67 return;
68 }
69
70 trace(category, &message_fn());
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use std::env;
77 use std::sync::Mutex;
78
79 static ENV_MUTEX: Mutex<()> = Mutex::new(());
82
83 struct EnvGuard {
85 trace_value: Option<String>,
86 verbose_value: Option<String>,
87 }
88
89 impl EnvGuard {
90 fn new() -> Self {
91 EnvGuard {
92 trace_value: env::var("COMMAND_STREAM_TRACE").ok(),
93 verbose_value: env::var("COMMAND_STREAM_VERBOSE").ok(),
94 }
95 }
96 }
97
98 impl Drop for EnvGuard {
99 fn drop(&mut self) {
100 match &self.trace_value {
102 Some(v) => env::set_var("COMMAND_STREAM_TRACE", v),
103 None => env::remove_var("COMMAND_STREAM_TRACE"),
104 }
105 match &self.verbose_value {
106 Some(v) => env::set_var("COMMAND_STREAM_VERBOSE", v),
107 None => env::remove_var("COMMAND_STREAM_VERBOSE"),
108 }
109 }
110 }
111
112 #[test]
113 fn test_trace_disabled_by_default() {
114 let _lock = ENV_MUTEX.lock().unwrap();
115 let _guard = EnvGuard::new();
116
117 env::remove_var("COMMAND_STREAM_TRACE");
119 env::remove_var("COMMAND_STREAM_VERBOSE");
120 assert!(!is_trace_enabled());
121 }
122
123 #[test]
124 fn test_trace_enabled_by_verbose() {
125 let _lock = ENV_MUTEX.lock().unwrap();
126 let _guard = EnvGuard::new();
127
128 env::remove_var("COMMAND_STREAM_TRACE");
129 env::set_var("COMMAND_STREAM_VERBOSE", "true");
130 assert!(is_trace_enabled());
131 }
132
133 #[test]
134 fn test_trace_explicit_true() {
135 let _lock = ENV_MUTEX.lock().unwrap();
136 let _guard = EnvGuard::new();
137
138 env::remove_var("COMMAND_STREAM_VERBOSE");
139 env::set_var("COMMAND_STREAM_TRACE", "true");
140 assert!(is_trace_enabled());
141 }
142
143 #[test]
144 fn test_trace_explicit_false_overrides_verbose() {
145 let _lock = ENV_MUTEX.lock().unwrap();
146 let _guard = EnvGuard::new();
147
148 env::set_var("COMMAND_STREAM_TRACE", "false");
149 env::set_var("COMMAND_STREAM_VERBOSE", "true");
150 assert!(!is_trace_enabled());
151 }
152}