|
| 1 | +use metrics::{counter, describe_counter, describe_gauge, describe_histogram, gauge, histogram}; |
| 2 | +use std::{sync::OnceLock, time::Duration}; |
| 3 | + |
| 4 | +// ── Metric name constants ────────────────────────────────────────── |
| 5 | + |
| 6 | +const BLOCKS_FETCHED: &str = "host_rpc.blocks_fetched"; |
| 7 | +const REORGS: &str = "host_rpc.reorgs"; |
| 8 | +const WALK_EXHAUSTED: &str = "host_rpc.walk_exhausted"; |
| 9 | +const BACKFILL_BATCHES: &str = "host_rpc.backfill_batches"; |
| 10 | +const TAG_REFRESHES: &str = "host_rpc.tag_refreshes"; |
| 11 | +const STALE_HINTS: &str = "host_rpc.stale_hints"; |
| 12 | +const RPC_ERRORS: &str = "host_rpc.rpc_errors"; |
| 13 | + |
| 14 | +const WALK_CHAIN_DURATION: &str = "host_rpc.walk_chain.duration_ms"; |
| 15 | +const FETCH_BLOCK_DURATION: &str = "host_rpc.fetch_block.duration_ms"; |
| 16 | +const BACKFILL_BATCH_DURATION: &str = "host_rpc.backfill_batch.duration_ms"; |
| 17 | +const HANDLE_NEW_HEAD_DURATION: &str = "host_rpc.handle_new_head.duration_ms"; |
| 18 | +const REORG_DEPTH: &str = "host_rpc.reorg.depth"; |
| 19 | + |
| 20 | +const CHAIN_VIEW_LEN: &str = "host_rpc.chain_view.len"; |
| 21 | +const TIP_NUMBER: &str = "host_rpc.tip.number"; |
| 22 | + |
| 23 | +// ── Self-registering descriptions ────────────────────────────────── |
| 24 | + |
| 25 | +static DESCRIBED: OnceLock<()> = OnceLock::new(); |
| 26 | + |
| 27 | +fn ensure_described() { |
| 28 | + DESCRIBED.get_or_init(|| { |
| 29 | + describe_counter!(BLOCKS_FETCHED, "Total blocks fetched via RPC"); |
| 30 | + describe_counter!(REORGS, "Chain reorg events detected"); |
| 31 | + describe_counter!(WALK_EXHAUSTED, "Walk exhausted the chain view buffer"); |
| 32 | + describe_counter!(BACKFILL_BATCHES, "Backfill batches completed"); |
| 33 | + describe_counter!(TAG_REFRESHES, "Epoch boundary tag refreshes"); |
| 34 | + describe_counter!(STALE_HINTS, "Stale subscription hints that fell back to latest"); |
| 35 | + describe_counter!(RPC_ERRORS, "RPC transport/provider errors"); |
| 36 | + describe_histogram!(WALK_CHAIN_DURATION, "Time to walk the chain (ms)"); |
| 37 | + describe_histogram!(FETCH_BLOCK_DURATION, "Single block+receipts fetch (ms)"); |
| 38 | + describe_histogram!(BACKFILL_BATCH_DURATION, "Full backfill batch (ms)"); |
| 39 | + describe_histogram!(HANDLE_NEW_HEAD_DURATION, "Full new-head processing (ms)"); |
| 40 | + describe_histogram!(REORG_DEPTH, "Number of blocks reverted in a reorg"); |
| 41 | + describe_gauge!(CHAIN_VIEW_LEN, "Current chain view buffer size"); |
| 42 | + describe_gauge!(TIP_NUMBER, "Current tip block number"); |
| 43 | + }); |
| 44 | +} |
| 45 | + |
| 46 | +// ── Helper functions ─────────────────────────────────────────────── |
| 47 | + |
| 48 | +/// Record the duration of a `walk_chain` call. |
| 49 | +pub(crate) fn record_walk_duration(duration: Duration) { |
| 50 | + ensure_described(); |
| 51 | + histogram!(WALK_CHAIN_DURATION).record(duration.as_secs_f64() * 1000.0); |
| 52 | +} |
| 53 | + |
| 54 | +/// Increment the walk-exhausted counter. |
| 55 | +pub(crate) fn inc_walk_exhausted() { |
| 56 | + ensure_described(); |
| 57 | + counter!(WALK_EXHAUSTED).increment(1); |
| 58 | +} |
| 59 | + |
| 60 | +/// Record a single block fetch duration. |
| 61 | +pub(crate) fn record_fetch_block_duration(duration: Duration) { |
| 62 | + ensure_described(); |
| 63 | + histogram!(FETCH_BLOCK_DURATION).record(duration.as_secs_f64() * 1000.0); |
| 64 | +} |
| 65 | + |
| 66 | +/// Record blocks fetched with a mode label. |
| 67 | +pub(crate) fn inc_blocks_fetched(count: u64, mode: &'static str) { |
| 68 | + ensure_described(); |
| 69 | + counter!(BLOCKS_FETCHED, "mode" => mode).increment(count); |
| 70 | +} |
| 71 | + |
| 72 | +/// Record a reorg event with its depth. |
| 73 | +pub(crate) fn inc_reorgs(depth: u64) { |
| 74 | + ensure_described(); |
| 75 | + counter!(REORGS).increment(1); |
| 76 | + histogram!(REORG_DEPTH).record(depth as f64); |
| 77 | +} |
| 78 | + |
| 79 | +/// Increment the stale-hints counter. |
| 80 | +pub(crate) fn inc_stale_hints() { |
| 81 | + ensure_described(); |
| 82 | + counter!(STALE_HINTS).increment(1); |
| 83 | +} |
| 84 | + |
| 85 | +/// Increment the RPC errors counter. |
| 86 | +pub(crate) fn inc_rpc_errors() { |
| 87 | + ensure_described(); |
| 88 | + counter!(RPC_ERRORS).increment(1); |
| 89 | +} |
| 90 | + |
| 91 | +/// Record a backfill batch completion. |
| 92 | +pub(crate) fn record_backfill_batch(duration: Duration) { |
| 93 | + ensure_described(); |
| 94 | + counter!(BACKFILL_BATCHES).increment(1); |
| 95 | + histogram!(BACKFILL_BATCH_DURATION).record(duration.as_secs_f64() * 1000.0); |
| 96 | +} |
| 97 | + |
| 98 | +/// Record `handle_new_head` duration. |
| 99 | +pub(crate) fn record_handle_new_head_duration(duration: Duration) { |
| 100 | + ensure_described(); |
| 101 | + histogram!(HANDLE_NEW_HEAD_DURATION).record(duration.as_secs_f64() * 1000.0); |
| 102 | +} |
| 103 | + |
| 104 | +/// Increment the tag-refreshes counter. |
| 105 | +pub(crate) fn inc_tag_refreshes() { |
| 106 | + ensure_described(); |
| 107 | + counter!(TAG_REFRESHES).increment(1); |
| 108 | +} |
| 109 | + |
| 110 | +/// Update the chain view length gauge. |
| 111 | +pub(crate) fn set_chain_view_len(len: usize) { |
| 112 | + ensure_described(); |
| 113 | + gauge!(CHAIN_VIEW_LEN).set(len as f64); |
| 114 | +} |
| 115 | + |
| 116 | +/// Update the tip block number gauge. |
| 117 | +pub(crate) fn set_tip(number: u64) { |
| 118 | + ensure_described(); |
| 119 | + gauge!(TIP_NUMBER).set(number as f64); |
| 120 | +} |
0 commit comments