diff options
| author | tv <tv@krebsco.de> | 2026-10-31 06:53:00 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-10-31 06:53:00 +0100 |
| commit | df3f11a337955dd703199cc2b037d4bfb698ceba (patch) | |
| tree | 9077b4bb32b3a492005aad04ddf329a28a39c22d /src/api | |
| parent | 4855ff63536430b1cd26734a0eeeaf0c25df553e (diff) | |
add peer clock skew warning
Diffstat (limited to 'src/api')
| -rw-r--r-- | src/api/stats.rs | 16 | ||||
| -rw-r--r-- | src/api/stats/prometheus.rs | 22 |
2 files changed, 37 insertions, 1 deletions
diff --git a/src/api/stats.rs b/src/api/stats.rs index 13610dd..d274fd9 100644 --- a/src/api/stats.rs +++ b/src/api/stats.rs @@ -13,9 +13,10 @@ use std::collections::BTreeMap; use serde::Serialize; -use super::peers::{PeerListResponse, peer_list}; +use super::peers::{PeerListResponse, PeerLivenessStatus, peer_list}; use crate::document::replica::EpochRecord; use crate::state::{AppState, Incidents}; +use crate::swarm::skew::{self, Skew}; use crate::swarm::{members, stability, topology}; use crate::transport::stats::TransportStats; use crate::transport::traffic::PeerTraffic; @@ -44,6 +45,8 @@ pub(crate) struct StatsResponse { /// The peers listed in /peers together (a forgotten peer's are gone). incidents: Incidents, propagation: PropagationStats, + /// This node's clock against its active peers' (`swarm::skew`). + clock: Skew, /// This node's own files (`files`), by kind. disk: BTreeMap<&'static str, DiskStats>, /// How the transports find and reach peers (`Transport::stats`). @@ -271,6 +274,16 @@ pub(crate) async fn collect(state: &AppState, list: &PeerListResponse) -> StatsR let (connected_fraction, observed) = stability::measured(state); + let clock = skew::of( + &list + .peers + .values() + .filter(|peer| !matches!(peer.status, PeerLivenessStatus::Dormant)) + .filter_map(|peer| peer.clock) + .collect::<Vec<_>>(), + state.clock_skew_warn, + ); + let mut incidents = Incidents::default(); let mut last_from_neighbour_secs: Option<u64> = None; let mut diverged_peers = 0; @@ -347,6 +360,7 @@ pub(crate) async fn collect(state: &AppState, list: &PeerListResponse) -> StatsR stale_hello_replies: node.stale_hello_replies, traffic: state.traffic.total(), incidents, + clock, propagation: PropagationStats { count: node.propagation.count, sum_ms: node.propagation.sum_ms, diff --git a/src/api/stats/prometheus.rs b/src/api/stats/prometheus.rs index 2f33bef..6774e74 100644 --- a/src/api/stats/prometheus.rs +++ b/src/api/stats/prometheus.rs @@ -763,6 +763,28 @@ pub(super) fn render(stats: &StatsResponse, list: &PeerListResponse) -> String { propagation.ahead as f64, ); + let clock = &stats.clock; + out.single( + "clock_peers_compared", + "gauge", + "Active peers whose clocks were compared with ours (from their PONGs).", + clock.peers as f64, + ); + if let Some(offset_ms) = clock.offset_ms { + out.single( + "clock_offset_seconds", + "gauge", + "How far this node's clock is ahead of its peers' (behind: negative), the median.", + offset_ms as f64 / 1000.0, + ); + } + out.single( + "clock_off", + "gauge", + "1 while this node's clock differs from most of its peers' by more than --clock-skew-warn.", + flag(clock.off), + ); + // Node totals, including peers no longer listed. let totals = traffic_series(&stats.traffic); out.family( |
