blaze-performance-tester 3.1.20 → 3.1.22
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 +95 -18
- package/dist/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -240,12 +240,21 @@ function calculateSeoImpactMetrics(avgLatencyMs) {
|
|
|
240
240
|
}
|
|
241
241
|
return { trafficLoss, status, crawlPenalty, color };
|
|
242
242
|
}
|
|
243
|
+
function computeHealthScoreValue(apdex, errorRate, p95Latency, maxAllowedLatency) {
|
|
244
|
+
const apdexComponent = apdex * 50;
|
|
245
|
+
const errorComponent = Math.max(0, 1 - errorRate) * 30;
|
|
246
|
+
const latencyRatio = p95Latency / maxAllowedLatency;
|
|
247
|
+
const latencyComponent = Math.max(0, 1 - Math.min(1, latencyRatio)) * 20;
|
|
248
|
+
return Math.min(100, Math.max(0, Math.round(apdexComponent + errorComponent + latencyComponent)));
|
|
249
|
+
}
|
|
243
250
|
async function runIntelligentAgenticStressTest(config) {
|
|
244
251
|
console.log("\u{1F680} Initializing Intelligent Autonomous Load Agent...");
|
|
245
252
|
const history = [];
|
|
246
253
|
let aggregateErrorLogs = [];
|
|
247
254
|
let lastRawRequests = [];
|
|
248
255
|
let total1xx = 0, total2xx = 0, total3xx = 0, total4xx = 0, total5xx = 0;
|
|
256
|
+
let totalRequestsAccumulator = 0;
|
|
257
|
+
const globalCodeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 0, 502: 0, 503: 0, 504: 0 };
|
|
249
258
|
let globalMetricsAccumulator = { dns: [], tcp: [], tls: [], ttfb: [], latencies: [], bandwidths: [] };
|
|
250
259
|
let currentThreads = Math.min(config.maxThreads, Math.max(5, Math.floor(config.maxThreads * 0.2)));
|
|
251
260
|
let baseStep = config.stepSize;
|
|
@@ -264,6 +273,11 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
264
273
|
total3xx += metrics.c3xx;
|
|
265
274
|
total4xx += metrics.c4xx;
|
|
266
275
|
total5xx += metrics.c5xx;
|
|
276
|
+
totalRequestsAccumulator += metrics.totalRequests;
|
|
277
|
+
const targetCodes = [400, 401, 403, 404, 429, 500, 502, 503, 504];
|
|
278
|
+
targetCodes.forEach((code) => {
|
|
279
|
+
globalCodeCounts[code] += metrics.codeCounts[code];
|
|
280
|
+
});
|
|
267
281
|
globalMetricsAccumulator.dns.push(metrics.avgDnsMs);
|
|
268
282
|
globalMetricsAccumulator.tcp.push(metrics.avgTcpMs);
|
|
269
283
|
globalMetricsAccumulator.tls.push(metrics.avgTlsMs);
|
|
@@ -320,29 +334,38 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
320
334
|
const analyzer = new LogAnalyzer();
|
|
321
335
|
semanticReport = analyzer.process(aggregateErrorLogs);
|
|
322
336
|
}
|
|
337
|
+
const finalState = history[history.length - 1] || { apdex: 0, errorRate: 0, p95Latency: 0, throughput: 0 };
|
|
338
|
+
const healthScore = computeHealthScoreValue(finalState.apdex, finalState.errorRate, finalState.p95Latency, config.maxAllowedLatencyMs);
|
|
323
339
|
const finalSummaryCards = {
|
|
324
|
-
apdex:
|
|
325
|
-
throughput:
|
|
340
|
+
apdex: finalState.apdex,
|
|
341
|
+
throughput: finalState.throughput,
|
|
326
342
|
bandwidth: mathUtils.mean(globalMetricsAccumulator.bandwidths),
|
|
327
343
|
ttfb: mathUtils.mean(globalMetricsAccumulator.ttfb),
|
|
328
344
|
dns: mathUtils.mean(globalMetricsAccumulator.dns),
|
|
329
345
|
tcp: mathUtils.mean(globalMetricsAccumulator.tcp),
|
|
330
346
|
tls: mathUtils.mean(globalMetricsAccumulator.tls),
|
|
331
347
|
stdDev: mathUtils.stdDev(globalMetricsAccumulator.latencies, mathUtils.mean(globalMetricsAccumulator.latencies)),
|
|
332
|
-
saturationKneePoint: saturationKneePoint ||
|
|
348
|
+
saturationKneePoint: saturationKneePoint || finalState.threads || 50,
|
|
349
|
+
healthScore
|
|
333
350
|
};
|
|
334
|
-
generateFinalAgentReport(history);
|
|
351
|
+
generateFinalAgentReport(history, healthScore);
|
|
335
352
|
if (config.isSeo) {
|
|
336
|
-
const finalLat =
|
|
353
|
+
const finalLat = finalState.avgLatency || finalSummaryCards.ttfb;
|
|
337
354
|
const seo = calculateSeoImpactMetrics(finalLat);
|
|
338
355
|
console.log(`\u{1F50E} [SEO Impact Report]: Target latency under stress (${finalLat.toFixed(1)}ms) triggers a predicted Search Visibility Loss of -${seo.trafficLoss}% [Status: ${seo.status}].`);
|
|
339
356
|
}
|
|
340
|
-
|
|
357
|
+
const breakdownRates = {};
|
|
358
|
+
Object.keys(globalCodeCounts).forEach((code) => {
|
|
359
|
+
breakdownRates[code] = totalRequestsAccumulator === 0 ? 0 : globalCodeCounts[code] / totalRequestsAccumulator * 100;
|
|
360
|
+
});
|
|
361
|
+
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests);
|
|
341
362
|
}
|
|
342
363
|
async function runStandardStressTest(config) {
|
|
343
364
|
console.log(`\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: ${config.threads} | Duration: ${config.durationSec}s]`);
|
|
344
365
|
const { metrics, rawErrors, rawRequests } = await runBlazeCoreEngine(config);
|
|
345
366
|
printMatrixDashboard(metrics, config.threads);
|
|
367
|
+
const healthScore = computeHealthScoreValue(metrics.apdexScore, metrics.errorRate, metrics.p95LatencyMs, config.maxAllowedLatencyMs);
|
|
368
|
+
console.log(`\u{1F49A} Unified Blaze Health Score: ${healthScore}/100`);
|
|
346
369
|
const history = [{
|
|
347
370
|
threads: config.threads,
|
|
348
371
|
avgLatency: metrics.avgLatencyMs,
|
|
@@ -369,7 +392,8 @@ async function runStandardStressTest(config) {
|
|
|
369
392
|
tcp: metrics.avgTcpMs,
|
|
370
393
|
tls: metrics.avgTlsMs,
|
|
371
394
|
stdDev: metrics.stdDevMs,
|
|
372
|
-
saturationKneePoint: config.threads
|
|
395
|
+
saturationKneePoint: config.threads,
|
|
396
|
+
healthScore
|
|
373
397
|
};
|
|
374
398
|
const isPassed = metrics.apdexScore >= config.targetApdex && metrics.errorRate <= config.targetErrorRate;
|
|
375
399
|
const verdictReason = isPassed ? "Static single-wave baseline checks concluded successfully without triggering health boundaries." : "Static verification loop completed with values exceeding defined quality thresholds.";
|
|
@@ -377,12 +401,17 @@ async function runStandardStressTest(config) {
|
|
|
377
401
|
const seo = calculateSeoImpactMetrics(metrics.avgLatencyMs);
|
|
378
402
|
console.log(`\u{1F50E} [SEO Impact Report]: Target latency (${metrics.avgLatencyMs.toFixed(1)}ms) triggers a predicted Search Visibility Loss of -${seo.trafficLoss}% [Status: ${seo.status}].`);
|
|
379
403
|
}
|
|
404
|
+
const breakdownRates = {};
|
|
405
|
+
Object.keys(metrics.codeCounts).forEach((code) => {
|
|
406
|
+
breakdownRates[code] = metrics.totalRequests === 0 ? 0 : metrics.codeCounts[code] / metrics.totalRequests * 100;
|
|
407
|
+
});
|
|
380
408
|
exportHtmlDashboard(history, config, verdictReason, semanticReport, {
|
|
381
409
|
total1xx: metrics.c1xx,
|
|
382
410
|
total2xx: metrics.c2xx,
|
|
383
411
|
total3xx: metrics.c3xx,
|
|
384
412
|
total4xx: metrics.c4xx,
|
|
385
|
-
total5xx: metrics.c5xx
|
|
413
|
+
total5xx: metrics.c5xx,
|
|
414
|
+
breakdownRates
|
|
386
415
|
}, finalSummaryCards, rawRequests);
|
|
387
416
|
}
|
|
388
417
|
function getFallbackClusterLogs() {
|
|
@@ -411,7 +440,8 @@ function generateSimulationData(threads, durationSec, maxAllowedLatencyMs) {
|
|
|
411
440
|
let errorMessage;
|
|
412
441
|
let statusCode = 200;
|
|
413
442
|
if (isError) {
|
|
414
|
-
|
|
443
|
+
const targetResponseCodes = [400, 401, 403, 404, 429, 500, 502, 503, 504];
|
|
444
|
+
statusCode = targetResponseCodes[Math.floor(Math.random() * targetResponseCodes.length)];
|
|
415
445
|
errorMessage = errorPool[Math.floor(Math.random() * errorPool.length)];
|
|
416
446
|
}
|
|
417
447
|
data.push({
|
|
@@ -437,12 +467,16 @@ function processMetricsTelemetry(requests, durationSec) {
|
|
|
437
467
|
const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
|
|
438
468
|
const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
|
|
439
469
|
let c1xx = 0, c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
|
|
470
|
+
const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 502, 502: 0, 503: 0, 504: 0 };
|
|
440
471
|
requests.forEach((r) => {
|
|
441
472
|
if (r.statusCode >= 100 && r.statusCode < 200) c1xx++;
|
|
442
473
|
else if (r.statusCode >= 200 && r.statusCode < 300) c2xx++;
|
|
443
474
|
else if (r.statusCode >= 300 && r.statusCode < 400) c3xx++;
|
|
444
475
|
else if (r.statusCode >= 400 && r.statusCode < 500) c4xx++;
|
|
445
476
|
else if (r.statusCode >= 500) c5xx++;
|
|
477
|
+
if (r.statusCode in codeCounts) {
|
|
478
|
+
codeCounts[r.statusCode]++;
|
|
479
|
+
}
|
|
446
480
|
});
|
|
447
481
|
const errorCount = c4xx + c5xx;
|
|
448
482
|
const errorRate = totalRequests === 0 ? 0 : errorCount / totalRequests;
|
|
@@ -468,7 +502,8 @@ function processMetricsTelemetry(requests, durationSec) {
|
|
|
468
502
|
avgTcpMs,
|
|
469
503
|
avgTlsMs,
|
|
470
504
|
avgTtfbMs,
|
|
471
|
-
bandwidthMb
|
|
505
|
+
bandwidthMb,
|
|
506
|
+
codeCounts
|
|
472
507
|
};
|
|
473
508
|
}
|
|
474
509
|
function printMatrixDashboard(m, threads) {
|
|
@@ -479,7 +514,7 @@ function printMatrixDashboard(m, threads) {
|
|
|
479
514
|
console.log(`| ${pad(threads, 7)} | ${pad(m.totalRequests, 9)} | ${pad(m.avgLatencyMs.toFixed(1) + "ms", 11)} | ${pad(m.p95LatencyMs.toFixed(1) + "ms", 11)} | ${pad(m.requestsPerSecond.toFixed(0) + "/s", 10)} | ${pad((m.errorRate * 100).toFixed(2) + "%", 10)} | ${pad(m.apdexScore.toFixed(2), 9)} |`);
|
|
480
515
|
console.log(`-----------------------------------------------------------------------------------------`);
|
|
481
516
|
}
|
|
482
|
-
function generateFinalAgentReport(history) {
|
|
517
|
+
function generateFinalAgentReport(history, score) {
|
|
483
518
|
if (history.length === 0) return;
|
|
484
519
|
const peakThroughput = Math.max(...history.map((h) => h.throughput));
|
|
485
520
|
const cleanRuns = history.filter((h) => h.apdex >= 0.85 && h.errorRate <= 0.01);
|
|
@@ -487,6 +522,7 @@ function generateFinalAgentReport(history) {
|
|
|
487
522
|
console.log("\n=======================================================");
|
|
488
523
|
console.log("\u{1F9E0} INTELLIGENT AUTONOMOUS LOAD AGENT FINAL REPORT");
|
|
489
524
|
console.log("=======================================================");
|
|
525
|
+
console.log(`\u{1F49A} Unified Blaze Health Score : ${score}/100`);
|
|
490
526
|
console.log(`\u{1F3C6} Recommended Max Safe Concurrency : ${maxSafeThreads} allocation threads`);
|
|
491
527
|
console.log(`\u{1F4A5} Infrastructure Failure Boundary : ${history[history.length - 1].threads} concurrency allocation`);
|
|
492
528
|
console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
|
|
@@ -577,8 +613,8 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
577
613
|
<div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b; text-align: center;">
|
|
578
614
|
<div class="card-title" style="color: #94a3b8;">Est. Organic Traffic Loss</div>
|
|
579
615
|
<div style="font-size: 2rem; font-weight: bold; color: ${seoMetrics.color};">
|
|
580
|
-
|
|
581
|
-
</div>
|
|
616
|
+
${seoMetrics.trafficLoss > 0 ? "-" : ""}${seoMetrics.trafficLoss}%
|
|
617
|
+
</div>
|
|
582
618
|
<div style="font-size: 0.8rem; color: #64748b; margin-top: 0.25rem;">compared to 200ms sweet-spot</div>
|
|
583
619
|
</div>
|
|
584
620
|
<div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
@@ -637,6 +673,18 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
637
673
|
</div>
|
|
638
674
|
</div>
|
|
639
675
|
</div>`;
|
|
676
|
+
const breakdownRates = responseMatrix.breakdownRates || {};
|
|
677
|
+
const breakdownGridHtml = [400, 401, 403, 404, 429, 500, 502, 503, 504].map((code) => {
|
|
678
|
+
const rate = breakdownRates[code] || 0;
|
|
679
|
+
const displayColor = rate > 0 ? code >= 500 ? "#f87171" : "#fde047" : "#64748b";
|
|
680
|
+
return `
|
|
681
|
+
<div style="background: #090d16; border: 1px solid #1e293b; border-radius: 4px; padding: 0.4rem 0.2rem; text-align: center;">
|
|
682
|
+
<div style="font-size: 0.7rem; color: #64748b; font-weight: bold;">${code}</div>
|
|
683
|
+
<div style="font-size: 0.85rem; font-weight: bold; color: ${displayColor};">${rate.toFixed(2)}%</div>
|
|
684
|
+
</div>
|
|
685
|
+
`;
|
|
686
|
+
}).join("");
|
|
687
|
+
const gaugeColor = cards.healthScore >= 90 ? "#10b981" : cards.healthScore >= 70 ? "#f59e0b" : "#ef4444";
|
|
640
688
|
const htmlContent = `<!DOCTYPE html><html lang="en"><head>
|
|
641
689
|
<meta charset="UTF-8">
|
|
642
690
|
<title>Blaze Core Performance Report</title>
|
|
@@ -658,13 +706,16 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
658
706
|
.card-value.purple { color: #a855f7; }
|
|
659
707
|
.card-subtext { font-size: 0.8rem; color: #10b981; font-weight: 500; margin-left: 0.4rem; display: inline-block; }
|
|
660
708
|
|
|
661
|
-
.top-layout-grid { display: grid; grid-template-columns: 1fr
|
|
709
|
+
.top-layout-grid { display: grid; grid-template-columns: 1fr 280px 380px; gap: 1.5rem; margin-bottom: 2rem; }
|
|
662
710
|
.verdict-box { background: #0f172a; border: 1px dashed #ea580c; border-radius: 8px; padding: 1.25rem; }
|
|
663
711
|
.verdict-title { text-transform: uppercase; font-size: 0.85rem; font-weight: 700; color: #f97316; margin-bottom: 0.5rem; }
|
|
664
712
|
.verdict-text { font-size: 0.95rem; line-height: 1.5; color: #e2e8f0; margin-bottom: 0.75rem; }
|
|
665
713
|
.verdict-waves { background: #1f2937; border-radius: 6px; padding: 0.75rem 1rem; font-family: monospace; color: #9ca3af; font-size: 0.9rem; }
|
|
666
714
|
.wave-item { margin: 0.25rem 0; }
|
|
667
715
|
|
|
716
|
+
.gauge-container-box { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.25rem; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; }
|
|
717
|
+
.gauge-title { font-size: 0.85rem; font-weight: bold; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 1rem; }
|
|
718
|
+
|
|
668
719
|
.matrix-box { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.25rem; }
|
|
669
720
|
.matrix-title { font-size: 1.1rem; font-weight: bold; color: #ffffff; margin-bottom: 1rem; }
|
|
670
721
|
.matrix-box .matrix-row { display: flex; justify-content: space-between; align-items: center; padding: 0.6rem 0; border-bottom: 1px solid #1e293b; }
|
|
@@ -739,6 +790,26 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
739
790
|
<div class="verdict-waves">${waveListItems}</div>
|
|
740
791
|
</div>
|
|
741
792
|
|
|
793
|
+
<!-- IMPLEMENTED CARD FEATURE 76: Executive Health Gauges Panel -->
|
|
794
|
+
<div class="gauge-container-box">
|
|
795
|
+
<div class="gauge-title">Blaze Run Health Score</div>
|
|
796
|
+
<div style="position: relative; width: 140px; height: 140px; display: flex; align-items: center; justify-content: center;">
|
|
797
|
+
<svg width="140" height="140" viewBox="0 0 140 140" style="transform: rotate(-90deg);">
|
|
798
|
+
<circle cx="70" cy="70" r="58" stroke="#1e293b" stroke-width="12" fill="transparent"/>
|
|
799
|
+
<circle cx="70" cy="70" r="58" stroke="${gaugeColor}" stroke-width="12" fill="transparent"
|
|
800
|
+
stroke-dasharray="364.4" stroke-dashoffset="${364.4 - 364.4 * cards.healthScore / 100}"
|
|
801
|
+
stroke-linecap="round" style="transition: stroke-dashoffset 1s ease-out;"/>
|
|
802
|
+
</svg>
|
|
803
|
+
<div style="position: absolute; text-align: center;">
|
|
804
|
+
<div style="font-size: 2.2rem; font-weight: 800; color: #ffffff; line-height: 1;">${cards.healthScore}</div>
|
|
805
|
+
<div style="font-size: 0.75rem; color: #64748b; font-weight: bold; margin-top: 0.2rem; text-transform: uppercase;">/ 100</div>
|
|
806
|
+
</div>
|
|
807
|
+
</div>
|
|
808
|
+
<div style="margin-top: 0.75rem; font-size: 0.8rem; color: #94a3b8; font-weight: 500;">
|
|
809
|
+
Composite Run Quality Engine Rating
|
|
810
|
+
</div>
|
|
811
|
+
</div>
|
|
812
|
+
|
|
742
813
|
<div class="matrix-box">
|
|
743
814
|
<div class="matrix-title">\u{1F4CB} HTTP Response Matrix</div>
|
|
744
815
|
<div class="matrix-row">
|
|
@@ -761,6 +832,13 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
761
832
|
<div class="matrix-label">Server Error <span class="matrix-badge badge-5xx">5xx</span></div>
|
|
762
833
|
<div class="matrix-value">${responseMatrix.total5xx}</div>
|
|
763
834
|
</div>
|
|
835
|
+
|
|
836
|
+
<div class="matrix-title" style="margin-top: 1.5rem; font-size: 0.85rem; border-top: 1px solid #1e293b; padding-top: 1rem; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.05em;">
|
|
837
|
+
\u{1F522} HTTP Status Code Breakdown Rate
|
|
838
|
+
</div>
|
|
839
|
+
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; margin-top: 0.5rem;">
|
|
840
|
+
${breakdownGridHtml}
|
|
841
|
+
</div>
|
|
764
842
|
</div>
|
|
765
843
|
</div>
|
|
766
844
|
|
|
@@ -833,7 +911,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
833
911
|
const baseThroughput = ${cards.throughput};
|
|
834
912
|
const baseLatency = ${cards.ttfb};
|
|
835
913
|
|
|
836
|
-
// Live Concurrency Adjuster interactive client logic
|
|
837
914
|
const slider = document.getElementById('concurrencySlider');
|
|
838
915
|
const sliderVal = document.getElementById('sliderValue');
|
|
839
916
|
const simThroughput = document.getElementById('simThroughput');
|
|
@@ -939,9 +1016,9 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
939
1016
|
responsive: true,
|
|
940
1017
|
maintainAspectRatio: false,
|
|
941
1018
|
plugins: {
|
|
942
|
-
legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } }
|
|
943
|
-
|
|
944
|
-
|
|
1019
|
+
legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } },
|
|
1020
|
+
cutout: '65%'
|
|
1021
|
+
}
|
|
945
1022
|
}
|
|
946
1023
|
});
|
|
947
1024
|
|
|
Binary file
|