lc_core/observability/
mod.rs1mod agent_metrics;
11mod error;
12
13pub use agent_metrics::AgentMetrics;
14pub use error::ObsError;
15
16use crate::language_models::TokenUsage;
17use serde::Serialize;
18
19#[derive(Debug, Clone, Serialize)]
21#[serde(tag = "kind", rename_all = "snake_case")]
22pub enum ObsEvent {
23 TokenUsage(TokenUsage),
25 AgentMetrics(AgentMetrics),
27}
28
29#[async_trait::async_trait]
32pub trait MetricsSink: Send + Sync {
33 async fn export(&self, event: &ObsEvent) -> Result<(), ObsError>;
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41 use std::time::Duration;
42
43 fn sample_usage() -> TokenUsage {
44 TokenUsage {
45 prompt_tokens: 10,
46 completion_tokens: 5,
47 total_tokens: 15,
48 }
49 }
50
51 #[test]
52 fn obs_event_token_usage_serializes_with_kind_tag() {
53 let json = serde_json::to_string(&ObsEvent::TokenUsage(sample_usage())).unwrap();
54 let v: serde_json::Value = serde_json::from_str(&json).unwrap();
55 assert_eq!(v["kind"], "token_usage");
56 assert_eq!(v["prompt_tokens"], 10);
57 assert_eq!(v["completion_tokens"], 5);
58 assert_eq!(v["total_tokens"], 15);
59 }
60
61 #[test]
62 fn obs_event_agent_metrics_serializes_with_kind_tag() {
63 let m = AgentMetrics {
64 trace_id: Some("trace-x".to_string()),
65 llm_calls: 2,
66 cache_hits: 0,
67 tool_calls: 1,
68 compactions: 1,
69 total_tokens: Some(30),
70 duration: Duration::from_millis(100),
71 };
72 let json = serde_json::to_string(&ObsEvent::AgentMetrics(m)).unwrap();
73 let v: serde_json::Value = serde_json::from_str(&json).unwrap();
74 assert_eq!(v["kind"], "agent_metrics");
75 assert_eq!(v["llm_calls"], 2);
76 assert_eq!(v["tool_calls"], 1);
77 assert_eq!(v["total_tokens"], 30);
78 }
79}