fix(system-monitor): 改进进程CPU使用率计算准确性和稳定性
- 优先使用Node.js内置的process.cpuUsage()计算当前进程CPU使用率,提高跨平台准确性 - 为外部进程ps命令添加错误处理,避免在BusyBox环境下报错干扰日志 - 更新Dockerfile安装procps工具以支持系统监控功能 - 同步更新版本号至2.11.1
This commit is contained in:
parent
f2f02b365f
commit
7d2704b14e
3 changed files with 40 additions and 11 deletions
|
|
@ -19,8 +19,8 @@ FROM node:20-alpine
|
||||||
LABEL maintainer="AIClient2API Team"
|
LABEL maintainer="AIClient2API Team"
|
||||||
LABEL description="Docker image for AIClient2API server"
|
LABEL description="Docker image for AIClient2API server"
|
||||||
|
|
||||||
# 安装必要的系统工具(tar 用于更新功能,git 用于版本检查)
|
# 安装必要的系统工具(tar 用于更新功能,git 用于版本检查,procps 用于系统监控)
|
||||||
RUN apk add --no-cache tar git
|
RUN apk add --no-cache tar git procps
|
||||||
|
|
||||||
# 设置工作目录
|
# 设置工作目录
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
|
||||||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
2.11.0
|
2.11.1
|
||||||
|
|
|
||||||
|
|
@ -57,8 +57,31 @@ export function getProcessCpuUsagePercent(pid) {
|
||||||
const isWindows = process.platform === 'win32';
|
const isWindows = process.platform === 'win32';
|
||||||
let cpuPercent = 0;
|
let cpuPercent = 0;
|
||||||
|
|
||||||
if (isWindows) {
|
// 优先处理当前进程,使用 Node.js 内置的 process.cpuUsage(),这在所有平台上都更准确且无需外部命令
|
||||||
// Windows 下使用 PowerShell 获取进程的 CPU 使用率
|
if (pid === process.pid) {
|
||||||
|
const usage = process.cpuUsage();
|
||||||
|
const timestamp = Date.now();
|
||||||
|
const totalMicroseconds = usage.user + usage.system;
|
||||||
|
const prevInfo = processCpuInfoMap.get(pid);
|
||||||
|
|
||||||
|
if (prevInfo && prevInfo.totalMicroseconds !== undefined) {
|
||||||
|
const timeDiff = (timestamp - prevInfo.timestamp) * 1000; // 转换为微秒
|
||||||
|
const processTimeDiff = totalMicroseconds - prevInfo.totalMicroseconds;
|
||||||
|
|
||||||
|
if (timeDiff > 0) {
|
||||||
|
const cpuCount = os.cpus().length;
|
||||||
|
cpuPercent = (processTimeDiff / timeDiff) * 100;
|
||||||
|
// Node.js 返回的是所有核心累加的使用量,归一化到 0-100%
|
||||||
|
cpuPercent = cpuPercent / cpuCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processCpuInfoMap.set(pid, {
|
||||||
|
totalMicroseconds,
|
||||||
|
timestamp
|
||||||
|
});
|
||||||
|
} else if (isWindows) {
|
||||||
|
// Windows 下使用 PowerShell 获取其他进程的 CPU 使用率
|
||||||
// CPU = (Process.TotalProcessorTime / ElapsedTime) / ProcessorCount
|
// CPU = (Process.TotalProcessorTime / ElapsedTime) / ProcessorCount
|
||||||
const command = `powershell -Command "Get-Process -Id ${pid} | Select-Object -ExpandProperty TotalProcessorTime | ForEach-Object { $_.TotalSeconds }"`;
|
const command = `powershell -Command "Get-Process -Id ${pid} | Select-Object -ExpandProperty TotalProcessorTime | ForEach-Object { $_.TotalSeconds }"`;
|
||||||
const output = execSync(command, { encoding: 'utf8' }).trim();
|
const output = execSync(command, { encoding: 'utf8' }).trim();
|
||||||
|
|
@ -67,7 +90,7 @@ export function getProcessCpuUsagePercent(pid) {
|
||||||
|
|
||||||
if (!isNaN(totalProcessorSeconds)) {
|
if (!isNaN(totalProcessorSeconds)) {
|
||||||
const prevInfo = processCpuInfoMap.get(pid);
|
const prevInfo = processCpuInfoMap.get(pid);
|
||||||
if (prevInfo) {
|
if (prevInfo && prevInfo.totalProcessorSeconds !== undefined) {
|
||||||
const timeDiff = (timestamp - prevInfo.timestamp) / 1000; // 转换为秒
|
const timeDiff = (timestamp - prevInfo.timestamp) / 1000; // 转换为秒
|
||||||
const processTimeDiff = totalProcessorSeconds - prevInfo.totalProcessorSeconds;
|
const processTimeDiff = totalProcessorSeconds - prevInfo.totalProcessorSeconds;
|
||||||
|
|
||||||
|
|
@ -85,11 +108,17 @@ export function getProcessCpuUsagePercent(pid) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Linux/macOS 使用 ps 命令直接获取
|
// Linux/macOS 使用 ps 命令获取其他进程的 CPU 使用率
|
||||||
const output = execSync(`ps -p ${pid} -o %cpu`, { encoding: 'utf8' });
|
// 增加 2> /dev/null 以防在 BusyBox 等环境下报错干扰日志
|
||||||
const lines = output.trim().split('\n');
|
try {
|
||||||
if (lines.length >= 2) {
|
const output = execSync(`ps -p ${pid} -o %cpu 2>/dev/null`, { encoding: 'utf8' });
|
||||||
cpuPercent = parseFloat(lines[1].trim());
|
const lines = output.trim().split('\n');
|
||||||
|
if (lines.length >= 2) {
|
||||||
|
cpuPercent = parseFloat(lines[1].trim());
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 如果 ps -p 失败,尝试更通用的 ps 方式或直接忽略
|
||||||
|
cpuPercent = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue