From 4855ff63536430b1cd26734a0eeeaf0c25df553e Mon Sep 17 00:00:00 2001 From: tv Date: Sat, 31 Oct 2026 06:51:17 +0100 Subject: calculate peer clock drift --- src/api/peers.rs | 6 ++++++ src/api/stats/prometheus.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) (limited to 'src/api') diff --git a/src/api/peers.rs b/src/api/peers.rs index 020221b..3fe4c39 100644 --- a/src/api/peers.rs +++ b/src/api/peers.rs @@ -18,6 +18,7 @@ use crate::locks::MutexExt; use crate::state::{AppState, HelloState, Incidents, Liveness}; use crate::swarm::peer::forgotten_path; use crate::transport::Destination; +use crate::transport::paths::ClockOffset; use crate::transport::traffic::PeerTraffic; #[derive(Debug, Serialize)] @@ -66,6 +67,9 @@ pub(crate) struct PeerStatus { /// Smoothed sync throughput (`swarm::throughput`); absent before the first large /// exchange. pub(crate) sync_throughput: Option, + /// How far its clock is ahead of ours, give or take (`Transport::clock_offset`); + /// absent before a PONG from it. + pub(crate) clock: Option, } #[derive(Debug, Serialize)] @@ -141,6 +145,7 @@ pub(crate) async fn peer_list(state: &AppState) -> PeerListResponse { let alias = aliases.remove(&peer); let addresses = state.transport.addresses_of(&peer); let destination = state.transport.destination(&peer); + let clock = state.transport.clock_offset(&peer); peers.insert( peer, PeerStatus { @@ -168,6 +173,7 @@ pub(crate) async fn peer_list(state: &AppState) -> PeerListResponse { traffic, incidents: ps.incidents, sync_throughput, + clock, }, ); } diff --git a/src/api/stats/prometheus.rs b/src/api/stats/prometheus.rs index 8f7538f..2f33bef 100644 --- a/src/api/stats/prometheus.rs +++ b/src/api/stats/prometheus.rs @@ -9,6 +9,7 @@ use crate::api::media_type; use crate::api::peers::{PeerListResponse, PeerLivenessStatus}; use crate::state::Incidents; use crate::transport::Destination; +use crate::transport::paths::ClockOffset; use crate::transport::stats::{Reachability, TransportStats}; use crate::transport::traffic::{ByKind, Counter, PeerTraffic}; @@ -151,6 +152,7 @@ struct Peer { incidents: Incidents, throughput: Option, destination: Option, + clock: Option, } /// The rows of `/peers` (`peers::peer_list`), as the series need them. @@ -171,6 +173,7 @@ fn peers(list: &PeerListResponse) -> Vec { incidents: peer.incidents, throughput: peer.sync_throughput.as_ref().map(|t| t.bytes_per_sec), destination: peer.destination.clone(), + clock: peer.clock, }) .collect() } @@ -927,6 +930,35 @@ pub(super) fn render(stats: &StatsResponse, list: &PeerListResponse) -> String { } } + out.family( + "peer_clock_offset_seconds", + "gauge", + "How far the peer's clock is ahead of ours (behind: negative), from its PONGs.", + ); + for peer in &peers { + if let Some(clock) = peer.clock { + out.sample( + "peer_clock_offset_seconds", + &[("peer", &peer.key)], + clock.offset_ms as f64 / 1000.0, + ); + } + } + out.family( + "peer_clock_offset_within_seconds", + "gauge", + "Give or take this much: half the round trip it was measured over.", + ); + for peer in &peers { + if let Some(clock) = peer.clock { + out.sample( + "peer_clock_offset_within_seconds", + &[("peer", &peer.key)], + clock.within_ms as f64 / 1000.0, + ); + } + } + out.family( "peer_messages_total", "counter", -- cgit v1.3.1