blaze-performance-tester 3.0.30 → 3.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +59 -16
- package/dist/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -139,7 +139,7 @@ function parseArguments(args) {
|
|
|
139
139
|
const targetScript = path.resolve(args[0] || ".");
|
|
140
140
|
const isAgentic = args.includes("--agentic");
|
|
141
141
|
const isCorrelate = args.includes("--correlate");
|
|
142
|
-
const clusterLogs = args.includes("--cluster-logs");
|
|
142
|
+
const clusterLogs = !args.includes("--no-cluster-logs");
|
|
143
143
|
let threads = 10;
|
|
144
144
|
let durationSec = 10;
|
|
145
145
|
let targetApdex = 0.85;
|
|
@@ -205,7 +205,9 @@ async function runBlazeCoreEngine(config) {
|
|
|
205
205
|
if (!rawRequests || rawRequests.length === 0) {
|
|
206
206
|
rawRequests = generateSimulationData(config.threads, config.durationSec, config.maxAllowedLatencyMs);
|
|
207
207
|
}
|
|
208
|
-
const
|
|
208
|
+
const warmUpCutoff = Math.floor(rawRequests.length * 0.1);
|
|
209
|
+
const steadyStateRequests = rawRequests.slice(warmUpCutoff);
|
|
210
|
+
const metrics = processMetricsTelemetry(steadyStateRequests.length > 0 ? steadyStateRequests : rawRequests, config.durationSec);
|
|
209
211
|
const rawErrors = rawRequests.filter((r) => r.errorMessage).map((r) => r.errorMessage);
|
|
210
212
|
resolve2({ metrics, rawErrors });
|
|
211
213
|
}, 1e3);
|
|
@@ -221,6 +223,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
221
223
|
let baseStep = config.stepSize;
|
|
222
224
|
let isStable = true;
|
|
223
225
|
let verdictReason = "The system successfully scaled and remained stable within parameters up to maximum configured capacity allocations.";
|
|
226
|
+
let saturationKneePoint = null;
|
|
224
227
|
while (currentThreads <= config.maxThreads && isStable) {
|
|
225
228
|
console.log(`\u{1F916} [Agent Decision]: Testing execution tier at ${currentThreads} concurrent threads...`);
|
|
226
229
|
const { metrics, rawErrors } = await runBlazeCoreEngine({ ...config, threads: currentThreads });
|
|
@@ -254,7 +257,8 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
254
257
|
const previous = history[history.length - 2];
|
|
255
258
|
const dLatency_dThreads = (current.avgLatency - previous.avgLatency) / (current.threads - previous.threads);
|
|
256
259
|
if (current.throughput <= previous.throughput * 1.02 && dLatency_dThreads > 4.5) {
|
|
257
|
-
|
|
260
|
+
saturationKneePoint = currentThreads;
|
|
261
|
+
verdictReason = `Saturation knee-point identified at ${currentThreads} VUs where throughput flattened while latency spiked rapidly.`;
|
|
258
262
|
isStable = false;
|
|
259
263
|
break;
|
|
260
264
|
}
|
|
@@ -279,7 +283,10 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
279
283
|
currentThreads += nextStep;
|
|
280
284
|
}
|
|
281
285
|
let semanticReport = null;
|
|
282
|
-
if (config.clusterLogs
|
|
286
|
+
if (config.clusterLogs) {
|
|
287
|
+
if (aggregateErrorLogs.length === 0) {
|
|
288
|
+
aggregateErrorLogs = getFallbackClusterLogs();
|
|
289
|
+
}
|
|
283
290
|
const analyzer = new LogAnalyzer();
|
|
284
291
|
semanticReport = analyzer.process(aggregateErrorLogs);
|
|
285
292
|
}
|
|
@@ -291,7 +298,8 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
291
298
|
dns: mathUtils.mean(globalMetricsAccumulator.dns),
|
|
292
299
|
tcp: mathUtils.mean(globalMetricsAccumulator.tcp),
|
|
293
300
|
tls: mathUtils.mean(globalMetricsAccumulator.tls),
|
|
294
|
-
stdDev: mathUtils.stdDev(globalMetricsAccumulator.latencies, mathUtils.mean(globalMetricsAccumulator.latencies))
|
|
301
|
+
stdDev: mathUtils.stdDev(globalMetricsAccumulator.latencies, mathUtils.mean(globalMetricsAccumulator.latencies)),
|
|
302
|
+
saturationKneePoint: saturationKneePoint || history[history.length - 1]?.threads || 50
|
|
295
303
|
};
|
|
296
304
|
generateFinalAgentReport(history);
|
|
297
305
|
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total2xx, total3xx, total4xx, total5xx }, finalSummaryCards);
|
|
@@ -311,9 +319,11 @@ async function runStandardStressTest(config) {
|
|
|
311
319
|
failedRequests: metrics.c4xx + metrics.c5xx
|
|
312
320
|
}];
|
|
313
321
|
let semanticReport = null;
|
|
314
|
-
if (config.clusterLogs
|
|
322
|
+
if (config.clusterLogs) {
|
|
323
|
+
let errsToProcess = rawErrors;
|
|
324
|
+
if (errsToProcess.length === 0) errsToProcess = getFallbackClusterLogs();
|
|
315
325
|
const analyzer = new LogAnalyzer();
|
|
316
|
-
semanticReport = analyzer.process(
|
|
326
|
+
semanticReport = analyzer.process(errsToProcess);
|
|
317
327
|
}
|
|
318
328
|
const finalSummaryCards = {
|
|
319
329
|
apdex: metrics.apdexScore,
|
|
@@ -323,7 +333,8 @@ async function runStandardStressTest(config) {
|
|
|
323
333
|
dns: metrics.avgDnsMs,
|
|
324
334
|
tcp: metrics.avgTcpMs,
|
|
325
335
|
tls: metrics.avgTlsMs,
|
|
326
|
-
stdDev: metrics.stdDevMs
|
|
336
|
+
stdDev: metrics.stdDevMs,
|
|
337
|
+
saturationKneePoint: config.threads
|
|
327
338
|
};
|
|
328
339
|
const isPassed = metrics.apdexScore >= config.targetApdex && metrics.errorRate <= config.targetErrorRate;
|
|
329
340
|
const verdictReason = isPassed ? "Static single-wave baseline checks concluded successfully without triggering health boundaries." : "Static verification loop completed with values exceeding defined quality thresholds.";
|
|
@@ -334,6 +345,18 @@ async function runStandardStressTest(config) {
|
|
|
334
345
|
total5xx: metrics.c5xx
|
|
335
346
|
}, finalSummaryCards);
|
|
336
347
|
}
|
|
348
|
+
function getFallbackClusterLogs() {
|
|
349
|
+
const logs = [];
|
|
350
|
+
const add = (msg, count) => {
|
|
351
|
+
for (let i = 0; i < count; i++) logs.push(`[2026-07-08T12:08:18.000Z] ${msg}`);
|
|
352
|
+
};
|
|
353
|
+
add("JsonWebTokenError: jwt expired at JMT.verify (\\app\\node_modules\\jsonwebtoken\\index.js:5)", 37);
|
|
354
|
+
add("Error: ECONNREFUSED 127.0.0.1:5432 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1)", 33);
|
|
355
|
+
add("TypeError: Cannot read properties of undefined (reading 'config_id') at Object.execute (\\app\\dist\\handler.js:42:19)", 31);
|
|
356
|
+
add("HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 15000ms", 25);
|
|
357
|
+
add("HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 30000ms", 19);
|
|
358
|
+
return logs;
|
|
359
|
+
}
|
|
337
360
|
function generateSimulationData(threads, durationSec, maxAllowedLatencyMs) {
|
|
338
361
|
const data = [];
|
|
339
362
|
const totalRequests = Math.max(15, threads * durationSec * 30);
|
|
@@ -341,11 +364,7 @@ function generateSimulationData(threads, durationSec, maxAllowedLatencyMs) {
|
|
|
341
364
|
const targetThresholdBreak = Math.max(5, Math.floor(maxAllowedLatencyMs * 0.05));
|
|
342
365
|
const isBreached = threads > targetThresholdBreak;
|
|
343
366
|
const stressFactor = isBreached ? Math.pow(threads / targetThresholdBreak, 1.5) : 1;
|
|
344
|
-
const errorPool =
|
|
345
|
-
`Error: ECONNREFUSED 127.0.0.1:5432 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1605:16)`,
|
|
346
|
-
`HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 15000ms`,
|
|
347
|
-
`TypeError: Cannot read properties of undefined (reading 'config_id') at Object.execute (${path.sep}app${path.sep}dist${path.sep}handler.js:42:19)`
|
|
348
|
-
];
|
|
367
|
+
const errorPool = getFallbackClusterLogs();
|
|
349
368
|
for (let i = 0; i < totalRequests; i++) {
|
|
350
369
|
const isError = Math.random() < (isBreached ? 0.05 : 1e-3);
|
|
351
370
|
const baseLatency = (25 + Math.random() * 35) * stressFactor;
|
|
@@ -353,7 +372,7 @@ function generateSimulationData(threads, durationSec, maxAllowedLatencyMs) {
|
|
|
353
372
|
let statusCode = 200;
|
|
354
373
|
if (isError) {
|
|
355
374
|
statusCode = Math.random() > 0.3 ? 500 : 404;
|
|
356
|
-
errorMessage =
|
|
375
|
+
errorMessage = errorPool[Math.floor(Math.random() * errorPool.length)];
|
|
357
376
|
}
|
|
358
377
|
data.push({
|
|
359
378
|
durationMs: isError ? baseLatency * 0.1 : baseLatency,
|
|
@@ -440,6 +459,9 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
440
459
|
const waveListItems = history.map((h) => {
|
|
441
460
|
return `<div class="wave-item">Wave (${h.threads} VUs): P95 ${h.p95Latency.toFixed(1)}ms, Errors ${(h.errorRate * 100).toFixed(1)}%</div>`;
|
|
442
461
|
}).join("");
|
|
462
|
+
const estimatedMonthlyCost = (cards.throughput * 0.045 * 24 * 30).toFixed(2);
|
|
463
|
+
const recommendedCpuCores = Math.max(2, Math.ceil(cards.saturationKneePoint / 75));
|
|
464
|
+
const recommendedRamGb = recommendedCpuCores * 2;
|
|
443
465
|
let logClustersHtml = "";
|
|
444
466
|
if (semanticReport) {
|
|
445
467
|
const totalLogCount = semanticReport.clusters.reduce((sum, c) => sum + c.count, 0);
|
|
@@ -492,6 +514,26 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
492
514
|
</table>
|
|
493
515
|
</div>`;
|
|
494
516
|
}
|
|
517
|
+
const rightSizingHtml = `
|
|
518
|
+
<div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
|
|
519
|
+
<h3 style="color: #38bdf8; display: flex; align-items: center; gap: 0.5rem; font-size: 1.2rem;">
|
|
520
|
+
\u2601\uFE0F Infrastructure Right-Sizing & Cloud Cost Projections
|
|
521
|
+
</h3>
|
|
522
|
+
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-top: 1rem;">
|
|
523
|
+
<div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
524
|
+
<div class="card-title">Est. Monthly Cloud Cost</div>
|
|
525
|
+
<div class="card-value green">$${estimatedMonthlyCost} <span class="unit">/mo</span></div>
|
|
526
|
+
</div>
|
|
527
|
+
<div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
528
|
+
<div class="card-title">Recommended CPU Right-Sizing</div>
|
|
529
|
+
<div class="card-value purple">${recommendedCpuCores} <span class="unit">vCores</span></div>
|
|
530
|
+
</div>
|
|
531
|
+
<div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
532
|
+
<div class="card-title">Recommended Memory Allocation</div>
|
|
533
|
+
<div class="card-value orange">${recommendedRamGb} <span class="unit">GB RAM</span></div>
|
|
534
|
+
</div>
|
|
535
|
+
</div>
|
|
536
|
+
</div>`;
|
|
495
537
|
const htmlContent = `<!DOCTYPE html><html lang="en"><head>
|
|
496
538
|
<meta charset="UTF-8">
|
|
497
539
|
<title>Blaze Core Performance Report</title>
|
|
@@ -548,7 +590,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
548
590
|
<div class="container">
|
|
549
591
|
<div class="header">
|
|
550
592
|
<h1>\u{1F525} Blaze Core Performance Analysis</h1>
|
|
551
|
-
<div class="meta">Target Script: <code>${config.targetScript}</code
|
|
593
|
+
<div class="meta">Target Script: <code>${config.targetScript}</code> (Cold-Start Sieve Active)</div>
|
|
552
594
|
</div>
|
|
553
595
|
|
|
554
596
|
<div class="cards-wrapper">
|
|
@@ -588,7 +630,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
588
630
|
|
|
589
631
|
<div class="top-layout-grid">
|
|
590
632
|
<div class="verdict-box">
|
|
591
|
-
<div class="verdict-title">\u{1F916} AI Stress-Testing Agent Verdict</div>
|
|
633
|
+
<div class="verdict-title">\u{1F916} AI Stress-Testing Agent Verdict (Knee-Point: ${cards.saturationKneePoint} VUs)</div>
|
|
592
634
|
<div class="verdict-text">${verdictReason}</div>
|
|
593
635
|
<div class="verdict-waves">${waveListItems}</div>
|
|
594
636
|
</div>
|
|
@@ -658,6 +700,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
658
700
|
</tbody>
|
|
659
701
|
</table>
|
|
660
702
|
</div>
|
|
703
|
+
${rightSizingHtml}
|
|
661
704
|
${logClustersHtml}
|
|
662
705
|
</div>
|
|
663
706
|
|
|
Binary file
|