use super::TraceLevel;
use std::env;
#[derive(Debug, Clone)]
pub struct DebugConfig {
pub enabled: bool,
pub trace_level: TraceLevel,
pub collect_metrics: bool,
pub show_overlay: bool,
pub format: OutputFormat,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OutputFormat {
Text,
Json,
Compact,
}
impl DebugConfig {
#[must_use]
pub fn from_env() -> Self {
let enabled = env::var("HOJICHA_DEBUG")
.map(|v| matches!(v.to_lowercase().as_str(), "1" | "true" | "yes"))
.unwrap_or(false);
let trace_level = env::var("HOJICHA_TRACE")
.map_or_else(
|_| {
if enabled {
TraceLevel::COMMANDS.combine(TraceLevel::MESSAGES)
} else {
TraceLevel::NONE
}
},
|v| TraceLevel::parse(&v),
);
let collect_metrics = env::var("HOJICHA_METRICS")
.map(|v| matches!(v.to_lowercase().as_str(), "1" | "true" | "yes"))
.unwrap_or(enabled);
let format = env::var("HOJICHA_DEBUG_FORMAT")
.ok()
.and_then(|v| match v.to_lowercase().as_str() {
"json" => Some(OutputFormat::Json),
"compact" => Some(OutputFormat::Compact),
"text" => Some(OutputFormat::Text),
_ => None,
})
.unwrap_or(OutputFormat::Text);
Self {
enabled,
trace_level,
collect_metrics,
show_overlay: false, format,
}
}
pub fn disabled() -> Self {
Self {
enabled: false,
trace_level: TraceLevel::NONE,
collect_metrics: false,
show_overlay: false,
format: OutputFormat::Text,
}
}
pub fn full_debug() -> Self {
Self {
enabled: true,
trace_level: TraceLevel::ALL,
collect_metrics: true,
show_overlay: false,
format: OutputFormat::Text,
}
}
pub fn with_debugging(mut self, enabled: bool) -> Self {
self.enabled = enabled;
self
}
pub fn with_trace_level(mut self, level: TraceLevel) -> Self {
self.trace_level = level;
self
}
pub fn with_metrics(mut self, enabled: bool) -> Self {
self.collect_metrics = enabled;
self
}
pub fn with_format(mut self, format: OutputFormat) -> Self {
self.format = format;
self
}
}
impl Default for DebugConfig {
fn default() -> Self {
Self::from_env()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::env;
struct EnvGuard {
vars: Vec<(String, Option<String>)>,
}
impl EnvGuard {
fn new(vars: &[(&str, &str)]) -> Self {
let mut guard_vars = Vec::new();
for (key, value) in vars {
let old_value = env::var(key).ok();
env::set_var(key, value);
guard_vars.push((key.to_string(), old_value));
}
Self { vars: guard_vars }
}
}
impl Drop for EnvGuard {
fn drop(&mut self) {
for (key, old_value) in &self.vars {
match old_value {
Some(val) => env::set_var(key, val),
None => env::remove_var(key),
}
}
}
}
#[test]
fn test_env_var_parsing_variations() {
let _guard1 = EnvGuard::new(&[("HOJICHA_DEBUG", "1")]);
let config1 = DebugConfig::from_env();
assert!(config1.enabled);
let _guard2 = EnvGuard::new(&[("HOJICHA_DEBUG", "false")]);
let config2 = DebugConfig::from_env();
assert!(!config2.enabled);
let _guard3 = EnvGuard::new(&[("HOJICHA_DEBUG", "YES")]);
let config3 = DebugConfig::from_env();
assert!(config3.enabled);
}
}