Skip to main content

agent_code_lib/services/
telemetry.rs

1//! Telemetry and observability attributes.
2//!
3//! Structured attributes attached to API calls and tool executions
4//! for performance monitoring and debugging. These are local-only
5//! (no data is sent externally) and can be consumed by logging,
6//! tracing, or exported via OpenTelemetry.
7
8use std::collections::HashMap;
9use std::time::Instant;
10
11/// Structured attributes for a single API call or tool execution.
12#[derive(Debug, Clone, Default)]
13pub struct TelemetrySpan {
14    pub attributes: HashMap<String, String>,
15    pub start_time: Option<Instant>,
16    pub end_time: Option<Instant>,
17}
18
19impl TelemetrySpan {
20    pub fn new() -> Self {
21        Self {
22            start_time: Some(Instant::now()),
23            ..Default::default()
24        }
25    }
26
27    pub fn set(&mut self, key: &str, value: impl ToString) {
28        self.attributes.insert(key.to_string(), value.to_string());
29    }
30
31    pub fn finish(&mut self) {
32        self.end_time = Some(Instant::now());
33    }
34
35    pub fn duration_ms(&self) -> Option<u64> {
36        match (self.start_time, self.end_time) {
37            (Some(start), Some(end)) => Some(end.duration_since(start).as_millis() as u64),
38            _ => None,
39        }
40    }
41}
42
43/// Common attribute keys.
44pub mod attrs {
45    pub const MODEL: &str = "model";
46    pub const TOOL_NAME: &str = "tool.name";
47    pub const TOOL_USE_ID: &str = "tool.use_id";
48    pub const INPUT_TOKENS: &str = "tokens.input";
49    pub const OUTPUT_TOKENS: &str = "tokens.output";
50    pub const CACHE_READ_TOKENS: &str = "tokens.cache_read";
51    pub const CACHE_WRITE_TOKENS: &str = "tokens.cache_write";
52    pub const COST_USD: &str = "cost.usd";
53    pub const TURN_NUMBER: &str = "turn.number";
54    pub const SESSION_ID: &str = "session.id";
55    pub const EFFORT: &str = "effort";
56    pub const THINKING_MODE: &str = "thinking.mode";
57    pub const TTFT_MS: &str = "ttft.ms";
58    pub const DURATION_MS: &str = "duration.ms";
59    pub const IS_ERROR: &str = "is_error";
60    pub const ERROR_TYPE: &str = "error.type";
61    pub const PERMISSION_DECISION: &str = "permission.decision";
62}
63
64/// Build telemetry attributes for an API call.
65pub fn api_call_span(model: &str, turn: usize, session_id: &str) -> TelemetrySpan {
66    let mut span = TelemetrySpan::new();
67    span.set(attrs::MODEL, model);
68    span.set(attrs::TURN_NUMBER, turn);
69    span.set(attrs::SESSION_ID, session_id);
70    span
71}
72
73/// Build telemetry attributes for a tool execution.
74pub fn tool_span(tool_name: &str, tool_use_id: &str) -> TelemetrySpan {
75    let mut span = TelemetrySpan::new();
76    span.set(attrs::TOOL_NAME, tool_name);
77    span.set(attrs::TOOL_USE_ID, tool_use_id);
78    span
79}
80
81/// Record usage into a span.
82pub fn record_usage(span: &mut TelemetrySpan, usage: &crate::llm::message::Usage) {
83    span.set(attrs::INPUT_TOKENS, usage.input_tokens);
84    span.set(attrs::OUTPUT_TOKENS, usage.output_tokens);
85    span.set(attrs::CACHE_READ_TOKENS, usage.cache_read_input_tokens);
86    span.set(attrs::CACHE_WRITE_TOKENS, usage.cache_creation_input_tokens);
87}