diff options
Diffstat (limited to 'src/transport/stats.rs')
| -rw-r--r-- | src/transport/stats.rs | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/src/transport/stats.rs b/src/transport/stats.rs new file mode 100644 index 0000000..398ffdf --- /dev/null +++ b/src/transport/stats.rs @@ -0,0 +1,189 @@ +//! Figures about the transports themselves (`Transport::stats`), for /admin/stats +//! (`transports`, `docs/measurements.md`): how they find and reach peers, besides the +//! messages counted per peer (`traffic`). + +use std::collections::BTreeMap; + +use serde::Serialize; + +#[derive(Debug, Clone, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct TransportStats { + /// The identity layer's (`transport::identity`); absent without one. + pub(crate) identity: Option<IdentityStats>, + /// The paths layer's (`transport::paths`); absent without one. + pub(crate) paths: Option<PathsStats>, + /// The libp2p transport's; absent if it isn't one of this node's. + pub(crate) libp2p: Option<Libp2pStats>, +} + +impl TransportStats { + /// Takes what `other` has. + pub(crate) fn merge(&mut self, other: TransportStats) { + if other.identity.is_some() { + self.identity = other.identity; + } + if other.paths.is_some() { + self.paths = other.paths; + } + if other.libp2p.is_some() { + self.libp2p = other.libp2p; + } + } +} + +/// How the paths to peers with several addresses do (`transport::paths`). +#[derive(Debug, Clone, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct PathsStats { + /// Every path measured: those of peers this node chose among lately, and those its + /// keepalives went over. + pub(crate) paths: Vec<PathInfo>, + #[serde(flatten)] + pub(crate) counts: PathCounts, +} + +/// One path, as `transport::paths` measures it. +#[derive(Debug, Clone, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct PathInfo { + /// `<scheme>:<where it goes>`: where the transport says the path goes now + /// (`Transport::location`; libp2p: the remote address of its connection, ending in + /// the peer ID), else whom it goes to, `<scheme>:<transport identity>` (a libp2p + /// peer ID without a connection, a Mycelium public key, an onion service). + pub(crate) address: String, + /// Smoothed round-trip time of its PINGs (ours, and our keepalives); absent before + /// an answer. + pub(crate) rtt_ms: Option<f64>, + /// Its PINGs went unanswered three times in a row, or a send there failed within a + /// minute: used only when no other path works. + pub(crate) down: bool, +} + +/// Counts since start. +#[derive(Debug, Clone, Copy, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct PathCounts { + pub(crate) probes_sent: u64, + pub(crate) probes_answered: u64, + pub(crate) probes_unanswered: u64, + /// Sends that failed on a path (each tried at the next). + pub(crate) send_failures: u64, + /// Sends that went over another path after one failed. + pub(crate) failovers: u64, + /// Changes of the path in use for one faster. + pub(crate) switches: u64, +} + +/// Who is where (`transport::identity`): the books now, and counts since start. +#[derive(Debug, Clone, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct IdentityStats { + /// Nodes proven at an address, by transport (scheme); a node on several counts on + /// each. + pub(crate) proven: BTreeMap<String, usize>, + /// Nodes known only from hints (the member list, HELLO_REPLYs), proven nowhere. + pub(crate) hinted: usize, + #[serde(flatten)] + pub(crate) counts: IdentityCounts, +} + +#[derive(Debug, Clone, Copy, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct IdentityCounts { + /// Proofs that didn't hold (a bad signature, or made for other addresses): normally + /// none. + pub(crate) proofs_rejected: u64, + /// Nodes that proved themselves at another address on a transport than before: a + /// node restarted with a new transport identity (a new libp2p key or Mycelium key). + pub(crate) address_changes: u64, + /// Messages dropped because no node proved itself at their address: some after a + /// restart are normal, a steady stream is not. + pub(crate) dropped_unproven: u64, + /// Sends refused because the peer hadn't proven where it is yet (`NotProven`). + pub(crate) refused_unproven: u64, + /// Seeds no node answered at in time. + pub(crate) seeds_unanswered: u64, +} + +/// Whether others can dial this node, as AutoNAT found out. +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize)] +#[serde(rename_all = "camelCase")] +pub(crate) enum Reachability { + #[default] + Unknown, + /// Others can't dial it: it needs a relay. + Private, + Public, +} + +impl Reachability { + pub(crate) const ALL: [Reachability; 3] = [Self::Unknown, Self::Private, Self::Public]; + + pub(crate) fn as_str(self) -> &'static str { + match self { + Self::Unknown => "unknown", + Self::Private => "private", + Self::Public => "public", + } + } +} + +#[derive(Debug, Clone, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct Libp2pStats { + pub(crate) reachability: Reachability, + /// The address AutoNAT confirmed others can dial, while public. + pub(crate) public_address: Option<String>, + /// Open connections, now. + pub(crate) connections: Connections, + pub(crate) relay_slots: RelaySlots, + /// Direct connections tried over a relayed one (DCUtR), since start. + pub(crate) hole_punches: HolePunches, + /// Connections that couldn't be made, by cause, since start. + pub(crate) dial_failures: DialFailures, +} + +#[derive(Debug, Clone, Copy, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct Connections { + pub(crate) direct: usize, + /// Through a relay (a circuit). + pub(crate) relayed: usize, +} + +/// Slots this node holds on relays, to be reachable through them. +#[derive(Debug, Clone, Copy, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct RelaySlots { + /// Held now. + pub(crate) held: usize, + /// Relays picked that never granted a slot, not picked again for a while now. + pub(crate) paused: usize, + /// Since start: slots granted (not counting renewals), lost after being granted, and + /// asked for but never granted (a relay unreachable, or another peer at its + /// address: a relay restarted without its libp2p key). + pub(crate) granted: u64, + pub(crate) lost: u64, + pub(crate) not_granted: u64, +} + +#[derive(Debug, Clone, Copy, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct HolePunches { + pub(crate) succeeded: u64, + /// The relay carries on. + pub(crate) failed: u64, +} + +#[derive(Debug, Clone, Copy, Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct DialFailures { + /// No address of the peer could be reached (refused, timed out, no route). + pub(crate) unreachable: u64, + /// Another peer answered at the address: one restarted without its libp2p key. + pub(crate) wrong_peer_id: u64, + /// No address known for the peer. + pub(crate) no_addresses: u64, + pub(crate) other: u64, +} |
