adk_telemetry/events.rs
1//! Content event emitter for opt-in prompt/completion capture.
2//!
3//! Emits span events containing prompt or completion text when
4//! [`SemconvConfig::capture_content`](crate::config::SemconvConfig::capture_content)
5//! is enabled.
6
7use tracing::Span;
8
9use crate::config::SemconvConfig;
10
11/// Emits opt-in content events on the current span.
12///
13/// Only emits when [`SemconvConfig::capture_content`] is `true`.
14/// When content capture is disabled (the default), these methods are no-ops.
15///
16/// # Example
17/// ```
18/// use adk_telemetry::config::SemconvConfig;
19/// use adk_telemetry::events::ContentEventEmitter;
20///
21/// let config = SemconvConfig { capture_content: true };
22/// ContentEventEmitter::emit_prompt(&config, "What is the weather?");
23/// ContentEventEmitter::emit_completion(&config, "The weather is sunny.");
24/// ```
25pub struct ContentEventEmitter;
26
27impl ContentEventEmitter {
28 /// Emit a `gen_ai.content.prompt` span event with the prompt text.
29 ///
30 /// Only emits when `config.capture_content` is `true`.
31 pub fn emit_prompt(config: &SemconvConfig, prompt: &str) {
32 if !config.capture_content {
33 return;
34 }
35 let span = Span::current();
36 if span.is_none() {
37 tracing::debug!("content event emitter: no active span for prompt event");
38 return;
39 }
40 span.in_scope(|| {
41 tracing::info!(event_name = "gen_ai.content.prompt", content = prompt);
42 });
43 }
44
45 /// Emit a `gen_ai.content.completion` span event with the completion text.
46 ///
47 /// Only emits when `config.capture_content` is `true`.
48 pub fn emit_completion(config: &SemconvConfig, completion: &str) {
49 if !config.capture_content {
50 return;
51 }
52 let span = Span::current();
53 if span.is_none() {
54 tracing::debug!("content event emitter: no active span for completion event");
55 return;
56 }
57 span.in_scope(|| {
58 tracing::info!(event_name = "gen_ai.content.completion", content = completion);
59 });
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 #[test]
68 fn test_emit_prompt_disabled_is_noop() {
69 let config = SemconvConfig::default();
70 // Should not panic even without an active span
71 ContentEventEmitter::emit_prompt(&config, "test prompt");
72 }
73
74 #[test]
75 fn test_emit_completion_disabled_is_noop() {
76 let config = SemconvConfig::default();
77 // Should not panic even without an active span
78 ContentEventEmitter::emit_completion(&config, "test completion");
79 }
80}