Close #616: Keep track of peer connection times

Signed-off-by: Lee Smet <lee.smet@hotmail.com>
This commit is contained in:
Lee Smet committed 2025-05-08 14:34:47 +02:00
1 parent 27f5d66263
commit 62c1257479
3 files changed
+54 -2

No files matched your search

+2
View File
@@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- When a route is used which is about to expire, we now send a route request to
try and refresh its duration before it expires.
- We now track when a peer was fist discovered and when we last connected to it.
This info is displayed in the CLI when listing peers.
### Fixed
+25 -1
View File
@@ -37,7 +37,9 @@ pub async fn list_peers(
"Type",
"Connection",
"Rx total",
"Tx total"
"Tx total",
"Discovered",
"Last connection"
]);
for peer in peers.iter() {
table.add_row(row![
@@ -47,6 +49,10 @@ pub async fn list_peers(
peer.connection_state,
format_bytes(peer.rx_bytes),
format_bytes(peer.tx_bytes),
format_seconds(peer.discovered),
peer.last_connected
.map(format_seconds)
.unwrap_or("Never connected".to_string()),
]);
}
table.printstd();
@@ -69,6 +75,24 @@ fn format_bytes(bytes: u64) -> String {
)
}
/// Convert an amount of seconds into a human readable string.
fn format_seconds(total_seconds: u64) -> String {
let seconds = total_seconds % 60;
let minutes = (total_seconds / 60) % 60;
let hours = (total_seconds / 3600) % 60;
let days = (total_seconds / 86400) % 60;
if days > 0 {
format!("{days}d {hours}h {minutes}m {seconds}s")
} else if hours > 0 {
format!("{hours}h {minutes}m {seconds}s")
} else if minutes > 0 {
format!("{minutes}m {seconds}s")
} else {
format!("{seconds}s")
}
}
/// Remove peer(s) by (underlay) IP
pub async fn remove_peers(
server_addr: SocketAddr,
+27 -1
View File
@@ -27,7 +27,7 @@ use std::{collections::hash_map::Entry, future::IntoFuture};
use tokio::net::TcpStream;
use tokio::net::{TcpListener, UdpSocket};
use tokio::task::AbortHandle;
use tokio::time::MissedTickBehavior;
use tokio::time::{Instant, MissedTickBehavior};
use tracing::{debug, error, info, instrument, trace, warn};
/// Magic bytes to identify a multicast UDP packet used in link local peer discovery.
@@ -88,6 +88,10 @@ struct PeerInfo {
connection_attempts: usize,
/// Keep track of the amount of bytes we've sent to and received from this peer.
con_traffic: ConnectionTraffic,
/// The moment in time we learned about this peer.
discovered: Instant,
/// The moment we last connected to this peer.
connected: Option<Instant>,
}
/// Counters for the amount of traffic written to and received from a [`Peer`].
@@ -126,6 +130,10 @@ pub struct PeerStats {
pub tx_bytes: u64,
/// Amount of bytes received from this [`Peer`].
pub rx_bytes: u64,
/// Amount of time which passed since the system learned about this [`Peer`], in seconds.
pub discovered: u64,
/// Amount of seconds since the last succesfull connection to this [`Peer`].
pub last_connected: Option<u64>,
}
impl PeerInfo {
@@ -212,6 +220,7 @@ where
// loop will perform the actual check and figure out they are dead, then
// (re)connect.
.map(|s| {
let now = tokio::time::Instant::now();
(
s,
PeerInfo {
@@ -223,6 +232,8 @@ where
tx_bytes: Arc::new(AtomicU64::new(0)),
rx_bytes: Arc::new(AtomicU64::new(0)),
},
discovered: now,
connected: None,
},
)
})
@@ -281,6 +292,7 @@ where
if peer_map.contains_key(&peer) {
return Err(PeerExists);
}
let now = tokio::time::Instant::now();
peer_map.insert(
peer,
PeerInfo {
@@ -292,6 +304,8 @@ where
tx_bytes: Arc::new(AtomicU64::new(0)),
rx_bytes: Arc::new(AtomicU64::new(0)),
},
discovered: now,
connected: None,
},
);
@@ -333,6 +347,8 @@ where
connection_state,
tx_bytes: peer_info.written(),
rx_bytes: peer_info.read(),
discovered: peer_info.discovered.elapsed().as_secs(),
last_connected: peer_info.connected.map(|i| i.elapsed().as_secs()),
});
}
pi
@@ -382,6 +398,7 @@ where
// We successfully connected, reset the connection_attempts counter to 0
pi.connection_attempts = 0;
pi.connected = Some(tokio::time::Instant::now());
} else {
// Only log with error level on the first connection failure, to avoid spamming the logs
if pi.connection_attempts == 0 {
@@ -916,6 +933,7 @@ where
}
}
// Only if we don't know it yet.
let now = tokio::time::Instant::now();
if let Entry::Vacant(e) = peers.entry(endpoint) {
e.insert(PeerInfo {
pt: discovery_type,
@@ -927,6 +945,8 @@ where
},
connection_attempts: 0,
con_traffic,
discovered: now,
connected: if peer.is_some() { Some(now) } else { None },
});
if let Some(p) = peer {
self.router.lock().unwrap().add_peer_interface(p);
@@ -936,6 +956,10 @@ where
// We got an inbound peer with a duplicate entry. This is possible if the sending port
// is the same as the previous one, which generally happens with our Quic setup. In
// this case, the old connection needs to be replaced.
let discovered = peers
.get(&endpoint)
.map(|epi| epi.discovered)
.unwrap_or(now);
let old_peer_info = peers.insert(
endpoint,
PeerInfo {
@@ -948,6 +972,8 @@ where
},
connection_attempts: 0,
con_traffic,
discovered,
connected: Some(now),
},
);
// If we have a new peer notify insert the new one in the router, then notify it that