hojicha_core/debug/
config.rs1use super::TraceLevel;
4use std::env;
5
6#[derive(Debug, Clone)]
8pub struct DebugConfig {
9 pub enabled: bool,
11 pub trace_level: TraceLevel,
13 pub collect_metrics: bool,
15 pub show_overlay: bool,
17 pub format: OutputFormat,
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum OutputFormat {
24 Text,
26 Json,
28 Compact,
30}
31
32impl DebugConfig {
33 #[must_use]
41 pub fn from_env() -> Self {
42 let enabled = env::var("HOJICHA_DEBUG")
43 .map(|v| matches!(v.to_lowercase().as_str(), "1" | "true" | "yes"))
44 .unwrap_or(false);
45
46 let trace_level = env::var("HOJICHA_TRACE")
47 .map_or_else(
48 |_| {
49 if enabled {
50 TraceLevel::COMMANDS.combine(TraceLevel::MESSAGES)
51 } else {
52 TraceLevel::NONE
53 }
54 },
55 |v| TraceLevel::parse(&v),
56 );
57
58 let collect_metrics = env::var("HOJICHA_METRICS")
59 .map(|v| matches!(v.to_lowercase().as_str(), "1" | "true" | "yes"))
60 .unwrap_or(enabled);
61
62 let format = env::var("HOJICHA_DEBUG_FORMAT")
63 .ok()
64 .and_then(|v| match v.to_lowercase().as_str() {
65 "json" => Some(OutputFormat::Json),
66 "compact" => Some(OutputFormat::Compact),
67 "text" => Some(OutputFormat::Text),
68 _ => None,
69 })
70 .unwrap_or(OutputFormat::Text);
71
72 Self {
73 enabled,
74 trace_level,
75 collect_metrics,
76 show_overlay: false, format,
78 }
79 }
80
81 pub fn disabled() -> Self {
83 Self {
84 enabled: false,
85 trace_level: TraceLevel::NONE,
86 collect_metrics: false,
87 show_overlay: false,
88 format: OutputFormat::Text,
89 }
90 }
91
92 pub fn full_debug() -> Self {
94 Self {
95 enabled: true,
96 trace_level: TraceLevel::ALL,
97 collect_metrics: true,
98 show_overlay: false,
99 format: OutputFormat::Text,
100 }
101 }
102
103 pub fn with_debugging(mut self, enabled: bool) -> Self {
105 self.enabled = enabled;
106 self
107 }
108
109 pub fn with_trace_level(mut self, level: TraceLevel) -> Self {
111 self.trace_level = level;
112 self
113 }
114
115 pub fn with_metrics(mut self, enabled: bool) -> Self {
117 self.collect_metrics = enabled;
118 self
119 }
120
121 pub fn with_format(mut self, format: OutputFormat) -> Self {
123 self.format = format;
124 self
125 }
126}
127
128impl Default for DebugConfig {
129 fn default() -> Self {
130 Self::from_env()
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137 use std::env;
138
139 struct EnvGuard {
141 vars: Vec<(String, Option<String>)>,
142 }
143
144 impl EnvGuard {
145 fn new(vars: &[(&str, &str)]) -> Self {
146 let mut guard_vars = Vec::new();
147 for (key, value) in vars {
148 let old_value = env::var(key).ok();
149 env::set_var(key, value);
150 guard_vars.push((key.to_string(), old_value));
151 }
152 Self { vars: guard_vars }
153 }
154 }
155
156 impl Drop for EnvGuard {
157 fn drop(&mut self) {
158 for (key, old_value) in &self.vars {
159 match old_value {
160 Some(val) => env::set_var(key, val),
161 None => env::remove_var(key),
162 }
163 }
164 }
165 }
166
167 #[test]
169 fn test_env_var_parsing_variations() {
170 let _guard1 = EnvGuard::new(&[("HOJICHA_DEBUG", "1")]);
172 let config1 = DebugConfig::from_env();
173 assert!(config1.enabled);
174
175 let _guard2 = EnvGuard::new(&[("HOJICHA_DEBUG", "false")]);
177 let config2 = DebugConfig::from_env();
178 assert!(!config2.enabled);
179
180 let _guard3 = EnvGuard::new(&[("HOJICHA_DEBUG", "YES")]);
182 let config3 = DebugConfig::from_env();
183 assert!(config3.enabled);
184 }
185}