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) {
279 self.http_requests_total
280 .with_label_values(&[endpoint, status])
281 .inc();
282 }
283
284 pub fn record_http_request_duration(&self, duration_seconds: f64, endpoint: &str) {
286 self.http_request_duration
287 .with_label_values(&[endpoint])
288 .observe(duration_seconds);
289 }
290
291 pub fn record_auth_attempt(&self) {
294 self.auth_attempts_total.inc();
295 }
296
297 pub fn record_auth_success(&self) {
299 self.auth_successes_total.inc();
300 }
301
302 pub fn record_lightning_payment(&self, amount: f64, fee: f64) {
305 self.lightning_payments_total.inc();
306 self.lightning_payment_amount.observe(amount);
307 self.lightning_payment_fees.observe(fee);
308 }
309
310 pub fn record_db_operation(&self, duration_seconds: f64, op: &str) {
313 self.db_operations_total.inc();
314 self.db_operation_duration
315 .with_label_values(&[op])
316 .observe(duration_seconds);
317 }
318
319 pub fn set_db_connections_active(&self, count: i64) {
321 self.db_connections_active.set(count);
322 }
323
324 pub fn record_error(&self) {
327 self.errors_total.inc();
328 }
329
330 pub fn record_mint_operation(&self, operation: &str, success: bool) {
333 let status = if success { "success" } else { "error" };
334 self.mint_operations_total
335 .with_label_values(&[operation, status])
336 .inc();
337 }
338
339 pub fn record_mint_operation_histogram(
341 &self,
342 operation: &str,
343 success: bool,
344 duration_seconds: f64,
345 ) {
346 let status = if success { "success" } else { "error" };
347 self.mint_operation_duration
348 .with_label_values(&[operation, status])
349 .observe(duration_seconds);
350 }
351
352 pub fn inc_in_flight_requests(&self, operation: &str) {
354 self.mint_in_flight_requests
355 .with_label_values(&[operation])
356 .inc();
357 }
358
359 pub fn dec_in_flight_requests(&self, operation: &str) {
361 self.mint_in_flight_requests
362 .with_label_values(&[operation])
363 .dec();
364 }
365}
366
367impl Default for CdkMetrics {
368 fn default() -> Self {
369 Self::new().expect("Failed to create default CdkMetrics")
370 }
371}
372
373pub mod global {
375 use super::METRICS;
376
377 pub fn record_http_request(endpoint: &str, status: &str) {
379 METRICS.record_http_request(endpoint, status);
380 }
381
382 pub fn record_http_request_duration(duration_seconds: f64, endpoint: &str) {
384 METRICS.record_http_request_duration(duration_seconds, endpoint);
385 }
386
387 pub fn record_auth_attempt() {
389 METRICS.record_auth_attempt();
390 }
391
392 pub fn record_auth_success() {
394 METRICS.record_auth_success();
395 }
396
397 pub fn record_lightning_payment(amount: f64, fee: f64) {
399 METRICS.record_lightning_payment(amount, fee);
400 }
401
402 pub fn record_db_operation(duration_seconds: f64, op: &str) {
404 METRICS.record_db_operation(duration_seconds, op);
405 }
406
407 pub fn set_db_connections_active(count: i64) {
409 METRICS.set_db_connections_active(count);
410 }
411
412 pub fn record_error() {
414 METRICS.record_error();
415 }
416
417 pub fn record_mint_operation(operation: &str, success: bool) {
419 METRICS.record_mint_operation(operation, success);
420 }
421
422 pub fn record_mint_operation_histogram(operation: &str, success: bool, duration_seconds: f64) {
424 METRICS.record_mint_operation_histogram(operation, success, duration_seconds);
425 }
426
427 pub fn inc_in_flight_requests(operation: &str) {
429 METRICS.inc_in_flight_requests(operation);
430 }
431
432 pub fn dec_in_flight_requests(operation: &str) {
434 METRICS.dec_in_flight_requests(operation);
435 }
436
437 pub fn registry() -> std::sync::Arc<prometheus::Registry> {
439 METRICS.registry()
440 }
441}