metrics.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. use std::sync::Arc;
  2. use prometheus::{
  3. Histogram, HistogramVec, IntCounter, IntCounterVec, IntGauge, IntGaugeVec, Registry,
  4. };
  5. /// Global metrics instance
  6. pub static METRICS: std::sync::LazyLock<CdkMetrics> = std::sync::LazyLock::new(CdkMetrics::default);
  7. /// Custom metrics for CDK applications
  8. #[derive(Clone, Debug)]
  9. pub struct CdkMetrics {
  10. registry: Arc<Registry>,
  11. // HTTP metrics
  12. http_requests_total: IntCounterVec,
  13. http_request_duration: HistogramVec,
  14. // Authentication metrics
  15. auth_attempts_total: IntCounter,
  16. auth_successes_total: IntCounter,
  17. // Lightning metrics
  18. lightning_payments_total: IntCounter,
  19. lightning_payment_amount: Histogram,
  20. lightning_payment_fees: Histogram,
  21. // Database metrics
  22. db_operations_total: IntCounter,
  23. db_operation_duration: HistogramVec,
  24. db_connections_active: IntGauge,
  25. // Error metrics
  26. errors_total: IntCounter,
  27. // Mint metrics
  28. mint_operations_total: IntCounterVec,
  29. mint_in_flight_requests: IntGaugeVec,
  30. mint_operation_duration: HistogramVec,
  31. }
  32. impl CdkMetrics {
  33. /// Create a new instance with default metrics
  34. ///
  35. /// # Errors
  36. /// Returns an error if any of the metrics cannot be created or registered
  37. pub fn new() -> crate::Result<Self> {
  38. let registry = Arc::new(Registry::new());
  39. // Create and register HTTP metrics
  40. let (http_requests_total, http_request_duration) = Self::create_http_metrics(&registry)?;
  41. // Create and register authentication metrics
  42. let (auth_attempts_total, auth_successes_total) = Self::create_auth_metrics(&registry)?;
  43. // Create and register Lightning metrics
  44. let (lightning_payments_total, lightning_payment_amount, lightning_payment_fees) =
  45. Self::create_lightning_metrics(&registry)?;
  46. // Create and register database metrics
  47. let (db_operations_total, db_operation_duration, db_connections_active) =
  48. Self::create_db_metrics(&registry)?;
  49. // Create and register error metrics
  50. let errors_total = Self::create_error_metrics(&registry)?;
  51. // Create and register mint metrics
  52. let (mint_operations_total, mint_operation_duration, mint_in_flight_requests) =
  53. Self::create_mint_metrics(&registry)?;
  54. Ok(Self {
  55. registry,
  56. http_requests_total,
  57. http_request_duration,
  58. auth_attempts_total,
  59. auth_successes_total,
  60. lightning_payments_total,
  61. lightning_payment_amount,
  62. lightning_payment_fees,
  63. db_operations_total,
  64. db_operation_duration,
  65. db_connections_active,
  66. errors_total,
  67. mint_operations_total,
  68. mint_in_flight_requests,
  69. mint_operation_duration,
  70. })
  71. }
  72. /// Create and register HTTP metrics
  73. ///
  74. /// # Errors
  75. /// Returns an error if any of the metrics cannot be created or registered
  76. fn create_http_metrics(registry: &Registry) -> crate::Result<(IntCounterVec, HistogramVec)> {
  77. let http_requests_total = IntCounterVec::new(
  78. prometheus::Opts::new("cdk_http_requests_total", "Total number of HTTP requests"),
  79. &["endpoint", "status"],
  80. )?;
  81. registry.register(Box::new(http_requests_total.clone()))?;
  82. let http_request_duration = HistogramVec::new(
  83. prometheus::HistogramOpts::new(
  84. "cdk_http_request_duration_seconds",
  85. "HTTP request duration in seconds",
  86. )
  87. .buckets(vec![
  88. 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0,
  89. ]),
  90. &["endpoint"],
  91. )?;
  92. registry.register(Box::new(http_request_duration.clone()))?;
  93. Ok((http_requests_total, http_request_duration))
  94. }
  95. /// Create and register authentication metrics
  96. ///
  97. /// # Errors
  98. /// Returns an error if any of the metrics cannot be created or registered
  99. fn create_auth_metrics(registry: &Registry) -> crate::Result<(IntCounter, IntCounter)> {
  100. let auth_attempts_total =
  101. IntCounter::new("cdk_auth_attempts_total", "Total authentication attempts")?;
  102. registry.register(Box::new(auth_attempts_total.clone()))?;
  103. let auth_successes_total = IntCounter::new(
  104. "cdk_auth_successes_total",
  105. "Total successful authentications",
  106. )?;
  107. registry.register(Box::new(auth_successes_total.clone()))?;
  108. Ok((auth_attempts_total, auth_successes_total))
  109. }
  110. /// Create and register Lightning metrics
  111. ///
  112. /// # Errors
  113. /// Returns an error if any of the metrics cannot be created or registered
  114. fn create_lightning_metrics(
  115. registry: &Registry,
  116. ) -> crate::Result<(IntCounter, Histogram, Histogram)> {
  117. let wallet_operations_total =
  118. IntCounter::new("cdk_wallet_operations_total", "Total wallet operations")?;
  119. registry.register(Box::new(wallet_operations_total))?;
  120. let lightning_payments_total =
  121. IntCounter::new("cdk_lightning_payments_total", "Total Lightning payments")?;
  122. registry.register(Box::new(lightning_payments_total.clone()))?;
  123. let lightning_payment_amount = Histogram::with_opts(
  124. prometheus::HistogramOpts::new(
  125. "cdk_lightning_payment_amount_sats",
  126. "Lightning payment amounts in satoshis",
  127. )
  128. .buckets(vec![
  129. 1.0,
  130. 10.0,
  131. 100.0,
  132. 1000.0,
  133. 10_000.0,
  134. 100_000.0,
  135. 1_000_000.0,
  136. ]),
  137. )?;
  138. registry.register(Box::new(lightning_payment_amount.clone()))?;
  139. let lightning_payment_fees = Histogram::with_opts(
  140. prometheus::HistogramOpts::new(
  141. "cdk_lightning_payment_fees_sats",
  142. "Lightning payment fees in satoshis",
  143. )
  144. .buckets(vec![0.0, 1.0, 5.0, 10.0, 50.0, 100.0, 500.0, 1000.0]),
  145. )?;
  146. registry.register(Box::new(lightning_payment_fees.clone()))?;
  147. Ok((
  148. lightning_payments_total,
  149. lightning_payment_amount,
  150. lightning_payment_fees,
  151. ))
  152. }
  153. /// Create and register database metrics
  154. ///
  155. /// # Errors
  156. /// Returns an error if any of the metrics cannot be created or registered
  157. fn create_db_metrics(
  158. registry: &Registry,
  159. ) -> crate::Result<(IntCounter, HistogramVec, IntGauge)> {
  160. let db_operations_total =
  161. IntCounter::new("cdk_db_operations_total", "Total database operations")?;
  162. registry.register(Box::new(db_operations_total.clone()))?;
  163. let db_operation_duration = HistogramVec::new(
  164. prometheus::HistogramOpts::new(
  165. "cdk_db_operation_duration_seconds",
  166. "Database operation duration in seconds",
  167. )
  168. .buckets(vec![0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0]),
  169. &["operation"],
  170. )?;
  171. registry.register(Box::new(db_operation_duration.clone()))?;
  172. let db_connections_active = IntGauge::new(
  173. "cdk_db_connections_active",
  174. "Number of active database connections",
  175. )?;
  176. registry.register(Box::new(db_connections_active.clone()))?;
  177. Ok((
  178. db_operations_total,
  179. db_operation_duration,
  180. db_connections_active,
  181. ))
  182. }
  183. /// Create and register error metrics
  184. ///
  185. /// # Errors
  186. /// Returns an error if any of the metrics cannot be created or registered
  187. fn create_error_metrics(registry: &Registry) -> crate::Result<IntCounter> {
  188. let errors_total = IntCounter::new("cdk_errors_total", "Total errors")?;
  189. registry.register(Box::new(errors_total.clone()))?;
  190. Ok(errors_total)
  191. }
  192. /// Create and register mint metrics
  193. ///
  194. /// # Errors
  195. /// Returns an error if any of the metrics cannot be created or registered
  196. fn create_mint_metrics(
  197. registry: &Registry,
  198. ) -> crate::Result<(IntCounterVec, HistogramVec, IntGaugeVec)> {
  199. let mint_operations_total = IntCounterVec::new(
  200. prometheus::Opts::new(
  201. "cdk_mint_operations_total",
  202. "Total number of mint operations",
  203. ),
  204. &["operation", "status"],
  205. )?;
  206. registry.register(Box::new(mint_operations_total.clone()))?;
  207. let mint_operation_duration = HistogramVec::new(
  208. prometheus::HistogramOpts::new(
  209. "cdk_mint_operation_duration_seconds",
  210. "Duration of mint operations in seconds",
  211. )
  212. .buckets(vec![
  213. 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0,
  214. ]),
  215. &["operation", "status"],
  216. )?;
  217. registry.register(Box::new(mint_operation_duration.clone()))?;
  218. let mint_in_flight_requests = IntGaugeVec::new(
  219. prometheus::Opts::new(
  220. "cdk_mint_in_flight_requests",
  221. "Number of in-flight mint requests",
  222. ),
  223. &["operation"],
  224. )?;
  225. registry.register(Box::new(mint_in_flight_requests.clone()))?;
  226. Ok((
  227. mint_operations_total,
  228. mint_operation_duration,
  229. mint_in_flight_requests,
  230. ))
  231. }
  232. /// Get the metrics registry
  233. #[must_use]
  234. pub fn registry(&self) -> Arc<Registry> {
  235. Arc::<Registry>::clone(&self.registry)
  236. }
  237. // HTTP metrics methods
  238. pub fn record_http_request(&self, endpoint: &str, status: &str) {
  239. self.http_requests_total
  240. .with_label_values(&[endpoint, status])
  241. .inc();
  242. }
  243. pub fn record_http_request_duration(&self, duration_seconds: f64, endpoint: &str) {
  244. self.http_request_duration
  245. .with_label_values(&[endpoint])
  246. .observe(duration_seconds);
  247. }
  248. // Authentication metrics methods
  249. pub fn record_auth_attempt(&self) {
  250. self.auth_attempts_total.inc();
  251. }
  252. pub fn record_auth_success(&self) {
  253. self.auth_successes_total.inc();
  254. }
  255. // Lightning metrics methods
  256. pub fn record_lightning_payment(&self, amount: f64, fee: f64) {
  257. self.lightning_payments_total.inc();
  258. self.lightning_payment_amount.observe(amount);
  259. self.lightning_payment_fees.observe(fee);
  260. }
  261. // Database metrics methods
  262. pub fn record_db_operation(&self, duration_seconds: f64, op: &str) {
  263. self.db_operations_total.inc();
  264. self.db_operation_duration
  265. .with_label_values(&[op])
  266. .observe(duration_seconds);
  267. }
  268. pub fn set_db_connections_active(&self, count: i64) {
  269. self.db_connections_active.set(count);
  270. }
  271. // Error metrics methods
  272. pub fn record_error(&self) {
  273. self.errors_total.inc();
  274. }
  275. // Mint metrics methods
  276. pub fn record_mint_operation(&self, operation: &str, success: bool) {
  277. let status = if success { "success" } else { "error" };
  278. self.mint_operations_total
  279. .with_label_values(&[operation, status])
  280. .inc();
  281. }
  282. pub fn record_mint_operation_histogram(
  283. &self,
  284. operation: &str,
  285. success: bool,
  286. duration_seconds: f64,
  287. ) {
  288. let status = if success { "success" } else { "error" };
  289. self.mint_operation_duration
  290. .with_label_values(&[operation, status])
  291. .observe(duration_seconds);
  292. }
  293. pub fn inc_in_flight_requests(&self, operation: &str) {
  294. self.mint_in_flight_requests
  295. .with_label_values(&[operation])
  296. .inc();
  297. }
  298. pub fn dec_in_flight_requests(&self, operation: &str) {
  299. self.mint_in_flight_requests
  300. .with_label_values(&[operation])
  301. .dec();
  302. }
  303. }
  304. impl Default for CdkMetrics {
  305. fn default() -> Self {
  306. Self::new().expect("Failed to create default CdkMetrics")
  307. }
  308. }
  309. /// Helper functions for recording metrics using the global instance
  310. pub mod global {
  311. use super::METRICS;
  312. /// Record an HTTP request using the global metrics instance
  313. pub fn record_http_request(endpoint: &str, status: &str) {
  314. METRICS.record_http_request(endpoint, status);
  315. }
  316. /// Record HTTP request duration using the global metrics instance
  317. pub fn record_http_request_duration(duration_seconds: f64, endpoint: &str) {
  318. METRICS.record_http_request_duration(duration_seconds, endpoint);
  319. }
  320. /// Record authentication attempt using the global metrics instance
  321. pub fn record_auth_attempt() {
  322. METRICS.record_auth_attempt();
  323. }
  324. /// Record authentication success using the global metrics instance
  325. pub fn record_auth_success() {
  326. METRICS.record_auth_success();
  327. }
  328. /// Record Lightning payment using the global metrics instance
  329. pub fn record_lightning_payment(amount: f64, fee: f64) {
  330. METRICS.record_lightning_payment(amount, fee);
  331. }
  332. /// Record database operation using the global metrics instance
  333. pub fn record_db_operation(duration_seconds: f64, op: &str) {
  334. METRICS.record_db_operation(duration_seconds, op);
  335. }
  336. /// Set database connections active using the global metrics instance
  337. pub fn set_db_connections_active(count: i64) {
  338. METRICS.set_db_connections_active(count);
  339. }
  340. /// Record error using the global metrics instance
  341. pub fn record_error() {
  342. METRICS.record_error();
  343. }
  344. /// Record mint operation using the global metrics instance
  345. pub fn record_mint_operation(operation: &str, success: bool) {
  346. METRICS.record_mint_operation(operation, success);
  347. }
  348. /// Record mint operation with histogram using the global metrics instance
  349. pub fn record_mint_operation_histogram(operation: &str, success: bool, duration_seconds: f64) {
  350. METRICS.record_mint_operation_histogram(operation, success, duration_seconds);
  351. }
  352. /// Increment in-flight requests using the global metrics instance
  353. pub fn inc_in_flight_requests(operation: &str) {
  354. METRICS.inc_in_flight_requests(operation);
  355. }
  356. /// Decrement in-flight requests using the global metrics instance
  357. pub fn dec_in_flight_requests(operation: &str) {
  358. METRICS.dec_in_flight_requests(operation);
  359. }
  360. /// Get the metrics registry from the global instance
  361. pub fn registry() -> std::sync::Arc<prometheus::Registry> {
  362. METRICS.registry()
  363. }
  364. }