diff --git a/.yarn/cache/fsevents-patch-19706e7e35-10.zip b/.yarn/cache/fsevents-patch-19706e7e35-10.zip deleted file mode 100644 index aff1ab12ce5..00000000000 Binary files a/.yarn/cache/fsevents-patch-19706e7e35-10.zip and /dev/null differ diff --git a/packages/dashmate/src/doctor/analyse/analyseServiceContainersFactory.js b/packages/dashmate/src/doctor/analyse/analyseServiceContainersFactory.js index 7cf6b6c6964..4edd993b62e 100644 --- a/packages/dashmate/src/doctor/analyse/analyseServiceContainersFactory.js +++ b/packages/dashmate/src/doctor/analyse/analyseServiceContainersFactory.js @@ -20,9 +20,12 @@ export default function analyseServiceContainersFactory( const servicesNotStarted = []; const servicesFailed = []; const servicesOOMKilled = []; + const servicesHighCpuUsage = []; + const servicesHighMemoryUsage = []; for (const service of services) { const dockerInspect = samples.getServiceInfo(service.name, 'dockerInspect'); + const dockerStats = samples.getServiceInfo(service.name, 'dockerStats'); if (!dockerInspect) { continue; @@ -47,6 +50,34 @@ export default function analyseServiceContainersFactory( service, }); } + + const cpuSystemUsage = dockerStats?.cpuStats?.system_cpu_usage ?? 0; + const cpuServiceUsage = dockerStats?.cpuStats?.cpu_usage?.total_usage ?? 0; + + if (cpuSystemUsage > 0) { + const cpuUsage = cpuServiceUsage / cpuSystemUsage; + + if (cpuUsage > 0.8) { + servicesHighCpuUsage.push({ + service, + cpuUsage, + }); + } + } + + const memoryLimit = dockerStats?.memoryStats?.limit ?? 0; + const memoryServiceUsage = dockerStats?.memoryStats?.usage ?? 0; + + if (memoryLimit > 0) { + const memoryUsage = memoryServiceUsage / memoryLimit; + + if (memoryUsage > 0.8) { + servicesHighMemoryUsage.push({ + service, + memoryUsage, + }); + } + } } const problems = []; @@ -103,6 +134,34 @@ export default function analyseServiceContainersFactory( problems.push(problem); } + if (servicesHighCpuUsage.length > 0) { + for (const highCpuService of servicesHighCpuUsage) { + const description = `Service ${highCpuService.service.title} is consuming ${(highCpuService.cpuUsage * 100).toFixed(2)}% CPU.`; + + const problem = new Problem( + description, + 'Consider upgrading CPU or report in case of misbehaviour.', + SEVERITY.MEDIUM, + ); + + problems.push(problem); + } + } + + if (servicesHighMemoryUsage.length > 0) { + for (const highMemoryService of servicesHighMemoryUsage) { + const description = `Service ${highMemoryService.service.title} is consuming ${(highMemoryService.memoryUsage * 100).toFixed(2)}% RAM.`; + + const problem = new Problem( + description, + 'Consider upgrading RAM or report in case of misbehaviour.', + SEVERITY.MEDIUM, + ); + + problems.push(problem); + } + } + return problems; } diff --git a/packages/dashmate/src/listr/tasks/doctor/collectSamplesTaskFactory.js b/packages/dashmate/src/listr/tasks/doctor/collectSamplesTaskFactory.js index c766b316ada..a3be7545091 100644 --- a/packages/dashmate/src/listr/tasks/doctor/collectSamplesTaskFactory.js +++ b/packages/dashmate/src/listr/tasks/doctor/collectSamplesTaskFactory.js @@ -2,6 +2,7 @@ import fs from 'fs'; import { Listr } from 'listr2'; import path from 'path'; import process from 'process'; +import si from 'systeminformation'; import obfuscateConfig from '../../../config/obfuscateConfig.js'; import { DASHMATE_VERSION } from '../../../constants.js'; import Certificate from '../../../ssl/zerossl/Certificate.js'; @@ -312,13 +313,10 @@ export default function collectSamplesTaskFactory( }, }, { - title: 'Logs', - task: async (ctx, task) => { + title: 'Docker containers info', + task: async (ctx) => { const services = await getServiceList(config); - // eslint-disable-next-line no-param-reassign - task.output = `Pulling logs from ${services.map((e) => e.name)}`; - await Promise.all( services.map(async (service) => { const [inspect, logs] = (await Promise.allSettled([ @@ -326,6 +324,12 @@ export default function collectSamplesTaskFactory( dockerCompose.logs(config, [service.name], { tail: 300000 }), ])).map((e) => e.value || e.reason); + const containerId = inspect?.Id; + let dockerStats; + if (containerId) { + dockerStats = await si.dockerContainerStats(containerId); + } + if (logs?.out) { // Hide username & external ip from logs logs.out = logs.out.replaceAll( @@ -354,6 +358,7 @@ export default function collectSamplesTaskFactory( ctx.samples.setServiceInfo(service.name, 'stdOut', logs?.out); ctx.samples.setServiceInfo(service.name, 'stdErr', logs?.err); ctx.samples.setServiceInfo(service.name, 'dockerInspect', inspect); + ctx.samples.setServiceInfo(service.name, 'dockerStats', dockerStats); }), ); },