//! 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, /// The paths layer's (`transport::paths`); absent without one. pub(crate) paths: Option, /// The libp2p transport's; absent if it isn't one of this node's. pub(crate) libp2p: Option, } 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. pub(crate) paths: Vec, #[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 { /// `:`. pub(crate) address: String, /// Smoothed round-trip time of its PINGs; absent before an answer. pub(crate) rtt_ms: Option, /// 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, /// 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, /// 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, }