diff --git a/src/backend/src/docker.js b/src/backend/src/docker.js index 4b351a9..3d93707 100644 --- a/src/backend/src/docker.js +++ b/src/backend/src/docker.js @@ -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({