1use std::sync::Arc;
6use std::time::{Duration, Instant};
7
8use serde::{Deserialize, Serialize};
9
10use crate::Error;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
14pub enum MetricType {
15 Counter,
17 Gauge,
19 Timing,
21}
22
23pub trait Metric: Send + Sync {
25 fn increment(&self, value: u64);
27
28 fn decrement(&self, value: u64);
30
31 fn set(&self, value: u64);
33
34 fn timing(&self, duration: Duration);
36
37 fn metric_type(&self) -> MetricType;
39
40 fn name(&self) -> &str;
42}
43
44pub trait MetricCollector: Send + Sync {
46 fn counter(&self, name: &str) -> Arc<dyn Metric>;
48
49 fn gauge(&self, name: &str) -> Arc<dyn Metric>;
51
52 fn timer(&self, name: &str) -> Arc<dyn Metric>;
54
55 fn with_tags(&self, tags: std::collections::HashMap<String, String>) -> Box<dyn MetricCollector>;
57
58 fn close(&self) -> Result<(), Error>;
60}
61
62pub struct NoopMetric {
64 name: String,
65 metric_type: MetricType,
66}
67
68impl NoopMetric {
69 pub fn new(name: &str, metric_type: MetricType) -> Self {
71 Self {
72 name: name.to_string(),
73 metric_type,
74 }
75 }
76}
77
78impl Metric for NoopMetric {
79 fn increment(&self, _value: u64) {}
80 fn decrement(&self, _value: u64) {}
81 fn set(&self, _value: u64) {}
82 fn timing(&self, _duration: Duration) {}
83 fn metric_type(&self) -> MetricType { self.metric_type.clone() }
84 fn name(&self) -> &str { &self.name }
85}
86
87pub struct NoopCollector {}
89
90impl NoopCollector {
91 pub fn new() -> Self {
93 Self {}
94 }
95}
96
97impl MetricCollector for NoopCollector {
98 fn counter(&self, name: &str) -> Arc<dyn Metric> {
99 Arc::new(NoopMetric::new(name, MetricType::Counter))
100 }
101
102 fn gauge(&self, name: &str) -> Arc<dyn Metric> {
103 Arc::new(NoopMetric::new(name, MetricType::Gauge))
104 }
105
106 fn timer(&self, name: &str) -> Arc<dyn Metric> {
107 Arc::new(NoopMetric::new(name, MetricType::Timing))
108 }
109
110 fn with_tags(&self, _tags: std::collections::HashMap<String, String>) -> Box<dyn MetricCollector> {
111 Box::new(Self::new())
112 }
113
114 fn close(&self) -> Result<(), Error> {
115 Ok(())
116 }
117}
118
119pub struct PrometheusCollector {
121 prefix: String,
124}
125
126impl PrometheusCollector {
127 pub fn new(prefix: &str) -> Result<Self, Error> {
129 Ok(Self {
130 prefix: prefix.to_string(),
132 })
133 }
134}
135
136impl MetricCollector for PrometheusCollector {
137 fn counter(&self, name: &str) -> Arc<dyn Metric> {
138 Arc::new(NoopMetric::new(name, MetricType::Counter))
151 }
152
153 fn gauge(&self, name: &str) -> Arc<dyn Metric> {
154 Arc::new(NoopMetric::new(name, MetricType::Gauge))
157 }
158
159 fn timer(&self, name: &str) -> Arc<dyn Metric> {
160 Arc::new(NoopMetric::new(name, MetricType::Timing))
163 }
164
165 fn with_tags(&self, _tags: std::collections::HashMap<String, String>) -> Box<dyn MetricCollector> {
166 Box::new(Self {
168 prefix: self.prefix.clone(),
170 })
171 }
172
173 fn close(&self) -> Result<(), Error> {
174 Ok(())
176 }
177}
178
179pub struct TimingHelper {
181 metric: Arc<dyn Metric>,
182 start: Instant,
183}
184
185impl TimingHelper {
186 pub fn new(metric: Arc<dyn Metric>) -> Self {
188 Self {
189 metric,
190 start: Instant::now(),
191 }
192 }
193
194 pub fn done(self) {
196 let duration = self.start.elapsed();
197 self.metric.timing(duration);
198 }
199}
200
201pub fn create_metrics(config: &crate::config::MetricsConfig) -> Result<Box<dyn MetricCollector>, Error> {
203 if !config.enabled {
204 return Ok(Box::new(NoopCollector::new()));
205 }
206
207 let prefix = config.prefix.as_deref().unwrap_or("").to_string();
208
209 match config.type_name.as_str() {
210 "prometheus" => {
211 let collector = PrometheusCollector::new(&prefix)?;
212
213 if let Some(tags) = &config.tags {
215 Ok(collector.with_tags(tags.clone()))
216 } else {
217 Ok(Box::new(collector))
218 }
219 },
220 "statsd" => {
221 Ok(Box::new(NoopCollector::new()))
224 },
225 "none" | "noop" => {
226 Ok(Box::new(NoopCollector::new()))
227 },
228 _ => Err(Error::Config(format!("不支持的指标类型: {}", config.type_name))),
229 }
230}