agentzero_core/common/
mod.rs1pub mod local_providers;
2pub mod paths;
3pub mod privacy_helpers;
4pub mod url_policy;
5pub mod util;
6
7use std::collections::HashMap;
8use tracing_subscriber::layer::SubscriberExt;
9use tracing_subscriber::util::SubscriberInitExt;
10use tracing_subscriber::EnvFilter;
11
12#[derive(Debug, Clone, Default, PartialEq)]
14pub enum LogFormat {
15 #[default]
17 Text,
18 Json,
20}
21
22#[derive(Debug, Clone, Default)]
24pub struct TracingOptions {
25 pub format: LogFormat,
27 pub level: Option<String>,
29 pub modules: HashMap<String, String>,
31}
32
33pub fn init_tracing(verbosity: u8) {
39 let format = match std::env::var("AGENTZERO__LOGGING__FORMAT")
40 .unwrap_or_default()
41 .to_lowercase()
42 .as_str()
43 {
44 "json" => LogFormat::Json,
45 _ => LogFormat::Text,
46 };
47
48 let level = std::env::var("AGENTZERO__LOGGING__LEVEL")
49 .ok()
50 .unwrap_or_else(|| verbosity_to_level(verbosity).to_string());
51
52 init_tracing_with_options(&TracingOptions {
53 format,
54 level: Some(level),
55 ..Default::default()
56 });
57}
58
59pub fn init_tracing_with_options(opts: &TracingOptions) {
61 let base_level = opts.level.as_deref().unwrap_or("error");
62 let filter = build_env_filter(base_level, &opts.modules);
63
64 let registry = tracing_subscriber::registry().with(filter);
65
66 match opts.format {
67 LogFormat::Json => {
68 registry
69 .with(tracing_subscriber::fmt::layer().json().with_target(true))
70 .try_init()
71 .ok();
72 }
73 LogFormat::Text => {
74 registry
75 .with(tracing_subscriber::fmt::layer().with_target(false))
76 .try_init()
77 .ok();
78 }
79 }
80}
81
82fn build_env_filter(base_level: &str, modules: &HashMap<String, String>) -> EnvFilter {
83 if let Ok(rust_log) = std::env::var("RUST_LOG") {
85 return EnvFilter::new(rust_log);
86 }
87
88 let mut directives = base_level.to_string();
89 for (module, level) in modules {
90 directives.push_str(&format!(",{module}={level}"));
91 }
92 EnvFilter::new(directives)
93}
94
95fn verbosity_to_level(verbosity: u8) -> &'static str {
96 match verbosity {
97 0 | 1 => "error",
98 2 => "info",
99 3 => "debug",
100 _ => "trace",
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn verbosity_level_one_maps_to_error() {
110 assert_eq!(verbosity_to_level(1), "error");
111 }
112
113 #[test]
114 fn verbosity_level_two_maps_to_info() {
115 assert_eq!(verbosity_to_level(2), "info");
116 }
117
118 #[test]
119 fn verbosity_level_three_maps_to_debug() {
120 assert_eq!(verbosity_to_level(3), "debug");
121 }
122
123 #[test]
124 fn verbosity_level_four_or_more_maps_to_trace() {
125 assert_eq!(verbosity_to_level(4), "trace");
126 assert_eq!(verbosity_to_level(8), "trace");
127 }
128
129 #[test]
130 fn log_format_default_is_text() {
131 assert_eq!(LogFormat::default(), LogFormat::Text);
132 }
133
134 #[test]
135 fn tracing_options_default_uses_text_format() {
136 let opts = TracingOptions::default();
137 assert_eq!(opts.format, LogFormat::Text);
138 assert!(opts.level.is_none());
139 assert!(opts.modules.is_empty());
140 }
141
142 #[test]
143 fn build_env_filter_with_module_overrides() {
144 let mut modules = HashMap::new();
145 modules.insert("agentzero_gateway".to_string(), "debug".to_string());
146 let _ = build_env_filter("info", &modules);
148 }
149}