Skip to main content

dakera_client/
analytics.rs

1//! Analytics operations for the Dakera client.
2
3use serde::{Deserialize, Serialize};
4
5use crate::error::Result;
6use crate::DakeraClient;
7
8// ============================================================================
9// Analytics Types
10// ============================================================================
11
12/// Analytics overview response
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct AnalyticsOverview {
15    pub total_queries: u64,
16    pub avg_latency_ms: f64,
17    pub p95_latency_ms: f64,
18    pub p99_latency_ms: f64,
19    pub queries_per_second: f64,
20    pub error_rate: f64,
21    pub cache_hit_rate: f64,
22    pub storage_used_bytes: u64,
23    pub total_vectors: u64,
24    pub total_namespaces: u64,
25    pub uptime_seconds: u64,
26}
27
28/// Latency analytics response
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct LatencyAnalytics {
31    pub period: String,
32    pub avg_ms: f64,
33    pub p50_ms: f64,
34    pub p95_ms: f64,
35    pub p99_ms: f64,
36    pub max_ms: f64,
37    #[serde(default)]
38    pub by_operation: std::collections::HashMap<String, OperationLatency>,
39}
40
41/// Per-operation latency stats
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct OperationLatency {
44    pub avg_ms: f64,
45    pub p95_ms: f64,
46    pub count: u64,
47}
48
49/// Throughput analytics response
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct ThroughputAnalytics {
52    pub period: String,
53    pub total_operations: u64,
54    pub operations_per_second: f64,
55    #[serde(default)]
56    pub by_operation: std::collections::HashMap<String, u64>,
57}
58
59/// Storage analytics response
60#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct StorageAnalytics {
62    pub total_bytes: u64,
63    pub index_bytes: u64,
64    pub data_bytes: u64,
65    #[serde(default)]
66    pub by_namespace: std::collections::HashMap<String, NamespaceStorage>,
67}
68
69/// Per-namespace storage stats
70#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct NamespaceStorage {
72    pub bytes: u64,
73    pub vector_count: u64,
74}
75
76// ============================================================================
77// Analytics Client Methods
78// ============================================================================
79
80impl DakeraClient {
81    /// Get analytics overview
82    pub async fn analytics_overview(
83        &self,
84        period: Option<&str>,
85        namespace: Option<&str>,
86    ) -> Result<AnalyticsOverview> {
87        let mut url = format!("{}/v1/analytics/overview", self.base_url);
88        let mut params = Vec::new();
89        if let Some(p) = period {
90            params.push(format!("period={}", p));
91        }
92        if let Some(ns) = namespace {
93            params.push(format!("namespace={}", ns));
94        }
95        if !params.is_empty() {
96            url.push('?');
97            url.push_str(&params.join("&"));
98        }
99        let response = self.client.get(&url).send().await?;
100        self.handle_response(response).await
101    }
102
103    /// Get latency analytics
104    pub async fn analytics_latency(
105        &self,
106        period: Option<&str>,
107        namespace: Option<&str>,
108    ) -> Result<LatencyAnalytics> {
109        let mut url = format!("{}/v1/analytics/latency", self.base_url);
110        let mut params = Vec::new();
111        if let Some(p) = period {
112            params.push(format!("period={}", p));
113        }
114        if let Some(ns) = namespace {
115            params.push(format!("namespace={}", ns));
116        }
117        if !params.is_empty() {
118            url.push('?');
119            url.push_str(&params.join("&"));
120        }
121        let response = self.client.get(&url).send().await?;
122        self.handle_response(response).await
123    }
124
125    /// Get throughput analytics
126    pub async fn analytics_throughput(
127        &self,
128        period: Option<&str>,
129        namespace: Option<&str>,
130    ) -> Result<ThroughputAnalytics> {
131        let mut url = format!("{}/v1/analytics/throughput", self.base_url);
132        let mut params = Vec::new();
133        if let Some(p) = period {
134            params.push(format!("period={}", p));
135        }
136        if let Some(ns) = namespace {
137            params.push(format!("namespace={}", ns));
138        }
139        if !params.is_empty() {
140            url.push('?');
141            url.push_str(&params.join("&"));
142        }
143        let response = self.client.get(&url).send().await?;
144        self.handle_response(response).await
145    }
146
147    /// Get storage analytics
148    pub async fn analytics_storage(&self, namespace: Option<&str>) -> Result<StorageAnalytics> {
149        let mut url = format!("{}/v1/analytics/storage", self.base_url);
150        if let Some(ns) = namespace {
151            url.push_str(&format!("?namespace={}", ns));
152        }
153        let response = self.client.get(&url).send().await?;
154        self.handle_response(response).await
155    }
156}