use crate::common::ClientId;
use std::time::Duration;
#[derive(Debug, Clone, Default)]
pub struct ClientMetrics {
pub client_id: ClientId,
pub messages_sent: u64,
pub messages_received: u64,
pub messages_failed: u64,
pub connection_errors: u64,
pub total_rtt_ms: u64,
pub min_rtt_ms: Option<u64>,
pub max_rtt_ms: Option<u64>,
pub http_connections_created: u64,
pub http_connections_reused: u64,
pub http_status_codes: std::collections::HashMap<u16, u64>,
pub total_clients: u32,
}
impl ClientMetrics {
pub fn new(client_id: ClientId) -> Self {
Self {
client_id,
total_clients: 1, ..Default::default()
}
}
pub fn record_success(&mut self, rtt: Duration) {
self.messages_received += 1;
let rtt_ms = u64::try_from(rtt.as_millis()).unwrap_or(u64::MAX);
self.total_rtt_ms += rtt_ms;
self.min_rtt_ms = Some(match self.min_rtt_ms {
Some(min) => min.min(rtt_ms),
None => rtt_ms,
});
self.max_rtt_ms = Some(match self.max_rtt_ms {
Some(max) => max.max(rtt_ms),
None => rtt_ms,
});
}
pub fn record_sent(&mut self) {
self.messages_sent += 1;
}
pub fn record_failure(&mut self) {
self.messages_failed += 1;
}
pub fn record_connection_error(&mut self) {
self.connection_errors += 1;
}
pub fn record_http_connection_created(&mut self) {
self.http_connections_created += 1;
}
pub fn record_http_connection_reused(&mut self) {
self.http_connections_reused += 1;
}
pub fn record_http_status_code(&mut self, status_code: u16) {
*self.http_status_codes.entry(status_code).or_insert(0) += 1;
}
pub fn success_rate(&self) -> f64 {
let total = self.messages_sent;
if total == 0 {
return 100.0;
}
if self.total_clients > 1 {
let normalized_received = (self.messages_received as f64) / (self.total_clients as f64);
(normalized_received / total as f64) * 100.0
} else {
(self.messages_received as f64 / total as f64) * 100.0
}
}
#[allow(dead_code)]
pub fn avg_rtt_ms(&self) -> f64 {
if self.messages_received == 0 {
0.0
} else {
self.total_rtt_ms as f64 / self.messages_received as f64
}
}
pub fn total_attempted(&self) -> u64 {
self.messages_sent + self.messages_failed
}
pub fn has_activity(&self) -> bool {
self.total_attempted() > 0 || self.connection_errors > 0
}
}