hoprd_api/
prometheus.rs

1use axum::{extract::Request, middleware::Next, response::Response};
2
3#[cfg(all(feature = "prometheus", not(test)))]
4use hopr_metrics::metrics::{MultiCounter, MultiHistogram};
5
6#[cfg(all(feature = "prometheus", not(test)))]
7lazy_static::lazy_static! {
8    static ref METRIC_COUNT_API_CALLS: MultiCounter = MultiCounter::new(
9        "hopr_http_api_call_count",
10        "Number of different REST API calls and their statuses",
11        &["endpoint", "method", "status"]
12    )
13    .unwrap();
14    static ref METRIC_COUNT_API_CALLS_TIMING: MultiHistogram = MultiHistogram::new(
15        "hopr_http_api_call_timing_sec",
16        "Timing of different REST API calls in seconds",
17        vec![0.1, 0.25, 0.5, 1.0, 2.0, 5.0, 10.0],
18        &["endpoint", "method"]
19    )
20    .unwrap();
21
22    // Matches Ed25519-based peer IDs and channel IDs (Keccak256 hashes)
23    static ref ID_REGEX: regex::Regex = regex::Regex::new(r"(0x[0-9A-Fa-f]{64})|(12D3KooW[A-z0-9]{44})").unwrap();
24}
25
26/// Custom prometheus recording middleware
27#[cfg(all(feature = "prometheus", not(test)))]
28pub(crate) async fn record(
29    uri: axum::extract::OriginalUri,
30    method: axum::http::Method,
31    request: Request,
32    next: Next,
33) -> Response {
34    let path = uri.path().to_owned();
35
36    let start = std::time::Instant::now();
37    let response: Response = next.run(request).await;
38    let response_duration = start.elapsed();
39
40    let status = response.status();
41
42    // We're not interested in metrics for other than our own API endpoints
43    if path.starts_with("/api/v3/") && !path.contains("node/metrics") {
44        let path = ID_REGEX.replace(&path, "<id>");
45        METRIC_COUNT_API_CALLS.increment(&[&path, method.as_str(), &status.to_string()]);
46        METRIC_COUNT_API_CALLS_TIMING.observe(&[&path, method.as_str()], response_duration.as_secs_f64());
47    }
48
49    response
50}
51
52#[cfg(any(not(feature = "prometheus"), test))]
53pub(crate) async fn record(request: Request, next: Next) -> Response {
54    next.run(request).await
55}