1use std::collections::HashMap;
2use std::sync::{Arc, Mutex};
3
4#[derive(Debug, Clone, Hash, Eq, PartialEq)]
5pub struct MetricLabel {
6 pub key: String,
7 pub value: String,
8}
9
10impl MetricLabel {
11 pub fn new(key: &str, value: &str) -> Self {
12 Self {
13 key: key.to_string(),
14 value: value.to_string(),
15 }
16 }
17}
18
19#[derive(Debug, Clone, Hash, Eq, PartialEq)]
20pub struct MetricKey {
21 pub name: String,
22 pub labels: Vec<MetricLabel>,
23}
24
25impl MetricKey {
26 pub fn new(name: &str, labels: Vec<MetricLabel>) -> Self {
27 Self {
28 name: name.to_string(),
29 labels,
30 }
31 }
32}
33
34pub trait Metric: Send + Sync {
37 fn as_any(&self) -> &dyn std::any::Any;
38}
39
40pub struct Counter {
41 value: std::sync::atomic::AtomicU64,
42}
43
44impl Default for Counter {
45 fn default() -> Self {
46 Self::new()
47 }
48}
49
50impl Counter {
51 pub fn new() -> Self {
52 Self {
53 value: std::sync::atomic::AtomicU64::new(0),
54 }
55 }
56
57 pub fn increment(&self, amount: u64) {
58 self.value
59 .fetch_add(amount, std::sync::atomic::Ordering::Relaxed);
60 }
61
62 pub fn get(&self) -> u64 {
63 self.value.load(std::sync::atomic::Ordering::Relaxed)
64 }
65}
66
67impl Metric for Counter {
68 fn as_any(&self) -> &dyn std::any::Any {
69 self
70 }
71}
72
73pub struct Gauge {
74 value: std::sync::atomic::AtomicI64,
75}
76
77impl Default for Gauge {
78 fn default() -> Self {
79 Self::new()
80 }
81}
82
83impl Gauge {
84 pub fn new() -> Self {
85 Self {
86 value: std::sync::atomic::AtomicI64::new(0),
87 }
88 }
89
90 pub fn set(&self, val: i64) {
91 self.value.store(val, std::sync::atomic::Ordering::Relaxed);
92 }
93
94 pub fn get(&self) -> i64 {
95 self.value.load(std::sync::atomic::Ordering::Relaxed)
96 }
97}
98
99impl Metric for Gauge {
100 fn as_any(&self) -> &dyn std::any::Any {
101 self
102 }
103}
104
105use std::sync::atomic::{AtomicU64, Ordering};
107
108pub struct Histogram {
109 buckets: Vec<f64>,
110 counts: Vec<AtomicU64>,
111 sum: Mutex<f64>,
112 count: AtomicU64,
113}
114
115impl Histogram {
116 pub fn new(buckets: Vec<f64>) -> Self {
117 let len = buckets.len() + 1;
118 let mut counts = Vec::with_capacity(len);
119 for _ in 0..len {
120 counts.push(AtomicU64::new(0));
121 }
122
123 Self {
124 buckets,
125 counts,
126 sum: Mutex::new(0.0),
127 count: AtomicU64::new(0),
128 }
129 }
130
131 pub fn record(&self, value: f64) {
132 self.count.fetch_add(1, Ordering::Relaxed);
133
134 if let Ok(mut g) = self.sum.lock() {
136 *g += value;
137 }
138
139 let mut idx = self.buckets.len();
141 for (i, boundary) in self.buckets.iter().enumerate() {
142 if value <= *boundary {
143 idx = i;
144 break;
145 }
146 }
147
148 self.counts[idx].fetch_add(1, Ordering::Relaxed);
150 }
151}
152
153impl Metric for Histogram {
154 fn as_any(&self) -> &dyn std::any::Any {
155 self
156 }
157}
158
159pub struct MetricRegistry {
161 metrics: Mutex<HashMap<MetricKey, Arc<dyn Metric>>>,
162}
163
164impl Default for MetricRegistry {
165 fn default() -> Self {
166 Self::new()
167 }
168}
169
170impl MetricRegistry {
171 pub fn new() -> Self {
172 Self {
173 metrics: Mutex::new(HashMap::new()),
174 }
175 }
176
177 pub fn counter(&self, name: &str, labels: Vec<MetricLabel>) -> Arc<Counter> {
178 let _key = MetricKey::new(name, labels);
179 let _map = self.metrics.lock().unwrap();
180
181 todo!()
183 }
184
185 }
187
188pub struct SimpleRegistry {
196 counters: Mutex<HashMap<MetricKey, Arc<Counter>>>,
197 gauges: Mutex<HashMap<MetricKey, Arc<Gauge>>>,
198 histograms: Mutex<HashMap<MetricKey, Arc<Histogram>>>,
199}
200
201impl Default for SimpleRegistry {
202 fn default() -> Self {
203 Self::new()
204 }
205}
206
207impl SimpleRegistry {
208 pub fn new() -> Self {
209 Self {
210 counters: Mutex::new(HashMap::new()),
211 gauges: Mutex::new(HashMap::new()),
212 histograms: Mutex::new(HashMap::new()),
213 }
214 }
215
216 pub fn get_counter(&self, name: &str, labels: Vec<MetricLabel>) -> Arc<Counter> {
217 let key = MetricKey::new(name, labels);
218 let mut map = self.counters.lock().unwrap();
219 map.entry(key)
220 .or_insert_with(|| Arc::new(Counter::new()))
221 .clone()
222 }
223
224 pub fn get_gauge(&self, name: &str, labels: Vec<MetricLabel>) -> Arc<Gauge> {
225 let key = MetricKey::new(name, labels);
226 let mut map = self.gauges.lock().unwrap();
227 map.entry(key)
228 .or_insert_with(|| Arc::new(Gauge::new()))
229 .clone()
230 }
231
232 pub fn get_histogram(
233 &self,
234 name: &str,
235 labels: Vec<MetricLabel>,
236 buckets: Vec<f64>,
237 ) -> Arc<Histogram> {
238 let key = MetricKey::new(name, labels);
239 let mut map = self.histograms.lock().unwrap();
240 map.entry(key)
242 .or_insert_with(|| Arc::new(Histogram::new(buckets)))
243 .clone()
244 }
245}
246
247lazy_static::lazy_static! {
248 pub static ref REGISTRY: SimpleRegistry = SimpleRegistry::new();
249}