juncture_telemetry/
trace_store.rs1use crate::models::{EnrichedSession, Id, ModelStats, Observation, Session, SummaryStats, Trace};
8use chrono::{DateTime, Utc};
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, thiserror::Error)]
13pub enum StoreError {
14 #[error("storage error: {0}")]
16 Storage(String),
17 #[error("serialization error: {0}")]
19 Serialization(#[from] serde_json::Error),
20 #[error("not found: {0}")]
22 NotFound(String),
23}
24
25#[derive(Clone, Debug, Default, Serialize, Deserialize)]
27#[serde(rename_all = "camelCase")]
28pub struct TraceQuery {
29 pub session_id: Option<String>,
31 pub user_id: Option<String>,
33 pub name: Option<String>,
35 pub environment: Option<String>,
37 pub tags: Vec<String>,
39 pub from_timestamp: Option<DateTime<Utc>>,
41 pub to_timestamp: Option<DateTime<Utc>>,
43 pub page: Option<u32>,
45 pub page_size: Option<u32>,
47}
48
49#[derive(Clone, Debug, Serialize, Deserialize)]
51#[serde(rename_all = "camelCase")]
52pub struct PaginatedResponse<T> {
53 pub data: Vec<T>,
55 pub page: u32,
57 pub page_size: u32,
59 pub total_count: u64,
61}
62
63#[derive(Clone, Debug, Serialize, Deserialize)]
65#[serde(rename_all = "camelCase")]
66pub struct DailyStats {
67 pub date: String,
69 pub trace_count: u64,
71 pub observation_count: u64,
73 pub total_tokens: u64,
75 pub total_cost: f64,
77 pub total_duration_ms: u64,
79}
80
81#[async_trait::async_trait]
86pub trait TraceStore: Send + Sync + 'static {
87 async fn upsert_trace(&self, trace: &Trace) -> Result<(), StoreError>;
89
90 async fn insert_observation(&self, observation: &Observation) -> Result<(), StoreError>;
92
93 async fn upsert_session(&self, session: &Session) -> Result<(), StoreError>;
95
96 async fn get_trace(&self, id: Id) -> Result<Option<TraceWithObservations>, StoreError>;
98
99 async fn query_traces(
101 &self,
102 query: &TraceQuery,
103 ) -> Result<PaginatedResponse<Trace>, StoreError>;
104
105 async fn get_session(&self, id: &str) -> Result<Option<Session>, StoreError>;
107
108 async fn query_sessions(
110 &self,
111 page: u32,
112 page_size: u32,
113 ) -> Result<PaginatedResponse<Session>, StoreError>;
114
115 async fn get_daily_stats(
117 &self,
118 from: DateTime<Utc>,
119 to: DateTime<Utc>,
120 ) -> Result<Vec<DailyStats>, StoreError>;
121
122 async fn get_model_stats(&self) -> Result<Vec<ModelStats>, StoreError>;
124
125 async fn get_summary_stats(&self) -> Result<SummaryStats, StoreError>;
127
128 async fn query_enriched_sessions(
130 &self,
131 page: u32,
132 page_size: u32,
133 ) -> Result<PaginatedResponse<EnrichedSession>, StoreError>;
134
135 async fn flush(&self) -> Result<(), StoreError>;
137}
138
139#[derive(Clone, Debug, Serialize, Deserialize)]
141#[serde(rename_all = "camelCase")]
142pub struct TraceWithObservations {
143 pub trace: Trace,
145 pub observations: Vec<Observation>,
147}