llm_kernel/telemetry/
sink.rs1use crate::telemetry::events::TelemetryEvent;
4
5pub trait TelemetrySink: Send + Sync {
7 fn track(&mut self, event: TelemetryEvent);
9
10 fn flush(&mut self) {}
12}
13
14pub struct ConsoleSink {
17 app_name: String,
18}
19
20impl ConsoleSink {
21 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
36pub 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}