|
| 1 | +use prometheus::{CounterVec, HistogramVec, register_counter_vec, register_histogram_vec}; |
| 2 | +use std::{future::Future, sync::LazyLock}; |
| 3 | + |
| 4 | +pub static METRICS_RPC_REQUEST_OUTCOMES: LazyLock<CounterVec> = |
| 5 | + LazyLock::new(initialize_rpc_outcomes_counter); |
| 6 | + |
| 7 | +pub static METRICS_RPC_DURATION: LazyLock<HistogramVec> = |
| 8 | + LazyLock::new(initialize_rpc_duration_histogram); |
| 9 | + |
| 10 | +// Metrics defined in this module register into the Prometheus default registry. |
| 11 | +// The metrics API exposes them by calling `gather_default_metrics()`. |
| 12 | + |
| 13 | +fn initialize_rpc_outcomes_counter() -> CounterVec { |
| 14 | + register_counter_vec!( |
| 15 | + "rpc_requests_total", |
| 16 | + "Total number of RPC requests partitioned by namespace, method, and outcome", |
| 17 | + &["namespace", "method", "outcome", "error_kind"], |
| 18 | + ) |
| 19 | + .unwrap() |
| 20 | +} |
| 21 | + |
| 22 | +fn initialize_rpc_duration_histogram() -> HistogramVec { |
| 23 | + register_histogram_vec!( |
| 24 | + "rpc_request_duration_seconds", |
| 25 | + "Histogram of RPC request handling duration partitioned by namespace and method", |
| 26 | + &["namespace", "method"], |
| 27 | + ) |
| 28 | + .unwrap() |
| 29 | +} |
| 30 | + |
| 31 | +/// Represents the outcome of an RPC request when recording metrics. |
| 32 | +#[derive(Clone)] |
| 33 | +pub enum RpcOutcome { |
| 34 | + Success, |
| 35 | + Error(&'static str), |
| 36 | +} |
| 37 | + |
| 38 | +impl RpcOutcome { |
| 39 | + fn as_label(&self) -> &'static str { |
| 40 | + match self { |
| 41 | + RpcOutcome::Success => "success", |
| 42 | + RpcOutcome::Error(_) => "error", |
| 43 | + } |
| 44 | + } |
| 45 | + |
| 46 | + fn error_kind(&self) -> &str { |
| 47 | + match self { |
| 48 | + RpcOutcome::Success => "", |
| 49 | + RpcOutcome::Error(kind) => kind, |
| 50 | + } |
| 51 | + } |
| 52 | +} |
| 53 | + |
| 54 | +pub fn record_rpc_outcome(namespace: &str, method: &str, outcome: RpcOutcome) { |
| 55 | + METRICS_RPC_REQUEST_OUTCOMES |
| 56 | + .with_label_values(&[namespace, method, outcome.as_label(), outcome.error_kind()]) |
| 57 | + .inc(); |
| 58 | +} |
| 59 | + |
| 60 | +pub fn initialize_rpc_metrics() { |
| 61 | + METRICS_RPC_REQUEST_OUTCOMES.reset(); |
| 62 | + METRICS_RPC_DURATION.reset(); |
| 63 | +} |
| 64 | + |
| 65 | +/// Records the duration of an async operation in the RPC request duration histogram. |
| 66 | +/// |
| 67 | +/// This provides a lightweight alternative to the `#[instrument]` attribute. |
| 68 | +/// |
| 69 | +/// # Parameters |
| 70 | +/// * `namespace` - Category for the metric (e.g., "rpc", "engine", "block_execution") |
| 71 | +/// * `method` - Name identifier for the operation being timed |
| 72 | +/// * `future` - The async operation to time |
| 73 | +/// |
| 74 | +pub async fn record_async_duration<Fut, T>(namespace: &str, method: &str, future: Fut) -> T |
| 75 | +where |
| 76 | + Fut: Future<Output = T>, |
| 77 | +{ |
| 78 | + let timer = METRICS_RPC_DURATION |
| 79 | + .with_label_values(&[namespace, method]) |
| 80 | + .start_timer(); |
| 81 | + |
| 82 | + let output = future.await; |
| 83 | + timer.observe_duration(); |
| 84 | + output |
| 85 | +} |
0 commit comments