use super::error::Result;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use tokio::sync::Mutex;
use tokio::time;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum MetricType {
CpuUsage,
MemoryUsage,
DiskIO,
NetworkIO,
RequestLatency,
RequestThroughput,
ErrorRate,
Custom(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Metric {
pub metric_type: MetricType,
pub value: f64,
pub timestamp: Duration,
pub labels: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceSnapshot {
pub timestamp: Duration,
pub cpu_usage: f64,
pub memory_usage: u64,
pub disk_io: f64,
pub network_io: u64,
pub request_latency: f64,
pub request_throughput: f64,
pub error_rate: f64,
}
pub struct DataCollector {
interval: Duration,
latest_metrics: Arc<Mutex<Vec<Metric>>>,
history: Arc<Mutex<Vec<PerformanceSnapshot>>>,
}
impl DataCollector {
pub fn new(interval: Duration) -> Self {
Self {
interval,
latest_metrics: Arc::new(Mutex::new(Vec::new())),
history: Arc::new(Mutex::new(Vec::new())),
}
}
pub async fn start(&self) -> Result<()> {
let interval: _ = self.interval;
let latest_metrics: _ = self.latest_metrics.clone();
let history: _ = self.history.clone();
tokio::spawn(async move {
let mut interval_timer = time::interval(interval);
loop {
interval_timer.tick().await;
let snapshot: _ = Self::collect_system_metrics().await;
{
let mut metrics = latest_metrics.lock().await;
metrics.clear();
metrics.extend(Self::metrics_from_snapshot(&snapshot));
}
{
let mut hist = history.lock().await;
hist.push(snapshot);
if hist.len() > 1000 {
hist.remove(0);
}
}
}
});
Ok(())
}
pub async fn get_latest_metrics(&self) -> Vec<Metric> {
let metrics: _ = self.latest_metrics.lock().await;
metrics.clone()
}
pub async fn get_history(&self, count: usize) -> Vec<PerformanceSnapshot> {
let hist: _ = self.history.lock().await;
let len: _ = hist.len();
let start: _ = if len > count { len - count } else { 0 };
hist[start..].to_vec()
}
async fn collect_system_metrics() -> PerformanceSnapshot {
let now: _ = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default();
PerformanceSnapshot {
timestamp: now,
cpu_usage: 0.0, memory_usage: 0, disk_io: 0.0, network_io: 0, request_latency: 0.0, request_throughput: 0.0, error_rate: 0.0, }
}
fn metrics_from_snapshot(snapshot: &PerformanceSnapshot) -> Vec<Metric> {
let timestamp: _ = snapshot.timestamp;
let labels: _ = HashMap::new();
vec![
Metric {
metric_type: MetricType::CpuUsage,
value: snapshot.cpu_usage,
timestamp,
labels: labels.clone(),
},
Metric {
metric_type: MetricType::MemoryUsage,
value: snapshot.memory_usage as f64,
timestamp,
labels: labels.clone(),
},
Metric {
metric_type: MetricType::DiskIO,
value: snapshot.disk_io,
timestamp,
labels: labels.clone(),
},
Metric {
metric_type: MetricType::NetworkIO,
value: snapshot.network_io as f64,
timestamp,
labels: labels.clone(),
},
Metric {
metric_type: MetricType::RequestLatency,
value: snapshot.request_latency,
timestamp,
labels: labels.clone(),
},
Metric {
metric_type: MetricType::RequestThroughput,
value: snapshot.request_throughput,
timestamp,
labels: labels.clone(),
},
Metric {
metric_type: MetricType::ErrorRate,
value: snapshot.error_rate,
timestamp,
labels,
},
]
}
}
impl Default for DataCollector {
fn default() -> Self {
Self::new(Duration::from_secs(5))
}
}