summaryrefslogtreecommitdiffstats
path: root/src/api/stats
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-26 20:48:45 +0100
committertv <tv@krebsco.de>2026-10-26 20:48:45 +0100
commit5854fe5a3a7c7e8f681264d3a4b27597a8c61de0 (patch)
treee5c5f085a291a633140edb2cf7d1757b3567c69f /src/api/stats
parent8414f96f27b059c4536ae67ddfce18dec54e7451 (diff)
add sync and relay stats
Diffstat (limited to 'src/api/stats')
-rw-r--r--src/api/stats/prometheus.rs68
1 files changed, 68 insertions, 0 deletions
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<f64>,
+ last_sync_secs: Option<f64>,
+ diverged_secs: Option<f64>,
traffic: PeerTraffic,
incidents: Incidents,
rtt_secs: Option<f64>,
@@ -142,6 +144,12 @@ async fn peers(state: &AppState) -> Vec<Peer> {
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",
@@ -490,6 +538,26 @@ pub(super) async fn render(state: &AppState, stats: &StatsResponse) -> String {
}
}
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",
"Effective round-trip time (smoothed, raised by unanswered requests).",