103 lines
2.9 KiB
JavaScript
103 lines
2.9 KiB
JavaScript
|
|
"use strict";
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Linux 服务器采集器
|
|||
|
|
*
|
|||
|
|
* 采集指标(告警相关):
|
|||
|
|
* - cpu_usage CPU 使用率(%)
|
|||
|
|
* - memory_usage 内存使用率(%)
|
|||
|
|
* - disk_usage 磁盘使用率(%,只显示超过 80% 的挂载点)
|
|||
|
|
*
|
|||
|
|
* 实现说明:
|
|||
|
|
* 直接使用 POSIX shell 命令,命令与 NetMesh System Manager 的概览一致。
|
|||
|
|
* 传入 exec 函数来执行远程命令(由调度器注入,复用 SSH 连接池)。
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
const BaseAdapter = require("./baseAdapter.cjs");
|
|||
|
|
|
|||
|
|
class LinuxServerAdapter extends BaseAdapter {
|
|||
|
|
constructor(connectionInfo, options = {}) {
|
|||
|
|
super(connectionInfo, options);
|
|||
|
|
this.adapterName = "linux_server";
|
|||
|
|
// 支持外部注入 exec 函数(用于复用 SSH 连接)
|
|||
|
|
if (options.execFn) {
|
|||
|
|
this.execute = options.execFn;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
getSupportedMetrics() {
|
|||
|
|
return [
|
|||
|
|
"cpu_usage",
|
|||
|
|
"memory_usage",
|
|||
|
|
"disk_usage",
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async collectMetrics() {
|
|||
|
|
const metrics = {};
|
|||
|
|
const raw = {};
|
|||
|
|
|
|||
|
|
// 1. CPU 使用率(采样 top)
|
|||
|
|
try {
|
|||
|
|
raw.cpu = await this.execute("top -bn1 2>/dev/null | head -n 5");
|
|||
|
|
const cpuMatch = (raw.cpu || "").match(/Cpu\(s\):\s*([\d.]+)\s*us,\s*([\d.]+)\s*sy/i);
|
|||
|
|
if (cpuMatch) {
|
|||
|
|
metrics.cpu_usage = Math.round(parseFloat(cpuMatch[1]) + parseFloat(cpuMatch[2]));
|
|||
|
|
}
|
|||
|
|
} catch (e) {
|
|||
|
|
throw e; // SSH 失败或其他错误必须向上传播
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. 内存使用率
|
|||
|
|
try {
|
|||
|
|
raw.mem = await this.execute("free -k 2>/dev/null | head -n 2 | tail -n 1");
|
|||
|
|
// 支持中英文输出: "Mem:" 或 "内存:"
|
|||
|
|
const memMatch = (raw.mem || "").match(/(?:Mem:|内存[::])\s+(\d+)\s+(\d+)/);
|
|||
|
|
if (memMatch) {
|
|||
|
|
const total = parseInt(memMatch[1], 10);
|
|||
|
|
const used = parseInt(memMatch[2], 10);
|
|||
|
|
if (total > 0) {
|
|||
|
|
metrics.memory_usage = Math.min(100, Math.round((used / total) * 100));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} catch (e) {
|
|||
|
|
throw e;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. 磁盘使用率(显示所有挂载点)
|
|||
|
|
try {
|
|||
|
|
raw.disk = await this.execute("df -h 2>/dev/null | tail -n +2 | grep -v '/dev/loop'");
|
|||
|
|
const disks = this.parseDiskUsage(raw.disk);
|
|||
|
|
if (disks.length > 0) metrics.disk_usage = disks;
|
|||
|
|
} catch (e) {
|
|||
|
|
throw e;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return metrics;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 解析磁盘使用率(df -h 输出格式),返回所有挂载点
|
|||
|
|
*/
|
|||
|
|
parseDiskUsage(text) {
|
|||
|
|
const disks = [];
|
|||
|
|
const lines = (text || "").split("\n");
|
|||
|
|
for (const line of lines) {
|
|||
|
|
const parts = line.trim().split(/\s+/);
|
|||
|
|
if (parts.length < 6) continue;
|
|||
|
|
const usageStr = parts[4] || "";
|
|||
|
|
const usageMatch = usageStr.match(/^(\d+)%/);
|
|||
|
|
if (!usageMatch) continue;
|
|||
|
|
const usagePercent = parseInt(usageMatch[1], 10);
|
|||
|
|
disks.push({
|
|||
|
|
filesystem: parts[0],
|
|||
|
|
usage_percent: usagePercent,
|
|||
|
|
mount: parts[parts.length - 1],
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
return disks;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
module.exports = LinuxServerAdapter;
|