feat(monitor): 顶部栏增加磁盘占用,格式与内存一致
采集根分区(/)容量,按 DISK x% · x/x GB · Free x GB 拼入展示文本, Stats 新增 disk_used_pct / disk_total_bytes / disk_available_bytes 字段。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
f576b03315
commit
a3075133d1
@ -6,7 +6,7 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use serde::Serialize;
|
||||
use sysinfo::System;
|
||||
use sysinfo::{Disks, System};
|
||||
use tokio::time::sleep;
|
||||
|
||||
use crate::state::AppState;
|
||||
@ -26,6 +26,12 @@ pub struct Stats {
|
||||
pub mem_total_bytes: u64,
|
||||
/// 可用内存(字节)
|
||||
pub mem_available_bytes: u64,
|
||||
/// 磁盘使用率(百分比,0–100)
|
||||
pub disk_used_pct: f32,
|
||||
/// 磁盘总量(字节)
|
||||
pub disk_total_bytes: u64,
|
||||
/// 可用磁盘(字节)
|
||||
pub disk_available_bytes: u64,
|
||||
}
|
||||
|
||||
impl Default for Stats {
|
||||
@ -36,6 +42,9 @@ impl Default for Stats {
|
||||
mem_used_pct: 0.0,
|
||||
mem_total_bytes: 0,
|
||||
mem_available_bytes: 0,
|
||||
disk_used_pct: 0.0,
|
||||
disk_total_bytes: 0,
|
||||
disk_available_bytes: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -44,9 +53,22 @@ fn bytes_to_gb(bytes: u64) -> f64 {
|
||||
bytes as f64 / 1024.0 / 1024.0 / 1024.0
|
||||
}
|
||||
|
||||
/// 选出要展示的磁盘容量:优先根分区 `/`(Linux 线上环境),否则取容量最大的那块
|
||||
/// (兜底 Windows/本地等无 `/` 的情况)。返回 `(总字节, 可用字节)`;无磁盘时 `(0, 0)`。
|
||||
fn root_disk(disks: &Disks) -> (u64, u64) {
|
||||
let chosen = disks
|
||||
.iter()
|
||||
.find(|d| d.mount_point() == std::path::Path::new("/"))
|
||||
.or_else(|| disks.iter().max_by_key(|d| d.total_space()));
|
||||
match chosen {
|
||||
Some(d) => (d.total_space(), d.available_space()),
|
||||
None => (0, 0),
|
||||
}
|
||||
}
|
||||
|
||||
impl Stats {
|
||||
/// 从已刷新的 `System` 读出指标并格式化。
|
||||
fn from_system(sys: &System) -> Self {
|
||||
/// 从已刷新的 `System` + `Disks` 读出指标并格式化。
|
||||
fn from_system(sys: &System, disks: &Disks) -> Self {
|
||||
let cpu = sys.global_cpu_usage();
|
||||
let total = sys.total_memory();
|
||||
let available = sys.available_memory();
|
||||
@ -57,13 +79,25 @@ impl Stats {
|
||||
0.0
|
||||
};
|
||||
|
||||
let (disk_total, disk_available) = root_disk(disks);
|
||||
let disk_used = disk_total.saturating_sub(disk_available);
|
||||
let disk_used_pct = if disk_total > 0 {
|
||||
disk_used as f32 / disk_total as f32 * 100.0
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
let text = format!(
|
||||
"CPU {:.1}% · MEM {:.1}% · {:.1}/{:.1} GB · Free {:.1} GB",
|
||||
"CPU {:.1}% · MEM {:.1}% · {:.1}/{:.1} GB · Free {:.1} GB · DISK {:.1}% · {:.1}/{:.1} GB · Free {:.1} GB",
|
||||
cpu,
|
||||
mem_used_pct,
|
||||
bytes_to_gb(used),
|
||||
bytes_to_gb(total),
|
||||
bytes_to_gb(available),
|
||||
disk_used_pct,
|
||||
bytes_to_gb(disk_used),
|
||||
bytes_to_gb(disk_total),
|
||||
bytes_to_gb(disk_available),
|
||||
);
|
||||
|
||||
Self {
|
||||
@ -72,6 +106,9 @@ impl Stats {
|
||||
mem_used_pct,
|
||||
mem_total_bytes: total,
|
||||
mem_available_bytes: available,
|
||||
disk_used_pct,
|
||||
disk_total_bytes: disk_total,
|
||||
disk_available_bytes: disk_available,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -82,6 +119,8 @@ impl Stats {
|
||||
/// `MINIMUM_CPU_UPDATE_INTERVAL`),之后循环里的读数才准确。
|
||||
pub async fn run_sampler(state: AppState) {
|
||||
let mut sys = System::new();
|
||||
// 磁盘容量变化很慢,但每轮 refresh 一下也很廉价,省得单独计时。
|
||||
let mut disks = Disks::new_with_refreshed_list();
|
||||
|
||||
sys.refresh_cpu_usage();
|
||||
sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL).await;
|
||||
@ -89,8 +128,9 @@ pub async fn run_sampler(state: AppState) {
|
||||
loop {
|
||||
sys.refresh_cpu_usage();
|
||||
sys.refresh_memory();
|
||||
disks.refresh(true);
|
||||
|
||||
let stats = Stats::from_system(&sys);
|
||||
let stats = Stats::from_system(&sys, &disks);
|
||||
*state.snapshot.write().await = stats;
|
||||
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user