diff options
| author | murilo ijanc | 2026-03-24 15:04:03 -0300 |
|---|---|---|
| committer | murilo ijanc | 2026-03-24 15:04:03 -0300 |
| commit | 9821aabf0b50d2487b07502d3d2cd89e7d62bdbe (patch) | |
| tree | 53da095ff90cc755bac3d4bf699172b5e8cd07d6 /src/metrics.rs | |
| download | tesseras-dht-e908bc01403f4b8ef2a65fa6be43716fd1c6e003.tar.gz | |
Initial commitv0.1.0
NAT-aware Kademlia DHT library for peer-to-peer networks.
Features:
- Distributed key-value storage (iterative FIND_NODE, FIND_VALUE, STORE)
- NAT traversal via DTUN hole-punching and proxy relay
- Reliable Datagram Protocol (RDP) with 7-state connection machine
- Datagram transport with automatic fragmentation/reassembly
- Ed25519 packet authentication
- 256-bit node IDs (Ed25519 public keys)
- Rate limiting, ban list, and eclipse attack mitigation
- Persistence and metrics
- OpenBSD and Linux support
Diffstat (limited to 'src/metrics.rs')
| -rw-r--r-- | src/metrics.rs | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/src/metrics.rs b/src/metrics.rs new file mode 100644 index 0000000..67ec30f --- /dev/null +++ b/src/metrics.rs @@ -0,0 +1,121 @@ +//! Node metrics and observability. +//! +//! Atomic counters for messages, lookups, storage, +//! and errors. Accessible via `Tessera::metrics()`. + +use std::sync::atomic::{AtomicU64, Ordering}; + +/// Atomic metrics counters. +pub struct Metrics { + pub messages_sent: AtomicU64, + pub messages_received: AtomicU64, + pub lookups_started: AtomicU64, + pub lookups_completed: AtomicU64, + pub rpc_timeouts: AtomicU64, + pub values_stored: AtomicU64, + pub packets_rejected: AtomicU64, + pub bytes_sent: AtomicU64, + pub bytes_received: AtomicU64, +} + +impl Metrics { + pub fn new() -> Self { + Self { + messages_sent: AtomicU64::new(0), + messages_received: AtomicU64::new(0), + lookups_started: AtomicU64::new(0), + lookups_completed: AtomicU64::new(0), + rpc_timeouts: AtomicU64::new(0), + values_stored: AtomicU64::new(0), + packets_rejected: AtomicU64::new(0), + bytes_sent: AtomicU64::new(0), + bytes_received: AtomicU64::new(0), + } + } + + /// Take a snapshot of all counters. + pub fn snapshot(&self) -> MetricsSnapshot { + MetricsSnapshot { + messages_sent: self.messages_sent.load(Ordering::Relaxed), + messages_received: self.messages_received.load(Ordering::Relaxed), + lookups_started: self.lookups_started.load(Ordering::Relaxed), + lookups_completed: self.lookups_completed.load(Ordering::Relaxed), + rpc_timeouts: self.rpc_timeouts.load(Ordering::Relaxed), + values_stored: self.values_stored.load(Ordering::Relaxed), + packets_rejected: self.packets_rejected.load(Ordering::Relaxed), + bytes_sent: self.bytes_sent.load(Ordering::Relaxed), + bytes_received: self.bytes_received.load(Ordering::Relaxed), + } + } +} + +impl Default for Metrics { + fn default() -> Self { + Self::new() + } +} + +/// Snapshot of metrics at a point in time. +#[derive(Debug, Clone)] +pub struct MetricsSnapshot { + pub messages_sent: u64, + pub messages_received: u64, + pub lookups_started: u64, + pub lookups_completed: u64, + pub rpc_timeouts: u64, + pub values_stored: u64, + pub packets_rejected: u64, + pub bytes_sent: u64, + pub bytes_received: u64, +} + +impl std::fmt::Display for MetricsSnapshot { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "sent={} recv={} lookups={}/{} timeouts={} \ + stored={} rejected={} bytes={}/{}", + self.messages_sent, + self.messages_received, + self.lookups_completed, + self.lookups_started, + self.rpc_timeouts, + self.values_stored, + self.packets_rejected, + self.bytes_sent, + self.bytes_received, + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn counters_start_zero() { + let m = Metrics::new(); + let s = m.snapshot(); + assert_eq!(s.messages_sent, 0); + assert_eq!(s.bytes_sent, 0); + } + + #[test] + fn increment_and_snapshot() { + let m = Metrics::new(); + m.messages_sent.fetch_add(5, Ordering::Relaxed); + m.bytes_sent.fetch_add(1000, Ordering::Relaxed); + let s = m.snapshot(); + assert_eq!(s.messages_sent, 5); + assert_eq!(s.bytes_sent, 1000); + } + + #[test] + fn display_format() { + let m = Metrics::new(); + m.messages_sent.fetch_add(10, Ordering::Relaxed); + let s = m.snapshot(); + let text = format!("{s}"); + assert!(text.contains("sent=10")); + } +} |