fix: remplacer nsenter par lecture directe /proc pour les métriques monitoring

This commit is contained in:
manus-admin
2026-06-01 01:14:33 +02:00
parent 6bae1d569d
commit ed57d4af73

View File

@@ -181,67 +181,52 @@ async function restartContainer(containerName) {
function getServerMetrics() {
return new Promise((resolve) => {
const { execSync } = require("child_process");
const fs = require("fs");
try {
// nsenter -t 1 -m lit les métriques réelles de l'hôte VPS (pas de l'hyperviseur)
const ns = "nsenter -t 1 -m --";
// Lecture directe de /proc (monté depuis l'hôte via le namespace PID du conteneur)
// 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;
try {
const s1 = execSync(`${ns} cat /proc/stat | grep '^cpu '`).toString().trim().split(/\s+/);
execSync("sleep 0.2");
const s2 = execSync(`${ns} cat /proc/stat | grep '^cpu '`).toString().trim().split(/\s+/);
const idle1 = parseInt(s1[4]), total1 = s1.slice(1).reduce((a,b)=>a+parseInt(b),0);
const idle2 = parseInt(s2[4]), total2 = s2.slice(1).reduce((a,b)=>a+parseInt(b),0);
const parseCpuLine = (line) => line.trim().split(/\s+/).slice(1).map(Number);
const s1 = parseCpuLine(fs.readFileSync('/proc/stat', 'utf8').split('\n').find(l => l.startsWith('cpu ')));
execSync("sleep 0.3");
const s2 = parseCpuLine(fs.readFileSync('/proc/stat', 'utf8').split('\n').find(l => l.startsWith('cpu ')));
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;
cpuUsage = dTotal > 0 ? Math.round((1 - dIdle / dTotal) * 100) : 0;
} catch(e) {
try {
const cpuRaw = execSync(`${ns} top -bn1 | grep 'Cpu(s)' | awk '{print $2}'`).toString().trim();
cpuUsage = parseFloat(cpuRaw) || 0;
} catch(e2) {}
}
} catch(e) {}
// RAM : cgroup de l'hôte (fiable même en environnement VPS virtualisé)
// 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)
// RAM : lecture de /proc/meminfo (valeurs réelles de l'hôte)
let memTotal = 8589934592; // 8 Go par défaut
let memFree = 0, memAvailable = 0, memUsed = 0;
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();
if (cgroupMax && cgroupMax !== 'max' && !isNaN(parseInt(cgroupMax))) {
memTotal = parseInt(cgroupMax);
}
const meminfo = fs.readFileSync('/proc/meminfo', 'utf8');
const getVal = (key) => {
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) {}
// RAM utilisée : somme de tous les conteneurs via docker stats
let memUsed = 0;
// Disque : df sur la racine du conteneur (= hôte car pas de volume overlay)
let diskTotal = 0, diskUsed = 0, diskFree = 0;
try {
const statsRaw = execSync("docker stats --no-stream --format '{{.MemUsage}}'").toString().trim();
statsRaw.split('\n').forEach(line => {
const match = line.match(/([\d.]+)(\w+)\s*\//);
if (match) {
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;
}
});
const diskRaw = execSync('df -B1 / | tail -1').toString().trim().split(/\s+/);
diskTotal = parseInt(diskRaw[1]);
diskUsed = parseInt(diskRaw[2]);
diskFree = parseInt(diskRaw[3]);
} 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
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 loadRaw = execSync(`${ns} cat /proc/loadavg`).toString().trim().split(" ");
const loadRaw = fs.readFileSync('/proc/loadavg', 'utf8').trim().split(' ');
const load1 = parseFloat(loadRaw[0]);
const load5 = parseFloat(loadRaw[1]);
const load15 = parseFloat(loadRaw[2]);
@@ -249,9 +234,13 @@ function getServerMetrics() {
// Réseau
let netRx = 0, netTx = 0;
try {
const netRaw = execSync(`${ns} cat /proc/net/dev | grep -E 'eth0|ens|enp' | head -1`).toString().trim().split(/\s+/);
netRx = parseInt(netRaw[1]) || 0;
netTx = parseInt(netRaw[9]) || 0;
const netDev = fs.readFileSync('/proc/net/dev', 'utf8');
const netLine = netDev.split('\n').find(l => /eth0|ens|enp/.test(l));
if (netLine) {
const parts = netLine.trim().split(/\s+/);
netRx = parseInt(parts[1]) || 0;
netTx = parseInt(parts[9]) || 0;
}
} catch(e) {}
resolve({