TDevOpsCICD / build-kit (push) Successful in 6m11s
- tcpc 支持 hex/文本发送、--headlen 大端长度头自动填充与收包校验、超时控制 refactor(killport): 支持 --dry 模式,Linux 下通过 docker-proxy 定位容器内真实进程(拆分至 linux/portpid.js)
80 lines
2.4 KiB
JavaScript
80 lines
2.4 KiB
JavaScript
/**
|
||
* 进程监控指标采集(仅支持 Linux)
|
||
* - CPU 占用率:两次采样 /proc/<pid>/stat 与 /proc/stat 差值计算,内部休眠约 1 秒
|
||
* - 内存占用:/proc/<pid>/status 的 VmRSS,单位 MB
|
||
* - 句柄数:/proc/<pid>/fd 目录条目数
|
||
* - 端口 -> pid:端口解析逻辑见 ../linux/portpid.js(含 docker 端口发布)
|
||
*/
|
||
const fs = require("fs");
|
||
const portpid = require("../linux/portpid");
|
||
const os = require("os");
|
||
|
||
function isLinux() {
|
||
return os.type() === "Linux";
|
||
}
|
||
|
||
function sleep(ms) {
|
||
return new Promise(resolve => setTimeout(resolve, ms));
|
||
}
|
||
|
||
function readPidTicks(pid) {
|
||
const txt = fs.readFileSync(`/proc/${pid}/stat`, "utf8");
|
||
// 字段 14=utime 15=stime,comm 可能含空格,按最后一个 ) 截断
|
||
const rest = txt.slice(txt.lastIndexOf(")") + 1).trim().split(/\s+/);
|
||
return Number(rest[11]) + Number(rest[12]);
|
||
}
|
||
|
||
function readCpuTotal() {
|
||
const line = fs.readFileSync("/proc/stat", "utf8").split("\n")[0];
|
||
// user nice system idle iowait irq softirq steal(guest 已计入 user)
|
||
const parts = line.trim().split(/\s+/).slice(1, 9).map(Number);
|
||
let total = 0;
|
||
for (const v of parts) {
|
||
total += Number.isFinite(v) ? v : 0;
|
||
}
|
||
return total;
|
||
}
|
||
|
||
function readMemMB(pid) {
|
||
const status = fs.readFileSync(`/proc/${pid}/status`, "utf8");
|
||
const m = status.match(/^VmRSS:\s+(\d+)\s+kB/m);
|
||
if (!m) {
|
||
return null;
|
||
}
|
||
return Math.round(Number(m[1]) / 1024 * 100) / 100;
|
||
}
|
||
|
||
function readHandleCount(pid) {
|
||
return fs.readdirSync(`/proc/${pid}/fd`, { withFileTypes: true }).length;
|
||
}
|
||
|
||
/**
|
||
* 采集单个进程的监控数据
|
||
* @param {number} pid
|
||
* @returns {Promise<{pid:number,cpu:number,mem:number,handle:number}|null>} 进程不存在/不可读返回 null
|
||
*/
|
||
async function collectPid(pid) {
|
||
try {
|
||
const beforePid = readPidTicks(pid);
|
||
const beforeTotal = readCpuTotal();
|
||
await sleep(1000);
|
||
const afterPid = readPidTicks(pid);
|
||
const afterTotal = readCpuTotal();
|
||
|
||
const totalDelta = afterTotal - beforeTotal;
|
||
const pidDelta = afterPid - beforePid;
|
||
const cpu = totalDelta > 0 ? Math.round(pidDelta / totalDelta * 10000) / 100 : 0;
|
||
|
||
const mem = readMemMB(pid);
|
||
const handle = readHandleCount(pid);
|
||
return { pid, cpu, mem, handle };
|
||
} catch (e) {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
module.exports = {
|
||
isLinux,
|
||
collectPid,
|
||
findPortPid: portpid.findPortPid
|
||
}; |