Skip to main content

llm_kernel/telemetry/
sink.rs

1//! Telemetry sink trait and implementations.
2
3use crate::telemetry::events::TelemetryEvent;
4
5/// Trait for telemetry event sinks.
6pub trait TelemetrySink: Send + Sync {
7    /// Track a telemetry event.
8    fn track(&mut self, event: TelemetryEvent);
9
10    /// Flush any buffered events.
11    fn flush(&mut self) {}
12}
13
14/// Console telemetry sink — logs events via `tracing::info!`.
15/// Useful for development and debugging.
16pub struct ConsoleSink {
17    app_name: String,
18}
19
20impl ConsoleSink {
21    /// Create a new console sink with the given app name.
22    pub fn new(app_name: impl Into<String>) -> Self {
23        Self {
24            app_name: app_name.into(),
25        }
26    }
27}
28
29impl TelemetrySink for ConsoleSink {
30    fn track(&mut self, event: TelemetryEvent) {
31        let json = serde_json::to_string(&event).unwrap_or_default();
32        tracing::info!(app = %self.app_name, event = %json, "telemetry");
33    }
34}
35
36/// No-op telemetry sink — discards all events.
37/// Use when telemetry is opted out.
38pub struct NoopSink;
39
40impl TelemetrySink for NoopSink {
41    fn track(&mut self, _event: TelemetryEvent) {}
42}
43
44#[cfg(test)]
45mod tests {
46    use super::*;
47    use crate::telemetry::events::FailureClass;
48
49    #[test]
50    fn console_sink_does_not_panic() {
51        use crate::telemetry::events::ToolName;
52        let mut sink = ConsoleSink::new("test");
53        sink.track(TelemetryEvent::ToolInvoked {
54            tool: ToolName::Search,
55        });
56        sink.track(TelemetryEvent::Error {
57            class: FailureClass::Network,
58        });
59        sink.flush();
60    }
61
62    #[test]
63    fn noop_sink_discards() {
64        use crate::telemetry::events::ToolName;
65        let mut sink = NoopSink;
66        sink.track(TelemetryEvent::ToolInvoked {
67            tool: ToolName::Search,
68        });
69        sink.flush();
70    }
71}