1use std::sync::Arc;
2
3use prometheus::{
4 Histogram, HistogramVec, IntCounter, IntCounterVec, IntGauge, IntGaugeVec, Registry,
5};
6
7pub static METRICS: std::sync::LazyLock<CdkMetrics> = std::sync::LazyLock::new(CdkMetrics::default);
9
10#[derive(Clone, Debug)]
12pub struct CdkMetrics {
13 registry: Arc<Registry>,
14
15 http_requests_total: IntCounterVec,
17 http_request_duration: HistogramVec,
18
19 auth_attempts_total: IntCounter,
21 auth_successes_total: IntCounter,
22
23 lightning_payments_total: IntCounter,
25 lightning_payment_amount: Histogram,
26 lightning_payment_fees: Histogram,
27
28 db_operations_total: IntCounter,
30 db_operation_duration: HistogramVec,
31 db_connections_active: IntGauge,
32
33 errors_total: IntCounter,
35
36 mint_operations_total: IntCounterVec,
38 mint_in_flight_requests: IntGaugeVec,
39 mint_operation_duration: HistogramVec,
40}
41
42impl CdkMetrics {
43 pub fn new() -> crate::Result<Self> {
48 let registry = Arc::new(Registry::new());
49
50 let (http_requests_total, http_request_duration) = Self::create_http_metrics(®istry)?;
52
53 let (auth_attempts_total, auth_successes_total) = Self::create_auth_metrics(®istry)?;
55
56 let (lightning_payments_total, lightning_payment_amount, lightning_payment_fees) =
58 Self::create_lightning_metrics(®istry)?;
59
60 let (db_operations_total, db_operation_duration, db_connections_active) =
62 Self::create_db_metrics(®istry)?;
63
64 let errors_total = Self::create_error_metrics(®istry)?;
66
67 let (mint_operations_total, mint_operation_duration, mint_in_flight_requests) =
69 Self::create_mint_metrics(®istry)?;
70
71 Ok(Self {
72 registry,
73 http_requests_total,
74 http_request_duration,
75 auth_attempts_total,
76 auth_successes_total,
77 lightning_payments_total,
78 lightning_payment_amount,
79 lightning_payment_fees,
80 db_operations_total,
81 db_operation_duration,
82 db_connections_active,
83 errors_total,
84 mint_operations_total,
85 mint_in_flight_requests,
86 mint_operation_duration,
87 })
88 }
89
90 fn create_http_metrics(registry: &Registry) -> crate::Result<(IntCounterVec, HistogramVec)> {
95 let http_requests_total = IntCounterVec::new(
96 prometheus::Opts::new("cdk_http_requests_total", "Total number of HTTP requests"),
97 &["endpoint", "status"],
98 )?;
99 registry.register(Box::new(http_requests_total.clone()))?;
100
101 let http_request_duration = HistogramVec::new(
102 prometheus::HistogramOpts::new(
103 "cdk_http_request_duration_seconds",
104 "HTTP request duration in seconds",
105 )
106 .buckets(vec![
107 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0,
108 ]),
109 &["endpoint"],
110 )?;
111 registry.register(Box::new(http_request_duration.clone()))?;
112
113 Ok((http_requests_total, http_request_duration))
114 }
115
116 fn create_auth_metrics(registry: &Registry) -> crate::Result<(IntCounter, IntCounter)> {
121 let auth_attempts_total =
122 IntCounter::new("cdk_auth_attempts_total", "Total authentication attempts")?;
123 registry.register(Box::new(auth_attempts_total.clone()))?;
124
125 let auth_successes_total = IntCounter::new(
126 "cdk_auth_successes_total",
127 "Total successful authentications",
128 )?;
129 registry.register(Box::new(auth_successes_total.clone()))?;
130
131 Ok((auth_attempts_total, auth_successes_total))
132 }
133
134 fn create_lightning_metrics(
139 registry: &Registry,
140 ) -> crate::Result<(IntCounter, Histogram, Histogram)> {
141 let wallet_operations_total =
142 IntCounter::new("cdk_wallet_operations_total", "Total wallet operations")?;
143 registry.register(Box::new(wallet_operations_total))?;
144
145 let lightning_payments_total =
146 IntCounter::new("cdk_lightning_payments_total", "Total Lightning payments")?;
147 registry.register(Box::new(lightning_payments_total.clone()))?;
148
149 let lightning_payment_amount = Histogram::with_opts(
150 prometheus::HistogramOpts::new(
151 "cdk_lightning_payment_amount_sats",
152 "Lightning payment amounts in satoshis",
153 )
154 .buckets(vec![
155 1.0,
156 10.0,
157 100.0,
158 1000.0,
159 10_000.0,
160 100_000.0,
161 1_000_000.0,
162 ]),
163 )?;
164 registry.register(Box::new(lightning_payment_amount.clone()))?;
165
166 let lightning_payment_fees = Histogram::with_opts(
167 prometheus::HistogramOpts::new(
168 "cdk_lightning_payment_fees_sats",
169 "Lightning payment fees in satoshis",
170 )
171 .buckets(vec![0.0, 1.0, 5.0, 10.0, 50.0, 100.0, 500.0, 1000.0]),
172 )?;
173 registry.register(Box::new(lightning_payment_fees.clone()))?;
174
175 Ok((
176 lightning_payments_total,
177 lightning_payment_amount,
178 lightning_payment_fees,
179 ))
180 }
181
182 fn create_db_metrics(
187 registry: &Registry,
188 ) -> crate::Result<(IntCounter, HistogramVec, IntGauge)> {
189 let db_operations_total =
190 IntCounter::new("cdk_db_operations_total", "Total database operations")?;
191 registry.register(Box::new(db_operations_total.clone()))?;
192 let db_operation_duration = HistogramVec::new(
193 prometheus::HistogramOpts::new(
194 "cdk_db_operation_duration_seconds",
195 "Database operation duration in seconds",
196 )
197 .buckets(vec![0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0]),
198 &["operation"],
199 )?;
200 registry.register(Box::new(db_operation_duration.clone()))?;
201
202 let db_connections_active = IntGauge::new(
203 "cdk_db_connections_active",
204 "Number of active database connections",
205 )?;
206 registry.register(Box::new(db_connections_active.clone()))?;
207
208 Ok((
209 db_operations_total,
210 db_operation_duration,
211 db_connections_active,
212 ))
213 }
214
215 fn create_error_metrics(registry: &Registry) -> crate::Result<IntCounter> {
220 let errors_total = IntCounter::new("cdk_errors_total", "Total errors")?;
221 registry.register(Box::new(errors_total.clone()))?;
222
223 Ok(errors_total)
224 }
225
226 fn create_mint_metrics(
231 registry: &Registry,
232 ) -> crate::Result<(IntCounterVec, HistogramVec, IntGaugeVec)> {
233 let mint_operations_total = IntCounterVec::new(
234 prometheus::Opts::new(
235 "cdk_mint_operations_total",
236 "Total number of mint operations",
237 ),
238 &["operation", "status"],
239 )?;
240 registry.register(Box::new(mint_operations_total.clone()))?;
241
242 let mint_operation_duration = HistogramVec::new(
243 prometheus::HistogramOpts::new(
244 "cdk_mint_operation_duration_seconds",
245 "Duration of mint operations in seconds",
246 )
247 .buckets(vec![
248 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0,
249 ]),
250 &["operation", "status"],
251 )?;
252 registry.register(Box::new(mint_operation_duration.clone()))?;
253
254 let mint_in_flight_requests = IntGaugeVec::new(
255 prometheus::Opts::new(
256 "cdk_mint_in_flight_requests",
257 "Number of in-flight mint requests",
258 ),
259 &["operation"],
260 )?;
261 registry.register(Box::new(mint_in_flight_requests.clone()))?;
262
263 Ok((
264 mint_operations_total,
265 mint_operation_duration,
266 mint_in_flight_requests,
267 ))
268 }
269
270 #[must_use]
272 pub fn registry(&self) -> Arc<Registry> {
273 Arc::<Registry>::clone(&self.registry)
274 }
275
276 pub fn record_http_request(&self, endpoint: &str, status: &str) {
278 self.http_requests_total
279 .with_label_values(&[endpoint, status])
280 .inc();
281 }
282
283 pub fn record_http_request_duration(&self, duration_seconds: f64, endpoint: &str) {
284 self.http_request_duration
285 .with_label_values(&[endpoint])
286 .observe(duration_seconds);
287 }
288
289 pub fn record_auth_attempt(&self) {
291 self.auth_attempts_total.inc();
292 }
293
294 pub fn record_auth_success(&self) {
295 self.auth_successes_total.inc();
296 }
297
298 pub fn record_lightning_payment(&self, amount: f64, fee: f64) {
300 self.lightning_payments_total.inc();
301 self.lightning_payment_amount.observe(amount);
302 self.lightning_payment_fees.observe(fee);
303 }
304
305 pub fn record_db_operation(&self, duration_seconds: f64, op: &str) {
307 self.db_operations_total.inc();
308 self.db_operation_duration
309 .with_label_values(&[op])
310 .observe(duration_seconds);
311 }
312
313 pub fn set_db_connections_active(&self, count: i64) {
314 self.db_connections_active.set(count);
315 }
316
317 pub fn record_error(&self) {
319 self.errors_total.inc();
320 }
321
322 pub fn record_mint_operation(&self, operation: &str, success: bool) {
324 let status = if success { "success" } else { "error" };
325 self.mint_operations_total
326 .with_label_values(&[operation, status])
327 .inc();
328 }
329 pub fn record_mint_operation_histogram(
330 &self,
331 operation: &str,
332 success: bool,
333 duration_seconds: f64,
334 ) {
335 let status = if success { "success" } else { "error" };
336 self.mint_operation_duration
337 .with_label_values(&[operation, status])
338 .observe(duration_seconds);
339 }
340 pub fn inc_in_flight_requests(&self, operation: &str) {
341 self.mint_in_flight_requests
342 .with_label_values(&[operation])
343 .inc();
344 }
345
346 pub fn dec_in_flight_requests(&self, operation: &str) {
347 self.mint_in_flight_requests
348 .with_label_values(&[operation])
349 .dec();
350 }
351}
352
353impl Default for CdkMetrics {
354 fn default() -> Self {
355 Self::new().expect("Failed to create default CdkMetrics")
356 }
357}
358
359pub mod global {
361 use super::METRICS;
362
363 pub fn record_http_request(endpoint: &str, status: &str) {
365 METRICS.record_http_request(endpoint, status);
366 }
367
368 pub fn record_http_request_duration(duration_seconds: f64, endpoint: &str) {
370 METRICS.record_http_request_duration(duration_seconds, endpoint);
371 }
372
373 pub fn record_auth_attempt() {
375 METRICS.record_auth_attempt();
376 }
377
378 pub fn record_auth_success() {
380 METRICS.record_auth_success();
381 }
382
383 pub fn record_lightning_payment(amount: f64, fee: f64) {
385 METRICS.record_lightning_payment(amount, fee);
386 }
387
388 pub fn record_db_operation(duration_seconds: f64, op: &str) {
390 METRICS.record_db_operation(duration_seconds, op);
391 }
392
393 pub fn set_db_connections_active(count: i64) {
395 METRICS.set_db_connections_active(count);
396 }
397
398 pub fn record_error() {
400 METRICS.record_error();
401 }
402
403 pub fn record_mint_operation(operation: &str, success: bool) {
405 METRICS.record_mint_operation(operation, success);
406 }
407
408 pub fn record_mint_operation_histogram(operation: &str, success: bool, duration_seconds: f64) {
410 METRICS.record_mint_operation_histogram(operation, success, duration_seconds);
411 }
412
413 pub fn inc_in_flight_requests(operation: &str) {
415 METRICS.inc_in_flight_requests(operation);
416 }
417
418 pub fn dec_in_flight_requests(operation: &str) {
420 METRICS.dec_in_flight_requests(operation);
421 }
422
423 pub fn registry() -> std::sync::Arc<prometheus::Registry> {
425 METRICS.registry()
426 }
427}