EvalueTonSavoir/test/stressTest/utility/writeMetrics.js
MathieuSevignyLavallee 11222c70bd not finished
2024-11-26 17:04:22 -05:00

227 lines
7.6 KiB
JavaScript

import fs from "fs";
import path from "path";
import { ChartJSNodeCanvas } from "chartjs-node-canvas";
// Ensure a directory exists, creating it if necessary
function ensureDirectoryExists(directory) {
try {
fs.mkdirSync(directory, { recursive: true });
} catch (err) {
console.error(`Error creating directory ${directory}:`, err.message);
throw err;
}
}
// Write metrics to a JSON file
export function writeMetricsToFile(metrics) {
if (!metrics.endTime) {
console.error("Error: metrics.endTime is not defined. Ensure it is set before calling this function.");
return;
}
const directory = `./metrics/${metrics.startTime.toISOString().replace(/[:.]/g, "-")}`;
const filename = path.join(directory, "metrics_report.json");
// Ensure the directory exists
ensureDirectoryExists(directory);
const metricsData = {
summary: {
roomsCreated: metrics.roomsCreated,
roomsFailed: metrics.roomsFailed,
teachersConnected: metrics.teachersConnected,
teachersFailed: metrics.teachersFailed,
studentsConnected: metrics.studentsConnected,
studentsFailed: metrics.studentsFailed,
},
messages: {
messagesSent: metrics.messagesSent,
messagesReceived: metrics.messagesReceived,
throughput: metrics.throughput.toFixed(2), // Messages per second
},
latencies: {
totalLatency: metrics.totalLatency,
averageLatency: metrics.teachersConnected + metrics.studentsConnected
? (metrics.totalLatency / (metrics.teachersConnected + metrics.studentsConnected)).toFixed(2)
: null,
maxLatency: metrics.maxLatency,
minLatency: metrics.minLatency,
},
timing: {
startTime: metrics.startTime?.toISOString(),
endTime: metrics.endTime?.toISOString(),
executionTimeInSeconds: metrics.endTime && metrics.startTime
? (metrics.endTime - metrics.startTime) / 1000
: null,
},
};
// Write metrics to a file
fs.writeFile(filename, JSON.stringify(metricsData, null, 4), (err) => {
if (err) {
console.error(`Error writing metrics to file:`, err.message);
} else {
console.log(`Metrics saved to file: ${filename}`);
}
});
}
// Generate charts for resource data
export async function generateGraphs(resourceData, metrics) {
if (!metrics.endTime) {
console.error("Error: metrics.endTime is not defined. Ensure it is set before calling this function.");
return;
}
const directory = `./metrics/${metrics.startTime.toISOString().replace(/[:.]/g, "-")}`;
ensureDirectoryExists(directory);
const chartJSNodeCanvas = new ChartJSNodeCanvas({ width: 800, height: 600 });
// Aggregated data for all containers
const aggregatedTimestamps = [];
const aggregatedMemoryUsage = [];
const aggregatedCpuUserPercentage = [];
const aggregatedCpuSystemPercentage = [];
// Generate charts for individual containers
for (const [roomId, data] of Object.entries(resourceData)) {
if (!data || !data.length) {
console.warn(`No data available for room ${roomId}. Skipping individual charts.`);
continue;
}
// Extract data
const timestamps = data.map((point) => new Date(point.timestamp).toLocaleTimeString());
const memoryUsage = data.map((point) => (point.memory.rss || 0) / (1024 * 1024)); // MB
const cpuUserPercentage = data.map((point) => point.cpu.userPercentage || 0);
const cpuSystemPercentage = data.map((point) => point.cpu.systemPercentage || 0);
// Update aggregated data
data.forEach((point, index) => {
if (!aggregatedTimestamps[index]) {
aggregatedTimestamps[index] = timestamps[index];
aggregatedMemoryUsage[index] = 0;
aggregatedCpuUserPercentage[index] = 0;
aggregatedCpuSystemPercentage[index] = 0;
}
aggregatedMemoryUsage[index] += memoryUsage[index];
aggregatedCpuUserPercentage[index] += cpuUserPercentage[index];
aggregatedCpuSystemPercentage[index] += cpuSystemPercentage[index];
});
// Memory usage chart
await saveChart(
chartJSNodeCanvas,
{
labels: timestamps,
datasets: [
{
label: "Memory Usage (MB)",
data: memoryUsage,
borderColor: "blue",
fill: false,
},
],
},
"Time",
"Memory Usage (MB)",
path.join(directory, `memory-usage-room-${roomId}.png`)
);
// CPU usage chart
await saveChart(
chartJSNodeCanvas,
{
labels: timestamps,
datasets: [
{
label: "CPU User Usage (%)",
data: cpuUserPercentage,
borderColor: "red",
fill: false,
},
{
label: "CPU System Usage (%)",
data: cpuSystemPercentage,
borderColor: "orange",
fill: false,
},
],
},
"Time",
"CPU Usage (%)",
path.join(directory, `cpu-usage-room-${roomId}.png`)
);
console.log(`Charts generated for room ${roomId}`);
}
// Ensure aggregated data is not empty
if (!aggregatedTimestamps.length) {
console.error("Error: Aggregated data is empty. Verify container data.");
return;
}
// Aggregated memory usage chart
await saveChart(
chartJSNodeCanvas,
{
labels: aggregatedTimestamps,
datasets: [
{
label: "Total Memory Usage (MB)",
data: aggregatedMemoryUsage,
borderColor: "blue",
fill: false,
},
],
},
"Time",
"Memory Usage (MB)",
path.join(directory, "aggregated-memory-usage.png")
);
// Aggregated CPU usage chart
await saveChart(
chartJSNodeCanvas,
{
labels: aggregatedTimestamps,
datasets: [
{
label: "Total CPU User Usage (%)",
data: aggregatedCpuUserPercentage,
borderColor: "red",
fill: false,
},
{
label: "Total CPU System Usage (%)",
data: aggregatedCpuSystemPercentage,
borderColor: "orange",
fill: false,
},
],
},
"Time",
"CPU Usage (%)",
path.join(directory, "aggregated-cpu-usage.png")
);
console.log("Aggregated charts generated.");
}
// Helper function to save a chart
async function saveChart(chartJSNodeCanvas, data, xLabel, yLabel, outputFile) {
const chartConfig = {
type: "line",
data,
options: {
scales: {
x: { title: { display: true, text: xLabel } },
y: { title: { display: true, text: yLabel } },
},
},
};
const chartBuffer = await chartJSNodeCanvas.renderToBuffer(chartConfig);
fs.writeFileSync(outputFile, chartBuffer);
}