fix: remplacer nsenter par lecture directe /proc pour les métriques monitoring
This commit is contained in:
@@ -181,67 +181,52 @@ async function restartContainer(containerName) {
|
|||||||
function getServerMetrics() {
|
function getServerMetrics() {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const { execSync } = require("child_process");
|
const { execSync } = require("child_process");
|
||||||
|
const fs = require("fs");
|
||||||
try {
|
try {
|
||||||
// nsenter -t 1 -m lit les métriques réelles de l'hôte VPS (pas de l'hyperviseur)
|
// Lecture directe de /proc (monté depuis l'hôte via le namespace PID du conteneur)
|
||||||
const ns = "nsenter -t 1 -m --";
|
// Pas besoin de nsenter : /proc dans le conteneur reflète l'hôte
|
||||||
|
|
||||||
// CPU : delta /proc/stat sur 200ms
|
// CPU : delta /proc/stat sur 300ms
|
||||||
let cpuUsage = 0;
|
let cpuUsage = 0;
|
||||||
try {
|
try {
|
||||||
const s1 = execSync(`${ns} cat /proc/stat | grep '^cpu '`).toString().trim().split(/\s+/);
|
const parseCpuLine = (line) => line.trim().split(/\s+/).slice(1).map(Number);
|
||||||
execSync("sleep 0.2");
|
const s1 = parseCpuLine(fs.readFileSync('/proc/stat', 'utf8').split('\n').find(l => l.startsWith('cpu ')));
|
||||||
const s2 = execSync(`${ns} cat /proc/stat | grep '^cpu '`).toString().trim().split(/\s+/);
|
execSync("sleep 0.3");
|
||||||
const idle1 = parseInt(s1[4]), total1 = s1.slice(1).reduce((a,b)=>a+parseInt(b),0);
|
const s2 = parseCpuLine(fs.readFileSync('/proc/stat', 'utf8').split('\n').find(l => l.startsWith('cpu ')));
|
||||||
const idle2 = parseInt(s2[4]), total2 = s2.slice(1).reduce((a,b)=>a+parseInt(b),0);
|
const idle1 = s1[3], total1 = s1.reduce((a,b)=>a+b,0);
|
||||||
|
const idle2 = s2[3], total2 = s2.reduce((a,b)=>a+b,0);
|
||||||
const dIdle = idle2 - idle1, dTotal = total2 - total1;
|
const dIdle = idle2 - idle1, dTotal = total2 - total1;
|
||||||
cpuUsage = dTotal > 0 ? Math.round((1 - dIdle / dTotal) * 100) : 0;
|
cpuUsage = dTotal > 0 ? Math.round((1 - dIdle / dTotal) * 100) : 0;
|
||||||
} catch(e) {
|
} catch(e) {}
|
||||||
try {
|
|
||||||
const cpuRaw = execSync(`${ns} top -bn1 | grep 'Cpu(s)' | awk '{print $2}'`).toString().trim();
|
|
||||||
cpuUsage = parseFloat(cpuRaw) || 0;
|
|
||||||
} catch(e2) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RAM : cgroup de l'hôte (fiable même en environnement VPS virtualisé)
|
// RAM : lecture de /proc/meminfo (valeurs réelles de l'hôte)
|
||||||
// La RAM totale est lue depuis /sys/fs/cgroup/memory.max de l'hôte
|
|
||||||
// La RAM utilisée est calculée via docker stats (valeurs réelles du VPS)
|
|
||||||
let memTotal = 8589934592; // 8 Go par défaut
|
let memTotal = 8589934592; // 8 Go par défaut
|
||||||
|
let memFree = 0, memAvailable = 0, memUsed = 0;
|
||||||
try {
|
try {
|
||||||
const cgroupMax = execSync(`${ns} cat /sys/fs/cgroup/memory.max 2>/dev/null || cat /sys/fs/cgroup/memory/memory.limit_in_bytes 2>/dev/null`).toString().trim();
|
const meminfo = fs.readFileSync('/proc/meminfo', 'utf8');
|
||||||
if (cgroupMax && cgroupMax !== 'max' && !isNaN(parseInt(cgroupMax))) {
|
const getVal = (key) => {
|
||||||
memTotal = parseInt(cgroupMax);
|
const m = meminfo.match(new RegExp(`^${key}:\\s+(\\d+)`, 'm'));
|
||||||
}
|
return m ? parseInt(m[1]) * 1024 : 0;
|
||||||
|
};
|
||||||
|
memTotal = getVal('MemTotal');
|
||||||
|
memFree = getVal('MemFree');
|
||||||
|
memAvailable = getVal('MemAvailable');
|
||||||
|
memUsed = memTotal - memAvailable;
|
||||||
} catch(e) {}
|
} catch(e) {}
|
||||||
|
|
||||||
// RAM utilisée : somme de tous les conteneurs via docker stats
|
// Disque : df sur la racine du conteneur (= hôte car pas de volume overlay)
|
||||||
let memUsed = 0;
|
let diskTotal = 0, diskUsed = 0, diskFree = 0;
|
||||||
try {
|
try {
|
||||||
const statsRaw = execSync("docker stats --no-stream --format '{{.MemUsage}}'").toString().trim();
|
const diskRaw = execSync('df -B1 / | tail -1').toString().trim().split(/\s+/);
|
||||||
statsRaw.split('\n').forEach(line => {
|
diskTotal = parseInt(diskRaw[1]);
|
||||||
const match = line.match(/([\d.]+)(\w+)\s*\//);
|
diskUsed = parseInt(diskRaw[2]);
|
||||||
if (match) {
|
diskFree = parseInt(diskRaw[3]);
|
||||||
const val = parseFloat(match[1]);
|
|
||||||
const unit = match[2].toLowerCase();
|
|
||||||
if (unit === 'gib') memUsed += val * 1024 * 1024 * 1024;
|
|
||||||
else if (unit === 'mib') memUsed += val * 1024 * 1024;
|
|
||||||
else if (unit === 'kib') memUsed += val * 1024;
|
|
||||||
else memUsed += val;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch(e) {}
|
} catch(e) {}
|
||||||
const memAvailable = memTotal - memUsed;
|
|
||||||
const memFree = memAvailable;
|
|
||||||
|
|
||||||
// Disque : df sur l'hôte
|
|
||||||
const diskRaw = execSync(`${ns} df -B1 / | tail -1`).toString().trim().split(/\s+/);
|
|
||||||
const diskTotal = parseInt(diskRaw[1]);
|
|
||||||
const diskUsed = parseInt(diskRaw[2]);
|
|
||||||
const diskFree = parseInt(diskRaw[3]);
|
|
||||||
|
|
||||||
// Uptime et load
|
// Uptime et load
|
||||||
const uptimeRaw = execSync(`${ns} cat /proc/uptime`).toString().trim().split(" ");
|
const uptimeRaw = fs.readFileSync('/proc/uptime', 'utf8').trim().split(' ');
|
||||||
const uptimeSeconds = parseFloat(uptimeRaw[0]);
|
const uptimeSeconds = parseFloat(uptimeRaw[0]);
|
||||||
const loadRaw = execSync(`${ns} cat /proc/loadavg`).toString().trim().split(" ");
|
const loadRaw = fs.readFileSync('/proc/loadavg', 'utf8').trim().split(' ');
|
||||||
const load1 = parseFloat(loadRaw[0]);
|
const load1 = parseFloat(loadRaw[0]);
|
||||||
const load5 = parseFloat(loadRaw[1]);
|
const load5 = parseFloat(loadRaw[1]);
|
||||||
const load15 = parseFloat(loadRaw[2]);
|
const load15 = parseFloat(loadRaw[2]);
|
||||||
@@ -249,9 +234,13 @@ function getServerMetrics() {
|
|||||||
// Réseau
|
// Réseau
|
||||||
let netRx = 0, netTx = 0;
|
let netRx = 0, netTx = 0;
|
||||||
try {
|
try {
|
||||||
const netRaw = execSync(`${ns} cat /proc/net/dev | grep -E 'eth0|ens|enp' | head -1`).toString().trim().split(/\s+/);
|
const netDev = fs.readFileSync('/proc/net/dev', 'utf8');
|
||||||
netRx = parseInt(netRaw[1]) || 0;
|
const netLine = netDev.split('\n').find(l => /eth0|ens|enp/.test(l));
|
||||||
netTx = parseInt(netRaw[9]) || 0;
|
if (netLine) {
|
||||||
|
const parts = netLine.trim().split(/\s+/);
|
||||||
|
netRx = parseInt(parts[1]) || 0;
|
||||||
|
netTx = parseInt(parts[9]) || 0;
|
||||||
|
}
|
||||||
} catch(e) {}
|
} catch(e) {}
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
|
|||||||
Reference in New Issue
Block a user