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() {
|
||||
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({
|
||||
|
||||
Reference in New Issue
Block a user