From 5854fe5a3a7c7e8f681264d3a4b27597a8c61de0 Mon Sep 17 00:00:00 2001 From: tv Date: Mon, 26 Oct 2026 20:48:45 +0100 Subject: add sync and relay stats --- src/api/stats/prometheus.rs | 68 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'src/api/stats/prometheus.rs') diff --git a/src/api/stats/prometheus.rs b/src/api/stats/prometheus.rs index 6fd37a0..3baa125 100644 --- a/src/api/stats/prometheus.rs +++ b/src/api/stats/prometheus.rs @@ -112,6 +112,8 @@ struct Peer { neighbour: bool, dormant: bool, last_seen_secs: Option, + last_sync_secs: Option, + diverged_secs: Option, traffic: PeerTraffic, incidents: Incidents, rtt_secs: Option, @@ -142,6 +144,12 @@ async fn peers(state: &AppState) -> Vec { last_seen_secs: peer_state .last_seen .map(|t| now.saturating_duration_since(t).as_secs_f64()), + last_sync_secs: peer_state + .last_sync_rx + .map(|t| now.saturating_duration_since(t).as_secs_f64()), + diverged_secs: peer_state + .diverged_since + .map(|t| now.saturating_duration_since(t).as_secs_f64()), traffic, incidents: peer_state.incidents, rtt_secs, @@ -303,6 +311,46 @@ pub(super) async fn render(state: &AppState, stats: &StatsResponse) -> String { remakes.archived_epochs as f64, ); + if let Some(secs) = stats.sync.last_from_neighbour_secs { + out.single( + "last_sync_from_neighbour_seconds", + "gauge", + "Seconds since a sync message from any neighbour was applied.", + secs as f64, + ); + } + out.single( + "diverged_peers", + "gauge", + "Peers whose heads differ from ours while sync is idle.", + stats.sync.diverged_peers as f64, + ); + let relay = &stats.relay; + out.single( + "announce_rounds_total", + "counter", + "Announcement rounds (our new heads to the neighbours).", + relay.announce_rounds as f64, + ); + out.single( + "pulls_total", + "counter", + "Pulls of changes we lacked, started.", + relay.pulls as f64, + ); + out.single( + "pulls_queued_total", + "counter", + "Announcements of heads we lacked that waited for the pull in progress.", + relay.pulls_queued as f64, + ); + out.single( + "blob_requests_dropped_total", + "counter", + "Blob requests not answered: too many were being answered.", + relay.blob_requests_dropped as f64, + ); + let topology = &stats.topology; out.single( "neighbours_target", @@ -489,6 +537,26 @@ pub(super) async fn render(state: &AppState, stats: &StatsResponse) -> String { out.sample("peer_last_seen_seconds", &[("peer", &peer.key)], secs); } } + out.family( + "peer_last_sync_seconds", + "gauge", + "Seconds since a sync message from the peer was applied (or the epoch changed).", + ); + for peer in &peers { + if let Some(secs) = peer.last_sync_secs { + out.sample("peer_last_sync_seconds", &[("peer", &peer.key)], secs); + } + } + out.family( + "peer_diverged_seconds", + "gauge", + "Seconds the peer's heads have differed from ours while sync was idle.", + ); + for peer in &peers { + if let Some(secs) = peer.diverged_secs { + out.sample("peer_diverged_seconds", &[("peer", &peer.key)], secs); + } + } out.family( "peer_rtt_seconds", "gauge", -- cgit v1.3.1