use std::collections::HashMap;
use std::sync::atomic::{AtomicU64, Ordering};
static EVENT_SEQUENCE: AtomicU64 = AtomicU64::new(0);
static HAS_WARNED_NO_EVENT_LOGGER: std::sync::atomic::AtomicBool =
std::sync::atomic::AtomicBool::new(false);
fn is_user_prompt_logging_enabled() -> bool {
std::env::var("OTEL_LOG_USER_PROMPTS")
.ok()
.map(|v| {
let v = v.to_lowercase();
v == "1" || v == "true" || v == "yes"
})
.unwrap_or(false)
}
pub fn redact_if_disabled(content: &str) -> String {
if is_user_prompt_logging_enabled() {
content.to_string()
} else {
"<REDACTED>".to_string()
}
}
pub async fn log_otel_event(event_name: &str, metadata: Option<HashMap<String, String>>) {
if std::env::var("RUST_ENV").ok().as_deref() == Some("test") {
return;
}
let metadata = metadata.unwrap_or_default();
let sequence = EVENT_SEQUENCE.fetch_add(1, Ordering::SeqCst);
let mut attributes = get_telemetry_attributes();
attributes.insert("event.name".to_string(), event_name.to_string());
attributes.insert(
"event.timestamp".to_string(),
chrono::Utc::now().to_rfc3339(),
);
attributes.insert("event.sequence".to_string(), sequence.to_string());
if let Some(prompt_id) = get_prompt_id() {
attributes.insert("prompt.id".to_string(), prompt_id);
}
if let Ok(workspace_dir) = std::env::var("AI_CODE_WORKSPACE_HOST_PATHS") {
attributes.insert(
"workspace.host_paths".to_string(),
workspace_dir.replace('|', ","),
);
}
for (key, value) in metadata {
attributes.insert(key, value);
}
tracing::debug!(
event = event_name,
?attributes,
"claude_code.{}",
event_name
);
}
fn get_telemetry_attributes() -> HashMap<String, String> {
crate::utils::telemetry_attributes::get_telemetry_attributes()
}
fn get_prompt_id() -> Option<String> {
std::env::var("AI_CODE_PROMPT_ID").ok()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_redact_if_disabled() {
std::env::remove_var("OTEL_LOG_USER_PROMPTS");
assert_eq!(redact_if_disabled("secret"), "<REDACTED>");
}
#[test]
fn test_redact_if_enabled() {
std::env::set_var("OTEL_LOG_USER_PROMPTS", "1");
assert_eq!(redact_if_disabled("visible"), "visible");
std::env::remove_var("OTEL_LOG_USER_PROMPTS");
}
}