use std::collections::HashMap;
use std::env;
use crate::KNOWN_CRATES;
#[derive(Debug, Clone, Default)]
pub struct CrateDebugFlags {
pub enabled_crates: HashMap<String, bool>,
}
impl CrateDebugFlags {
pub fn from_args<I>(args: I) -> Self
where
I: IntoIterator<Item = String>,
{
let mut enabled_crates = HashMap::new();
let mut debug_all = false;
for arg in args {
if arg == "--debug-all" {
debug_all = true;
continue;
}
if let Some(crate_name) = arg.strip_prefix("--debug-") {
enabled_crates.insert(crate_name.to_string(), true);
}
}
if debug_all {
for crate_name in KNOWN_CRATES {
enabled_crates.insert(crate_name.to_string(), true);
}
}
CrateDebugFlags { enabled_crates }
}
pub fn is_enabled(&self, crate_name: &str) -> bool {
self.enabled_crates.contains_key(crate_name)
}
pub fn enabled_crates(&self) -> Vec<&String> {
self.enabled_crates.keys().collect()
}
pub fn any_enabled(&self) -> bool {
!self.enabled_crates.is_empty()
}
pub fn log_level(&self, crate_name: &str) -> tracing::Level {
if self.is_enabled(crate_name) {
tracing::Level::DEBUG
} else {
tracing::Level::INFO
}
}
pub fn to_filter_string(&self) -> String {
if self.enabled_crates.is_empty() {
return "info".to_string();
}
let mut filters = Vec::new();
for crate_name in self.enabled_crates.keys() {
filters.push(format!("{}=debug", crate_name));
}
filters.push("info".to_string());
filters.join(",")
}
}
pub fn parse_debug_flags() -> CrateDebugFlags {
let mut flags = CrateDebugFlags::from_args(env::args());
if let Ok(env_var) = env::var("FEAGI_DEBUG") {
if env_var == "all" {
for crate_name in KNOWN_CRATES {
flags.enabled_crates.insert(crate_name.to_string(), true);
}
} else {
for crate_name in env_var.split(',') {
let crate_name = crate_name.trim();
if !crate_name.is_empty() {
flags.enabled_crates.insert(crate_name.to_string(), true);
}
}
}
}
flags
}
pub fn debug_flags_help() -> String {
format!(
r#"Debug Flags:
--debug-all Enable debug logging for all crates
--debug-{{crate-name}} Enable debug logging for specific crate
Available crates:
{}
Environment Variable:
FEAGI_DEBUG={{crate-name}}[,{{crate-name}}] Enable debug for crates (comma-separated)
FEAGI_DEBUG=all Enable debug for all crates
Examples:
--debug-feagi-api
--debug-feagi-api --debug-feagi-burst-engine
FEAGI_DEBUG=feagi-api,feagi-burst-engine
"#,
KNOWN_CRATES.join(", ")
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_single_crate_flag() {
let flags = CrateDebugFlags::from_args(vec!["--debug-feagi-api".to_string()]);
assert!(flags.is_enabled("feagi-api"));
assert!(!flags.is_enabled("feagi-burst-engine"));
}
#[test]
fn test_multiple_crate_flags() {
let flags = CrateDebugFlags::from_args(vec![
"--debug-feagi-api".to_string(),
"--debug-feagi-burst-engine".to_string(),
]);
assert!(flags.is_enabled("feagi-api"));
assert!(flags.is_enabled("feagi-burst-engine"));
assert!(!flags.is_enabled("feagi-bdu"));
}
#[test]
fn test_debug_all() {
let flags = CrateDebugFlags::from_args(vec!["--debug-all".to_string()]);
for crate_name in KNOWN_CRATES {
assert!(
flags.is_enabled(crate_name),
"{} should be enabled",
crate_name
);
}
}
#[test]
fn test_filter_string() {
let flags = CrateDebugFlags::from_args(vec!["--debug-feagi-api".to_string()]);
let filter = flags.to_filter_string();
assert!(filter.contains("feagi-api=debug"));
}
#[test]
fn test_log_level() {
let flags = CrateDebugFlags::from_args(vec!["--debug-feagi-api".to_string()]);
assert_eq!(flags.log_level("feagi-api"), tracing::Level::DEBUG);
assert_eq!(flags.log_level("feagi-burst-engine"), tracing::Level::INFO);
}
}