aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/stats
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-31 04:10:37 +0100
committertv <tv@krebsco.de>2026-10-31 04:10:37 +0100
commitd661f9e001a5b7866d67756a24cb66885471195d (patch)
tree8bf89e628fe11539ad05abd985ebc296c4fc55f0 /src/api/stats
parent4a2793864047134c6521dc44562828b6ab071c17 (diff)
prometheus: build per-peer series from /peers
Diffstat (limited to 'src/api/stats')
-rw-r--r--src/api/stats/prometheus.rs70
1 files changed, 26 insertions, 44 deletions
diff --git a/src/api/stats/prometheus.rs b/src/api/stats/prometheus.rs
index 01f1619..9180d9d 100644
--- a/src/api/stats/prometheus.rs
+++ b/src/api/stats/prometheus.rs
@@ -4,11 +4,9 @@
use std::fmt::Write;
-use tokio::time::Instant;
-
use super::StatsResponse;
-use crate::locks::MutexExt;
-use crate::state::{AppState, Incidents, Liveness};
+use crate::api::peers::{PeerListResponse, PeerLivenessStatus};
+use crate::state::Incidents;
use crate::transport::Destination;
use crate::transport::stats::{Reachability, TransportStats};
use crate::transport::traffic::{ByKind, Counter, PeerTraffic};
@@ -128,43 +126,26 @@ struct Peer {
destination: Option<Destination>,
}
-async fn peers(state: &AppState) -> Vec<Peer> {
- let now = Instant::now();
- let snapshot = state.peers_snapshot().await;
- let mut aliases = crate::swarm::members::aliases(&state.doc.read().await.doc);
- let mut peers = Vec::with_capacity(snapshot.len());
- for (key, peer_state) in snapshot {
- let neighbour = crate::swarm::topology::is_neighbour(state, &key);
- let throughput = state
- .throughput
- .lock_or_recover()
- .get(&key)
- .map(|estimate| estimate.bytes_per_sec);
- let traffic = state.traffic.peer(&key).unwrap_or_default();
- let peer_state = peer_state.lock().await;
- peers.push(Peer {
- neighbour,
- unknown: peer_state.liveness == Liveness::Unknown,
- dormant: matches!(peer_state.liveness, Liveness::Dormant { .. }),
- 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,
- throughput,
- alias: aliases.remove(&key),
- destination: state.transport.destination(&key),
- key,
- });
- }
- peers.sort_by(|a, b| a.key.cmp(&b.key));
- peers
+/// The rows of `/peers` (`peers::peer_list`), as the series need them.
+fn peers(list: &PeerListResponse) -> Vec<Peer> {
+ let secs = |secs: Option<u64>| secs.map(|secs| secs as f64);
+ list.peers
+ .iter()
+ .map(|(key, peer)| Peer {
+ key: key.clone(),
+ alias: peer.alias.clone(),
+ neighbour: peer.neighbour,
+ unknown: matches!(peer.status, PeerLivenessStatus::Unknown),
+ dormant: matches!(peer.status, PeerLivenessStatus::Dormant),
+ last_seen_secs: secs(peer.last_seen_secs_ago),
+ last_sync_secs: secs(peer.last_sync_secs_ago),
+ diverged_secs: secs(peer.diverged_for_secs),
+ traffic: peer.traffic,
+ incidents: peer.incidents,
+ throughput: peer.sync_throughput.as_ref().map(|t| t.bytes_per_sec),
+ destination: peer.destination.clone(),
+ })
+ .collect()
}
/// Every (direction, kind, counter) of `traffic`.
@@ -399,7 +380,8 @@ pub(super) fn render_relay_only(stats: &super::RelayOnlyStats) -> String {
/// A per-peer incident counter: its name, its help and how to read it.
type IncidentSeries = (&'static str, &'static str, fn(&Incidents) -> f64);
-pub(super) async fn render(state: &AppState, stats: &StatsResponse) -> String {
+/// `stats` and `list` (`/peers`) as series: nothing read anew.
+pub(super) fn render(stats: &StatsResponse, list: &PeerListResponse) -> String {
let mut out = Out::default();
// Names for joining (`* on(peer) group_left(alias) continuum_peer_info`), kept out
@@ -430,7 +412,7 @@ pub(super) async fn render(state: &AppState, stats: &StatsResponse) -> String {
"epoch_generation",
"gauge",
"Generation of the local epoch (remakes so far).",
- state.local_epoch().generation as f64,
+ stats.epoch.generation as f64,
);
let document = &stats.document;
@@ -807,7 +789,7 @@ pub(super) async fn render(state: &AppState, stats: &StatsResponse) -> String {
transports(&mut out, &stats.transports);
- let peers = peers(state).await;
+ let peers = peers(list);
out.family(
"peer_info",