added plattform specific cputemp and network load detection
This commit is contained in:
@@ -323,17 +323,62 @@ impl MetricsCollector {
|
|||||||
|
|
||||||
// Disk
|
// Disk
|
||||||
let disk = self.sys.disks().first();
|
let disk = self.sys.disks().first();
|
||||||
let (disk_size, disk_used) = if let Some(d) = disk {
|
// In collect_metrics():
|
||||||
let total = d.total_space();
|
let (disk_size, disk_usage, disk_temp) = {
|
||||||
let available = d.available_space();
|
let mut total_size = 0u64;
|
||||||
(
|
let mut total_used = 0u64;
|
||||||
(total as f64) / 1024.0 / 1024.0 / 1024.0, // Convert to GB
|
let mut temp = 0.0;
|
||||||
(total - available) as f64 / total as f64 * 100.0,
|
let mut count = 0;
|
||||||
)
|
|
||||||
|
for disk in self.sys.disks() {
|
||||||
|
total_size += disk.total_space();
|
||||||
|
total_used += disk.total_space() - disk.available_space();
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disk temperature (Linux only)
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
if let Ok(dir) = fs::read_dir("/sys/block") {
|
||||||
|
for entry in dir.flatten() {
|
||||||
|
if let Some(disk_name) = entry.file_name().to_str() {
|
||||||
|
if disk_name.starts_with("sd") || disk_name.starts_with("nvme") {
|
||||||
|
let temp_path = format!(
|
||||||
|
"/sys/block/{}/device/hwmon/hwmon*/temp1_input",
|
||||||
|
disk_name
|
||||||
|
);
|
||||||
|
if let Ok(paths) = glob::glob(&temp_path) {
|
||||||
|
for path in paths.flatten() {
|
||||||
|
if let Ok(content) = fs::read_to_string(path) {
|
||||||
|
if let Ok(t) = content.trim().parse::<f32>() {
|
||||||
|
temp += t / 1000.0; // Convert millidegrees
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let size_gb = if count > 0 {
|
||||||
|
(total_size as f64) / 1024.0 / 1024.0 / 1024.0
|
||||||
} else {
|
} else {
|
||||||
(0.0, 0.0)
|
0.0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let usage = if total_size > 0 {
|
||||||
|
(total_used as f64 / total_size as f64) * 100.0
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
|
||||||
|
let avg_temp = if count > 0 { temp / count as f64 } else { 0.0 };
|
||||||
|
|
||||||
|
(size_gb, usage, avg_temp)
|
||||||
|
};
|
||||||
// GPU (NVIDIA)
|
// GPU (NVIDIA)
|
||||||
let (gpu_temp, gpu_load, vram_used, vram_total) = if let Some(nvml) = &self.nvml {
|
let (gpu_temp, gpu_load, vram_used, vram_total) = if let Some(nvml) = &self.nvml {
|
||||||
if let Ok(device) = nvml.device_by_index(0) {
|
if let Ok(device) = nvml.device_by_index(0) {
|
||||||
@@ -381,7 +426,7 @@ impl MetricsCollector {
|
|||||||
ram_load,
|
ram_load,
|
||||||
ram_size,
|
ram_size,
|
||||||
disk_size,
|
disk_size,
|
||||||
disk_usage: disk_used,
|
disk_usage: disk_usage,
|
||||||
disk_temp: 0.0, // not supported
|
disk_temp: 0.0, // not supported
|
||||||
net_in: net_in_bits,
|
net_in: net_in_bits,
|
||||||
net_out: net_out_bits,
|
net_out: net_out_bits,
|
||||||
@@ -390,41 +435,105 @@ impl MetricsCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_cpu_temp() -> Option<f32> {
|
fn get_cpu_temp() -> Option<f32> {
|
||||||
let output = Command::new("sensors").output().ok()?;
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
// Linux: sensors command or sysfs
|
||||||
|
if let Ok(output) = Command::new("sensors").output() {
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
for line in stdout.lines() {
|
for line in stdout.lines() {
|
||||||
if line.to_lowercase().contains("package id") || line.to_lowercase().contains("cpu temp") {
|
if line.to_lowercase().contains("package id")
|
||||||
|
|| line.to_lowercase().contains("cpu temp")
|
||||||
|
{
|
||||||
if let Some(temp_str) = line.split_whitespace().find(|s| s.contains("°C")) {
|
if let Some(temp_str) = line.split_whitespace().find(|s| s.contains("°C")) {
|
||||||
let number: String = temp_str
|
let number: String = temp_str
|
||||||
.chars()
|
.chars()
|
||||||
.filter(|c| c.is_digit(10) || *c == '.')
|
.filter(|c| c.is_ascii_digit() || *c == '.')
|
||||||
.collect();
|
.collect();
|
||||||
return number.parse::<f32>().ok();
|
return number.parse::<f32>().ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to sysfs (common path for Intel/AMD)
|
||||||
|
if let Ok(content) = fs::read_to_string("/sys/class/thermal/thermal_zone0/temp") {
|
||||||
|
if let Ok(temp) = content.trim().parse::<f32>() {
|
||||||
|
return Some(temp / 1000.0); // Convert millidegrees to degrees
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
// Windows: WMI query
|
||||||
|
let output = Command::new("wmic")
|
||||||
|
.args(&["cpu", "get", "Temperature", "/Value"])
|
||||||
|
.output()
|
||||||
|
.ok()?;
|
||||||
|
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
for line in stdout.lines() {
|
||||||
|
if line.starts_with("Temperature=") {
|
||||||
|
if let Ok(temp) = line.replace("Temperature=", "").trim().parse::<f32>() {
|
||||||
|
return Some(temp); // Returns in Celsius
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_network_traffic() -> Option<(u64, u64)> {
|
fn get_network_traffic() -> Option<(u64, u64)> {
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
let content = fs::read_to_string("/proc/net/dev").ok()?;
|
let content = fs::read_to_string("/proc/net/dev").ok()?;
|
||||||
let mut rx_total = 0u64;
|
let mut rx_total = 0u64;
|
||||||
let mut tx_total = 0u64;
|
let mut tx_total = 0u64;
|
||||||
|
|
||||||
for line in content.lines().skip(2) {
|
for line in content.lines().skip(2) {
|
||||||
let parts: Vec<&str> = line.split_whitespace().collect();
|
let parts: Vec<&str> = line.split_whitespace().collect();
|
||||||
if parts.len() < 17 {
|
if parts.len() < 10 || parts[0].ends_with(":") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if parts[0].contains("lo:") {
|
if parts[0].contains("lo:") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
rx_total += parts[1].parse::<u64>().ok()?;
|
rx_total += parts[1].parse::<u64>().unwrap_or(0);
|
||||||
tx_total += parts[9].parse::<u64>().ok()?;
|
tx_total += parts[9].parse::<u64>().unwrap_or(0);
|
||||||
}
|
}
|
||||||
Some((rx_total, tx_total))
|
Some((rx_total, tx_total))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
use std::process::Stdio;
|
||||||
|
let output = Command::new("netstat")
|
||||||
|
.args(&["-e"])
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.output()
|
||||||
|
.ok()?;
|
||||||
|
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let mut lines = stdout.lines();
|
||||||
|
|
||||||
|
// Find the line with statistics
|
||||||
|
while let Some(line) = lines.next() {
|
||||||
|
if line.contains("Bytes") {
|
||||||
|
if let Some(stats_line) = lines.next() {
|
||||||
|
let parts: Vec<&str> = stats_line.split_whitespace().collect();
|
||||||
|
if parts.len() >= 2 {
|
||||||
|
let rx = parts[0].parse::<u64>().unwrap_or(0);
|
||||||
|
let tx = parts[1].parse::<u64>().unwrap_or(0);
|
||||||
|
return Some((rx, tx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn Error>> {
|
async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let server_base_url = "http://localhost:5000";
|
let server_base_url = "http://localhost:5000";
|
||||||
|
Reference in New Issue
Block a user