use crate::topics::*;
use crate::types::*;
use anyhow::Result;
use mecha10_core::prelude::*;
use mecha10_core::topics::Topic;
use std::sync::Mutex;
use sysinfo::{Disks, Networks, System};
pub struct SystemCollector {
source: String,
system: Mutex<System>,
}
impl SystemCollector {
pub fn new(source: impl Into<String>) -> Self {
Self {
source: source.into(),
system: Mutex::new(System::new_all()),
}
}
pub async fn collect_metrics(&self, ctx: &Context) -> Result<()> {
let metrics = {
let mut sys = self.system.lock().unwrap();
sys.refresh_all();
sys.refresh_cpu_usage();
let cpus = sys.cpus();
let cpu_per_core: Vec<f64> = cpus.iter().map(|cpu| cpu.cpu_usage() as f64).collect();
let cpu_percent = if !cpu_per_core.is_empty() {
cpu_per_core.iter().sum::<f64>() / cpu_per_core.len() as f64
} else {
0.0
};
let memory_total_bytes = sys.total_memory();
let memory_used_bytes = sys.used_memory();
let memory_percent = if memory_total_bytes > 0 {
(memory_used_bytes as f64 / memory_total_bytes as f64) * 100.0
} else {
0.0
};
let disks = Disks::new_with_refreshed_list();
let (disk_total_bytes, disk_used_bytes, disk_percent) = disks
.first()
.map(|disk| {
let total = disk.total_space();
let available = disk.available_space();
let used = total.saturating_sub(available);
let percent = if total > 0 {
(used as f64 / total as f64) * 100.0
} else {
0.0
};
(total, used, percent)
})
.unwrap_or((0, 0, 0.0));
let networks = Networks::new_with_refreshed_list();
let (network_rx_bytes, network_tx_bytes) = networks.iter().fold((0u64, 0u64), |(rx, tx), (_name, data)| {
(rx + data.total_received(), tx + data.total_transmitted())
});
let network_rx_bytes_per_sec = network_rx_bytes;
let network_tx_bytes_per_sec = network_tx_bytes;
SystemResourceMetrics {
cpu_percent,
cpu_per_core,
memory_total_bytes,
memory_used_bytes,
memory_percent,
disk_total_bytes,
disk_used_bytes,
disk_percent,
network_rx_bytes_per_sec,
network_tx_bytes_per_sec,
}
};
let msg = DiagnosticMessage::new(&self.source, metrics);
ctx.publish_to(
Topic::<DiagnosticMessage<SystemResourceMetrics>>::new(TOPIC_DIAGNOSTICS_SYSTEM_RESOURCES),
&msg,
)
.await?;
Ok(())
}
}