目录
- 一、配置项目依赖
-
- 方式一:命令行快速添加依赖
- 方式二:手动写入Cargo.toml
- 二、定义数据模型
- 1.项目目录注册
- [2. 系统基本信息数据模型](#2. 系统基本信息数据模型)
- 3.统一导出数据模型(可选)
- 三、实现基本信息获取
- 四、实现获取基本信息接口
一、配置项目依赖
方式一:命令行快速添加依赖
bash
cargo add sysinfo
cargo add chrono -F serde
方式二:手动写入Cargo.toml
toml
anyhow = "1.0.102"
axum = "0.8.9"
chrono = { version = "0.4.44", features = ["serde"] }
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.150"
sysinfo = "0.39.3"
tokio = { version = "1.52.3", features = ["full"] }
tower-http = { version = "0.6.11", features = ["trace"] }
二、定义数据模型
1.项目目录注册
在src目录下新建data文件夹,创建system.rs数据模型文件,同步注册至lib.rs
src/lib.rs
rust
/// http服务模块
pub mod app;
/// 数据模块
pub mod data;
src/data/mod.rs
rust
...
/// 系统信息数据模型
pub mod system;
...
2. 系统基本信息数据模型
编辑src/system.rs文件,实现系统基本信息数据模型、CPU数据模型等
rust
use serde::{Deserialize, Serialize};
/// 系统信息数据模型
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct SystemInfo {
// 系统基本信息
pub base: HostInfo,
// CPU信息
pub cpu: CpuInfo,
// 内存信息
pub mem: MemInfo,
// 磁盘信息
pub disks: Vec<DiskInfo>,
// 网络信息
pub networks: Vec<NetworkInfo>,
}
/// 系统基本信息数据模型
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct HostInfo {
// 主机名
pub host_name: String,
// 系统架构
pub arch: String,
// 发行版本
pub distro: String,
// 内核版本
pub kernel_version: String,
// 运行时间
pub up_time: String,
// 启动时间
pub boot_time: String,
}
/// CPU信息数据模型
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CpuInfo {
// CPU名称
pub name: String,
// CPU核心数
pub cores: u64,
// CPU逻辑核心数
pub logical_cores: u64,
// CPU频率
pub frequency: u64,
// CPU使用率
pub usage: f64,
// 每个逻辑CPU使用率 (%)
pub logical_usage: Vec<f64>,
}
/// 内存信息数据模型
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct MemInfo {
// 总内存
pub total: u64,
// 已使用内存
pub used: u64,
// 空闲内存
pub free: u64,
// 内存使用率 (%)
pub usage: f64,
// 交换内存
pub swap_total: u64,
// 已使用交换内存
pub swap_used: u64,
// 可用交换内存
pub swap_free: u64,
// 交换内存使用率 (%)
pub swap_usage: f64,
}
/// 磁盘信息数据模型
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct DiskInfo {
// 磁盘名称
pub name: String,
// 磁盘总容量
pub total: u64,
// 已使用容量
pub used: u64,
// 空闲容量
pub free: u64,
// 磁盘使用率 (%)
pub usage: f64,
// 总读取
pub read_all: u64,
// 总写入
pub write_all: u64,
// 挂载点
pub mount_point: String,
// 类型
pub disk_type: String,
// 读取速度
pub read_speed: u64,
// 写入速度
pub write_speed: u64,
}
/// 网络信息数据模型
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct NetworkInfo {
// 网络接口名称
pub name: String,
// 网络接口IP地址
pub ip: String,
// 网络接口MAC地址
pub mac: String,
// 下载速度
pub download_speed: u64,
// 上传速度
pub upload_speed: u64,
}
3.统一导出数据模型(可选)
编辑src/system.rs,统一导出模型,可简化导入路径
rust
/// 导出系统信息数据模型
pub use system::*;
三、实现基本信息获取
1.服务模块注册
在src目录下新建service.rs文件和serivce文件夹,并注册到lib.rs
rust
/// http服务模块
pub mod app;
/// 数据模块
pub mod data;
/// 服务模块
pub mod service;
rust
/// 基本信息模块
pub mod system;
2.系统信息服务实现
编辑src/system/system.rs文件,实现系统基本信息数据、CPU数据等
rust
use std::{env::consts::ARCH, fs::read_to_string, process::Output, thread::sleep, time::Duration, vec};
use chrono::{Local, TimeZone};
use sysinfo::{DiskUsage, Disks, Networks, System};
use tokio::{ time::Instant};
use crate::data::{CpuInfo, DiskInfo, HostInfo, MemInfo, NetworkInfo, SystemInfo};
pub trait SystemInfoService {
/// 获取CPU信息
fn cpu_info(&self) -> CpuInfo;
/// 获取内存信息
fn memory_info(&self) -> MemInfo;
/// 获取磁盘信息
fn disk_info(&self) -> Vec<DiskInfo>;
/// 获取网络信息
fn network_info(&self) -> Vec<NetworkInfo>;
/// 获取所有信息
fn all(&self) -> impl Future<Output = SystemInfo>;
/// 获取主机信息
fn host_info(&self) -> HostInfo;
}
#[derive(Debug, Clone, Copy)]
pub struct DefaultSystemInfo;
impl SystemInfoService for DefaultSystemInfo {
/// 获取CPU信息
fn cpu_info(&self) -> CpuInfo {
let mut sys = System::new_all();
sys.refresh_cpu_all();
sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
sys.refresh_cpu_all();
// 所有逻辑核心信息
let golbal_cpu = sys.cpus();
// 取第一个逻辑核心信息
let first_cpu = golbal_cpu.first().unwrap();
// CPU名称
let name = first_cpu.brand().to_string();
// 逻辑核心数
let logical_cores = golbal_cpu.len() as u64;
// CPU频率
let frequency = first_cpu.frequency() / 1000;
// 总使用率
let usage = sys.global_cpu_usage() as f64;
// 逻辑使用率
let logical_usage = golbal_cpu.iter().map(|s| s.cpu_usage() as f64).collect::<Vec<f64>>();
CpuInfo {
name,
logical_cores,
frequency,
usage,
logical_usage,
}
}
/// 获取内存信息
fn memory_info(&self) -> MemInfo {
let mut sys = System::new_all();
sys.refresh_memory();
// 总内存
let total = sys.total_memory();
// 已用内存
let used = sys.used_memory();
// 空闲内存
let free = sys.free_memory();
// 内存使用率
let usage = if total > 0 {
(used as f64 / total as f64) * 100.0
} else {
0.0
};
// 交换区总大小
let swap_total = sys.total_swap();
// 交换区已用大小
let swap_used = sys.used_swap();
// 交换区空闲大小
let swap_free = sys.free_swap();
// 交换区使用率
let swap_usage = if swap_total > 0 {
(swap_used as f64 / swap_total as f64) * 100.00
} else {
0.000
};
MemInfo {
total,
used,
free,
usage,
swap_total,
swap_used,
swap_free,
swap_usage,
}
}
/// 获取磁盘信息
fn disk_info(&self) -> Vec<DiskInfo> {
let disks_first = Disks::new_with_refreshed_list();
let start_time = Instant::now();
// 收集初始数据
let start_data = disks_first.list().iter().map(|d| {
(d.name().to_string_lossy().to_string(), d.usage())
}).collect::<Vec<(String, DiskUsage)>>();
sleep(Duration::from_secs(1));
// 刷新磁盘数据
let disks_now = Disks::new_with_refreshed_list();
// 计算耗时
let dur_ms =start_time.elapsed().as_millis() as u64;
// 收集当前数据
let mut res = Vec::new();
for disk in disks_now.list() {
// 获取磁盘名称、总空间、可用空间、使用空间、使用率、挂载点和文件系统类型
let name = disk.name().to_string_lossy().to_string();
let total = disk.total_space();
let free = disk.available_space();
let used = total.saturating_sub(free);
let usage = if total > 0 {used as f64 / total as f64 * 100.0} else {0.0};
let mount_point = disk.mount_point().to_string_lossy().to_string();
let disk_type = disk.file_system().to_string_lossy().to_string();
// 获取当前磁盘IO信息
let curr_io = disk.usage();
// 获取上一次磁盘IO信息
let pre = start_data.iter().find(|(n, _)| n == &name).map(|(_, u)| u).copied().unwrap_or(DiskUsage { total_written_bytes: 0, written_bytes: 0, total_read_bytes: 0, read_bytes: 0 });
// 计算磁盘IO速度
let read_all = curr_io.total_read_bytes;
let write_all = curr_io.total_written_bytes;
let delta_read = curr_io.read_bytes.saturating_sub(pre.read_bytes);
let delta_write = curr_io.written_bytes.saturating_sub(pre.written_bytes);
let read_speed = if dur_ms > 0 {delta_read * 1000 / dur_ms} else {0};
let write_speed = if dur_ms > 0 {delta_write * 1000 / dur_ms} else {0};
res.push(DiskInfo {
name,
total,
free,
used,
usage,
read_speed,
write_speed,
read_all,
write_all,
mount_point,
disk_type,
});
}
res
}
/// 获取网络信息
fn network_info(&self) -> Vec<NetworkInfo> {
// 获取当前网络信息
let net1 = Networks::new_with_refreshed_list();
// 获取网络信息
let prev = net1.list().iter()
.map(|(k, v)|(k.clone(), v.total_received(), v.total_transmitted()))
.collect::<Vec<(String, u64,u64)>>();
// 等待1秒
sleep(Duration::from_secs(1));
// 再次获取网络信息
let net2 = Networks::new_with_refreshed_list();
// 初始化网络信息
let mut list: Vec<NetworkInfo> = vec![];
for (name, data) in net2.list() {
// 获取上一次网络信息
let (pre_down, pre_up) = prev.iter().find(|(n, _, _)| n == name)
.map(|(_,d, u)|(*d, *u)).unwrap_or((0,0));
// 计算网络信息变化
let down = data.total_received().saturating_sub(pre_down);
let up = data.total_transmitted().saturating_sub(pre_up);
// 保存网络信息
list.push(NetworkInfo{
name: name.to_string(),
ip: data.ip_networks().first().map(|x|x.to_string()).unwrap_or_default(),
mac: data.mac_address().to_string(),
download_speed: down,
upload_speed: up,
});
}
list
}
/// 获取所有系统信息
async fn all(&self) -> SystemInfo {
let s = self.clone();
let host = tokio::task::spawn_blocking({
move || s.host_info()
});
let cpu = tokio::task::spawn_blocking({
move || s.cpu_info()
});
let mem = tokio::task::spawn_blocking({
move || s.memory_info()
});
let disk = tokio::task::spawn_blocking({
move || s.disk_info()
});
let net = tokio::task::spawn_blocking({
move || s.network_info()
});
// 等待全部完成(只等最慢的那个 ~1s)
let (host, cpu, mem, disk, net) = tokio::join!(host, cpu, mem, disk, net);
SystemInfo {
base: host.unwrap_or_default(),
cpu: cpu.unwrap_or_default(),
mem: mem.unwrap_or_default(),
disks: disk.unwrap_or_default(),
networks: net.unwrap_or_default(),
}
}
/// 获取系统基本信息
fn host_info(&self) -> HostInfo {
// 获取主机名、架构和发行版信息
let host_name = System::host_name().unwrap_or_default();
let arch = System::cpu_arch();
let distro = cfg_select! {
unix => read_to_string("/etc/os-release")
.ok()
.and_then(|txt| {
txt.lines()
.find_map(|line| {
line.strip_prefix(r#"PRETTY_NAME=""#).and_then(
|s| s.strip_suffix('"')
).map(|s| s.to_string())
})
})
.unwrap_or_else(|| {
System::long_os_version().unwrap_or_default()
})
,
_ => System::long_os_version().unwrap_or_default(),
};
// 获取内核版本、启动时间、运行时间
let kernel_version = System::kernel_version().unwrap_or_default();
let up_time =(|s: i64| {
let dur = chrono::Duration::seconds(s);
let days = dur.num_days();
let hour = dur.num_hours() % 24;
let min = dur.num_minutes() % 60;
let sec = dur.num_seconds() % 60;
match (days >0, hour > 0, min > 0) {
(true, true ,true) => format!("{}天{:02}时{:02}分{:02}秒", days, hour, min, sec),
(false, true, true) => format!("{:02}时{:02}分{:02}秒", hour,min, sec),
(false, false, true) => format!("{:02}分{:02}秒", min, sec),
(false, false, false) => format!("{:02}秒", sec),
_ => format!("{}天{:02}时{:02}分{:02}秒", days, hour, min, sec),
}
})(System::uptime() as i64);
let boot_time = (|s: i64| {
Local.timestamp_opt(s, 0).unwrap().format("%Y-%m-%d %H:%M:%S").to_string()
})(System::boot_time() as i64);
HostInfo {
host_name,
arch,
distro,
kernel_version,
up_time,
boot_time,
}
}
}
四、实现获取基本信息接口
1.接口模块注册
在src目录下新建api.rs文件和api文件夹,并注册到lib.rs
rust
/// http服务模块
pub mod app;
/// 数据模块
pub mod data;
/// 服务模块
pub mod service;
/// 接口模块
pub mod api;
rust
/// 系统基本信息
pub mod system;
2.接口路由实现
编辑src/api/system.rs文件,实现所有相关接口
rust
use axum::{Json, Router, routing::get};
use crate::{data::{CpuInfo, DiskInfo, HostInfo, NetworkInfo, Resp, SystemInfo}, service::system::{DefaultSystemService, SystemInfoService}};
/// 注册路由
pub fn register_system_url() -> Router {
Router::new()
.route("/all", get(get_all))
.route("/host", get(get_host))
.route("/cpu", get(get_cpu))
.route("/base", get(get_base))
.route("/net", get(get_net))
.route("/disk", get(get_disk))
}
/// 获取所有系统信息
async fn get_all() -> Json<Resp<SystemInfo>> {
let serv = DefaultSystemService::default();
Json(Resp::ok(Some(serv.all().await)))
}
/// 获取主机信息
async fn get_host() -> Json<Resp<HostInfo>> {
let serv = DefaultSystemService::default();
Json(Resp::ok(Some(serv.host_info())))
}
/// 获取CPU信息
async fn get_cpu() -> Json<Resp<CpuInfo>> {
let serv = DefaultSystemService::default();
Json(Resp::ok(Some(serv.cpu_info())))
}
/// 获取基础信息
async fn get_base() -> Json<Resp<HostInfo>> {
let serv = DefaultSystemService::default();
Json(Resp::ok(Some(serv.host_info())))
}
/// 获取网络信息
async fn get_net() -> Json<Resp<Vec<NetworkInfo>>> {
let serv = DefaultSystemService::default();
Json(Resp::ok(Some(serv.network_info())))
}
/// 获取磁盘信息
async fn get_disk() -> Json<Resp<Vec<DiskInfo>>> {
let serv = DefaultSystemService::default();
Json(Resp::ok(Some(serv.disk_info())))
}