hoprd_api/middleware/
prometheus.rs1use axum::{extract::Request, middleware::Next, response::Response};
2#[cfg(all(feature = "telemetry", not(test)))]
3use hopr_lib::AsUnixTimestamp;
4
5#[cfg(all(feature = "telemetry", not(test)))]
6lazy_static::lazy_static! {
7 static ref METRIC_COUNT_API_CALLS: hopr_metrics::MultiCounter = hopr_metrics::MultiCounter::new(
8 "hopr_http_api_call_count",
9 "Number of different REST API calls and their statuses",
10 &["path", "method", "status"]
11 )
12 .unwrap();
13 static ref METRIC_COUNT_API_CALLS_TIMING: hopr_metrics::MultiHistogram = hopr_metrics::MultiHistogram::new(
14 "hopr_http_api_call_timing_sec",
15 "Timing of different REST API calls in seconds",
16 vec![0.1, 0.25, 0.5, 1.0, 2.0, 5.0, 10.0],
17 &["path", "method"]
18 )
19 .unwrap();
20 static ref METRIC_API_LAST_TIME: hopr_metrics::SimpleGauge = hopr_metrics::SimpleGauge::new(
21 "hopr_http_api_last_used_time",
22 "The unix timestamp in seconds at which any API endpoint was last fetched"
23 ).unwrap();
24
25 static ref ID_REGEX: regex::Regex = regex::Regex::new(r"(0x[0-9A-Fa-f]{40})|(0x[0-9A-Fa-f]{64})|(12D3KooW[A-Za-z0-9]{44})|(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{1,5})").unwrap();
30}
31
32#[cfg(all(feature = "telemetry", not(test)))]
34pub(crate) async fn record(
35 uri: axum::extract::OriginalUri,
36 method: axum::http::Method,
37 request: Request,
38 next: Next,
39) -> Response {
40 let path = uri.path().to_owned();
41
42 let start = std::time::Instant::now();
43 let response: Response = next.run(request).await;
44 let response_duration = start.elapsed();
45
46 let status = response.status();
47
48 if path.starts_with("/api/v4/") && !path.contains("node/metrics") {
50 let path = ID_REGEX.replace(&path, "<id>");
51 METRIC_COUNT_API_CALLS.increment(&[&path, method.as_str(), &status.to_string()]);
52 METRIC_COUNT_API_CALLS_TIMING.observe(&[&path, method.as_str()], response_duration.as_secs_f64());
53 }
54
55 METRIC_API_LAST_TIME.set(std::time::SystemTime::now().as_unix_timestamp().as_secs_f64());
57
58 response
59}
60
61#[cfg(any(not(feature = "telemetry"), test))]
62pub(crate) async fn record(request: Request, next: Next) -> Response {
63 next.run(request).await
64}