enya_client/otlp/
metrics_client.rs1use std::sync::Arc;
4
5use super::store::TelemetryStore;
6use crate::prometheus::response::MetricLabels;
7use crate::{
8 BackendInfo, HealthCheckResult, LabelsResult, MetricLabelsResult, MetricsClient, QueryRequest,
9 QueryResult,
10};
11use poll_promise::Promise;
12
13pub struct OtlpMetricsClient {
19 store: Arc<TelemetryStore>,
20}
21
22impl OtlpMetricsClient {
23 pub fn new(store: Arc<TelemetryStore>) -> Self {
25 Self { store }
26 }
27}
28
29impl MetricsClient for OtlpMetricsClient {
30 fn query(&self, request: QueryRequest, _ctx: &egui::Context) -> Promise<QueryResult> {
31 let metric = if request.query.is_empty() || request.query == "*" {
35 &request.metric
36 } else {
37 &request.query
38 };
39
40 let now_ns = crate::now_unix_secs() * 1_000_000_000;
42 let start_ns = request
43 .start
44 .unwrap_or((now_ns - 3_600_000_000_000) as u128) as u64;
45 let end_ns = request.end.unwrap_or(now_ns as u128) as u64;
46 let step_ns = request.step_secs * 1_000_000_000;
47
48 let response = self.store.query_metric(
49 metric,
50 &rustc_hash::FxHashMap::default(),
51 start_ns,
52 end_ns,
53 step_ns,
54 );
55
56 Promise::from_ready(Ok(response))
57 }
58
59 fn fetch_label_names(&self, _ctx: &egui::Context) -> Promise<LabelsResult> {
60 let names = self.store.metric_names();
62 let mut all_labels: rustc_hash::FxHashSet<String> = rustc_hash::FxHashSet::default();
63 for name in &names {
64 for label in self.store.metric_label_names(name) {
65 if !label.starts_with("__") {
66 all_labels.insert(label);
67 }
68 }
69 }
70 let mut sorted: Vec<String> = all_labels.into_iter().collect();
71 sorted.sort();
72 Promise::from_ready(Ok(sorted))
73 }
74
75 fn fetch_label_values(&self, label: &str, _ctx: &egui::Context) -> Promise<LabelsResult> {
76 let names = self.store.metric_names();
77 let mut all_values: rustc_hash::FxHashSet<String> = rustc_hash::FxHashSet::default();
78 for name in &names {
79 for value in self.store.metric_label_values(name, label) {
80 all_values.insert(value);
81 }
82 }
83 let mut sorted: Vec<String> = all_values.into_iter().collect();
84 sorted.sort();
85 Promise::from_ready(Ok(sorted))
86 }
87
88 fn fetch_metric_names(&self, _ctx: &egui::Context) -> Promise<LabelsResult> {
89 let names = self.store.metric_names();
90 Promise::from_ready(Ok(names))
91 }
92
93 #[allow(clippy::disallowed_types)]
94 fn fetch_metric_labels(
95 &self,
96 metric: &str,
97 _ctx: &egui::Context,
98 ) -> Promise<MetricLabelsResult> {
99 let label_names = self.store.metric_label_names(metric);
100 let mut label_values = std::collections::HashMap::new();
101 for name in &label_names {
102 if name.starts_with("__") {
103 continue;
104 }
105 let values = self.store.metric_label_values(metric, name);
106 label_values.insert(name.clone(), values);
107 }
108 Promise::from_ready(Ok(MetricLabels {
109 labels: label_values,
110 }))
111 }
112
113 fn backend_type(&self) -> &'static str {
114 "otlp"
115 }
116
117 fn health_check(&self, _ctx: &egui::Context) -> Promise<HealthCheckResult> {
118 Promise::from_ready(Ok(BackendInfo {
119 backend_type: "otlp".to_string(),
120 version: format!(
121 "in-memory ({} series, {} points)",
122 self.store.metric_series_count(),
123 self.store.metric_point_count()
124 ),
125 }))
126 }
127}