139 lines
3.9 KiB
JavaScript
139 lines
3.9 KiB
JavaScript
const http = require("http");
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const os = require("os");
|
|
const { exec } = require("child_process");
|
|
|
|
const PORT = process.env.PORT || 3000;
|
|
const MIME = {
|
|
".html": "text/html; charset=utf-8",
|
|
".css": "text/css; charset=utf-8",
|
|
".js": "application/javascript; charset=utf-8",
|
|
".json": "application/json; charset=utf-8",
|
|
".svg": "image/svg+xml",
|
|
};
|
|
|
|
function run(cmd) {
|
|
return new Promise((resolve) => {
|
|
exec(cmd, { timeout: 4000 }, (err, stdout) => {
|
|
if (err) return resolve(null);
|
|
resolve(stdout.trim());
|
|
});
|
|
});
|
|
}
|
|
|
|
let lastCpu = os.cpus();
|
|
|
|
function cpuUsage() {
|
|
const now = os.cpus();
|
|
let total = 0, idle = 0;
|
|
for (let i = 0; i < now.length; i++) {
|
|
const cur = now[i].times;
|
|
const prev = lastCpu[i].times;
|
|
const t = (cur.user + cur.nice + cur.sys + cur.idle + cur.irq) -
|
|
(prev.user + prev.nice + prev.sys + prev.idle + prev.irq);
|
|
const i2 = cur.idle - prev.idle;
|
|
if (t > 0) { total += t; idle += i2; }
|
|
}
|
|
lastCpu = now;
|
|
return total > 0 ? Math.round(((total - idle) / total) * 1000) / 10 : 0;
|
|
}
|
|
|
|
async function diskInfo() {
|
|
const out = await run("df -k -P /");
|
|
if (!out) return null;
|
|
const line = out.split("\n").pop();
|
|
const parts = line.split(/\s+/);
|
|
if (parts.length < 5) return null;
|
|
const total = +parts[1] * 1024;
|
|
const used = +parts[2] * 1024;
|
|
const free = +parts[3] * 1024;
|
|
return {
|
|
total,
|
|
used,
|
|
free,
|
|
percent: total > 0 ? Math.round((used / total) * 1000) / 10 : 0,
|
|
};
|
|
}
|
|
|
|
async function topProcesses() {
|
|
const out = await run("ps -eo pid=,comm=,%cpu=,%mem= --sort=-%cpu | head -8");
|
|
if (!out) return [];
|
|
const rows = out.split("\n").filter(Boolean).map((l) => {
|
|
const m = l.trim().split(/\s+/);
|
|
if (m.length < 4) return null;
|
|
const pid = +m[0];
|
|
const name = m.slice(1, m.length - 2).join(" ") || "?";
|
|
return { pid, name, cpu: +parseFloat(m[m.length - 2]).toFixed(1), mem: +parseFloat(m[m.length - 1]).toFixed(1) };
|
|
});
|
|
return rows.filter(Boolean);
|
|
}
|
|
|
|
function cpuInfo() {
|
|
const cpus = os.cpus();
|
|
const speed = cpus[0] ? Math.round(cpus[0].speed / 100) / 10 : 0;
|
|
const model = cpus[0] ? cpus[0].model.trim() : "";
|
|
return {
|
|
usage: cpuUsage(),
|
|
model,
|
|
cores: cpus.length,
|
|
speed,
|
|
};
|
|
}
|
|
|
|
function memInfo() {
|
|
const total = os.totalmem();
|
|
const free = os.freemem();
|
|
const used = total - free;
|
|
return { total, used, free, percent: Math.round((used / total) * 1000) / 10 };
|
|
}
|
|
|
|
function networkInfo() {
|
|
const ifs = os.networkInterfaces();
|
|
for (const name of Object.keys(ifs)) {
|
|
for (const a of ifs[name] || []) {
|
|
if (a.family === "IPv4" && !a.internal) return name + ": " + a.address;
|
|
}
|
|
}
|
|
return "—";
|
|
}
|
|
|
|
async function metrics() {
|
|
const disk = await diskInfo();
|
|
return {
|
|
status: "ok",
|
|
hostname: os.hostname(),
|
|
os: os.platform(),
|
|
release: os.release(),
|
|
arch: os.arch(),
|
|
uptime: Math.floor(os.uptime()),
|
|
loadavg: os.loadavg(),
|
|
cpu: cpuInfo(),
|
|
mem: memInfo(),
|
|
disk: disk || { total: 0, used: 0, free: 0, percent: 0 },
|
|
network: networkInfo(),
|
|
processes: await topProcesses(),
|
|
timestamp: Date.now(),
|
|
};
|
|
}
|
|
|
|
http.createServer(async (req, res) => {
|
|
const url = (req.url || "/").split("?")[0];
|
|
|
|
if (req.method === "GET" && url === "/api/metrics") {
|
|
res.writeHead(200, { "Content-Type": MIME[".json"] });
|
|
return res.end(JSON.stringify(await metrics()));
|
|
}
|
|
|
|
let file = url === "/" ? "/index.html" : url;
|
|
const full = path.join(__dirname, file);
|
|
if (full.startsWith(__dirname) && fs.existsSync(full) && fs.statSync(full).isFile()) {
|
|
const type = MIME[path.extname(full)] || "application/octet-stream";
|
|
res.writeHead(200, { "Content-Type": type });
|
|
return res.end(fs.readFileSync(full));
|
|
}
|
|
|
|
res.writeHead(404);
|
|
res.end("Not found");
|
|
}).listen(PORT, () => console.log("Мониторинг запущен на порту " + PORT));
|