use std::time::{Duration, Instant};
#[derive(Debug)]
pub struct QueueMetrics {
pub depth: usize,
pub peak_depth: usize,
pub total_messages: u64,
pub messages_per_second: f64,
pub last_update: Instant,
}
impl Default for QueueMetrics {
fn default() -> Self {
Self {
depth: 0,
peak_depth: 0,
total_messages: 0,
messages_per_second: 0.0,
last_update: Instant::now(),
}
}
}
#[derive(Debug, Default)]
pub struct LatencyMetrics {
pub avg_latency: Duration,
pub peak_latency: Duration,
latency_samples: Vec<Duration>,
}
#[derive(Debug)]
pub struct ThroughputMetrics {
pub messages_per_second: f64,
pub bytes_per_second: f64,
pub peak_messages_per_second: f64,
pub total_bytes: u64,
pub last_update: Instant,
}
impl Default for ThroughputMetrics {
fn default() -> Self {
Self {
messages_per_second: 0.0,
bytes_per_second: 0.0,
peak_messages_per_second: 0.0,
total_bytes: 0,
last_update: Instant::now(),
}
}
}
#[derive(Debug, Default)]
pub struct NetworkMetrics {
pub connections: usize,
pub connection_failures: u64,
pub cache_hit_ratio: f64,
pub route_cache_hits: u64,
pub avg_latency: Duration,
}
impl QueueMetrics {
pub fn record_message(&mut self) {
self.total_messages += 1;
self.depth = self.depth.saturating_add(1);
self.peak_depth = self.peak_depth.max(self.depth);
let elapsed = self.last_update.elapsed();
if elapsed >= Duration::from_secs(1) {
self.messages_per_second = self.total_messages as f64 / elapsed.as_secs_f64();
self.last_update = Instant::now();
}
}
pub fn record_completion(&mut self) {
self.depth = self.depth.saturating_sub(1);
}
}
impl LatencyMetrics {
pub fn record_latency(&mut self, latency: Duration) {
self.avg_latency = if self.latency_samples.is_empty() {
latency
} else {
Duration::from_nanos(
((self.avg_latency.as_nanos() as f64 * self.latency_samples.len() as f64)
+ latency.as_nanos() as f64) as u64
/ (self.latency_samples.len() + 1) as f64 as u64,
)
};
self.peak_latency = self.peak_latency.max(latency);
if self.latency_samples.len() >= 100 {
self.latency_samples.remove(0);
}
self.latency_samples.push(latency);
}
pub fn get_percentile(&self, percentile: f64) -> Duration {
if self.latency_samples.is_empty() {
return Duration::default();
}
let mut samples = self.latency_samples.clone();
samples.sort();
let index =
((samples.len() as f64 * percentile / 100.0).round() as usize).min(samples.len() - 1);
samples[index]
}
}
impl ThroughputMetrics {
pub fn record_throughput(&mut self, bytes: u64) {
self.total_bytes += bytes;
let elapsed = self.last_update.elapsed();
if elapsed >= Duration::from_secs(1) {
let seconds = elapsed.as_secs_f64();
self.messages_per_second = self.total_bytes as f64 / seconds;
self.bytes_per_second = self.total_bytes as f64 / seconds;
self.peak_messages_per_second =
self.peak_messages_per_second.max(self.messages_per_second);
self.last_update = Instant::now();
}
}
}
impl NetworkMetrics {
pub fn record_connection(&mut self, success: bool) {
if success {
self.connections += 1;
} else {
self.connection_failures += 1;
}
}
pub fn record_cache_hit(&mut self) {
self.route_cache_hits += 1;
self.cache_hit_ratio = self.route_cache_hits as f64
/ (self.route_cache_hits + self.connection_failures) as f64;
}
pub fn record_latency(&mut self, latency: Duration) {
self.avg_latency = if self.avg_latency.is_zero() {
latency
} else {
(self.avg_latency + latency) / 2
};
}
pub fn get_summary(&self) -> NetworkMetricsSummary {
NetworkMetricsSummary {
active_connections: self.connections,
connection_failures: self.connection_failures,
cache_hit_ratio: self.cache_hit_ratio,
avg_latency_ms: self.avg_latency.as_millis() as f64,
}
}
}
#[derive(Debug, Clone)]
pub struct NetworkMetricsSummary {
pub active_connections: usize,
pub connection_failures: u64,
pub cache_hit_ratio: f64,
pub avg_latency_ms: f64,
}