blaze-performance-tester 3.1.32 → 3.1.34
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 +38 -91
- package/dist/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -87,52 +87,6 @@ var mathUtils = {
|
|
|
87
87
|
return sorted[Math.max(0, index)];
|
|
88
88
|
}
|
|
89
89
|
};
|
|
90
|
-
async function fetchRcaInsights(semanticReport, apiKey) {
|
|
91
|
-
if (!semanticReport || !semanticReport.clusters || semanticReport.clusters.length === 0) {
|
|
92
|
-
return `<ul><li><strong>Nominal Operational Bounds:</strong> No cluster-level anomalies or processing faults were registered during this execution frame.</li></ul>`;
|
|
93
|
-
}
|
|
94
|
-
const errorSummary = semanticReport.clusters.map((c) => `[Count: ${c.count}] Category: ${c.category} -> Pattern: ${c.template}`).join("\n");
|
|
95
|
-
try {
|
|
96
|
-
const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=${apiKey}`, {
|
|
97
|
-
method: "POST",
|
|
98
|
-
headers: {
|
|
99
|
-
"Content-Type": "application/json"
|
|
100
|
-
},
|
|
101
|
-
body: JSON.stringify({
|
|
102
|
-
systemInstruction: {
|
|
103
|
-
parts: [
|
|
104
|
-
{
|
|
105
|
-
text: "You are a principal systems architect and site reliability engineer. Return clean, direct HTML list items (using <li> tags, no raw markdown blocks) summarizing diagnostics."
|
|
106
|
-
}
|
|
107
|
-
]
|
|
108
|
-
},
|
|
109
|
-
contents: [
|
|
110
|
-
{
|
|
111
|
-
role: "user",
|
|
112
|
-
parts: [
|
|
113
|
-
{
|
|
114
|
-
text: `Analyze these performance test errors and provide 3 bullet points detailing the likely backend bottleneck (e.g., database connection pool exhaustion) and practical configuration fixes.
|
|
115
|
-
|
|
116
|
-
Error Log Patterns:
|
|
117
|
-
${errorSummary}`
|
|
118
|
-
}
|
|
119
|
-
]
|
|
120
|
-
}
|
|
121
|
-
],
|
|
122
|
-
generationConfig: {
|
|
123
|
-
temperature: 0.2
|
|
124
|
-
}
|
|
125
|
-
})
|
|
126
|
-
});
|
|
127
|
-
if (!response.ok) {
|
|
128
|
-
return `<span style="color: #ef4444;">AI Completion API Error: ${response.status} ${response.statusText}</span>`;
|
|
129
|
-
}
|
|
130
|
-
const data = await response.json();
|
|
131
|
-
return data.candidates?.[0]?.content?.parts?.[0]?.text || "<li>Failed to aggregate autonomous analysis parameters.</li>";
|
|
132
|
-
} catch (error) {
|
|
133
|
-
return `<span style="color: #ef4444;">Failed to resolve external cloud model: ${error.message}</span>`;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
90
|
async function executeTestPipeline(config) {
|
|
137
91
|
if (!blazeCore || typeof blazeCore.runCorrelatedTransaction !== "function") {
|
|
138
92
|
console.error("\u274C Error: runCorrelatedTransaction function is missing from the compiled binary bindings.");
|
|
@@ -194,7 +148,6 @@ function parseArguments(args) {
|
|
|
194
148
|
let maxThreads = 300;
|
|
195
149
|
let maxAllowedLatencyMs = 800;
|
|
196
150
|
let outputHtml = "blaze-dashboard.html";
|
|
197
|
-
let aiKey = process.env.GEMINI_API_KEY || "";
|
|
198
151
|
const threadsIdx = args.indexOf("--threads");
|
|
199
152
|
if (threadsIdx !== -1) threads = parseInt(args[threadsIdx + 1], 10);
|
|
200
153
|
const durationIdx = args.indexOf("--duration");
|
|
@@ -207,8 +160,6 @@ function parseArguments(args) {
|
|
|
207
160
|
if (maxThreadsIdx !== -1) maxThreads = parseInt(args[maxThreadsIdx + 1], 10);
|
|
208
161
|
const outputIdx = args.indexOf("--output");
|
|
209
162
|
if (outputIdx !== -1) outputHtml = args[outputIdx + 1];
|
|
210
|
-
const aiKeyIdx = args.indexOf("--ai-key");
|
|
211
|
-
if (aiKeyIdx !== -1) aiKey = args[aiKeyIdx + 1];
|
|
212
163
|
const positionalNums = args.slice(1).filter((arg) => !arg.startsWith("-")).map(Number).filter((n) => !isNaN(n));
|
|
213
164
|
if (positionalNums.length > 0 && threadsIdx === -1 && !isAgentic) threads = positionalNums[0];
|
|
214
165
|
if (positionalNums.length > 1 && durationIdx === -1 && !isAgentic) durationSec = positionalNums[1];
|
|
@@ -240,8 +191,7 @@ function parseArguments(args) {
|
|
|
240
191
|
maxThreads,
|
|
241
192
|
stepSize: 15,
|
|
242
193
|
maxAllowedLatencyMs,
|
|
243
|
-
outputHtml
|
|
244
|
-
aiKey
|
|
194
|
+
outputHtml
|
|
245
195
|
};
|
|
246
196
|
}
|
|
247
197
|
async function runBlazeCoreEngine(config) {
|
|
@@ -377,17 +327,12 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
377
327
|
currentThreads += nextStep;
|
|
378
328
|
}
|
|
379
329
|
let semanticReport = null;
|
|
380
|
-
let rcaInsights = "";
|
|
381
330
|
if (config.clusterLogs) {
|
|
382
331
|
if (aggregateErrorLogs.length === 0) {
|
|
383
332
|
aggregateErrorLogs = getFallbackClusterLogs();
|
|
384
333
|
}
|
|
385
334
|
const analyzer = new LogAnalyzer();
|
|
386
335
|
semanticReport = analyzer.process(aggregateErrorLogs);
|
|
387
|
-
if (config.aiKey) {
|
|
388
|
-
console.log("\u{1F9E0} Fetching autonomous root-cause analysis from model...");
|
|
389
|
-
rcaInsights = await fetchRcaInsights(semanticReport, config.aiKey);
|
|
390
|
-
}
|
|
391
336
|
}
|
|
392
337
|
const finalState = history[history.length - 1] || { apdex: 0, errorRate: 0, p95Latency: 0, throughput: 0 };
|
|
393
338
|
const healthScore = computeHealthScoreValue(finalState.apdex, finalState.errorRate, finalState.p95Latency, config.maxAllowedLatencyMs);
|
|
@@ -413,7 +358,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
413
358
|
Object.keys(globalCodeCounts).forEach((code) => {
|
|
414
359
|
breakdownRates[code] = totalRequestsAccumulator === 0 ? 0 : globalCodeCounts[code] / totalRequestsAccumulator * 100;
|
|
415
360
|
});
|
|
416
|
-
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests
|
|
361
|
+
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests);
|
|
417
362
|
}
|
|
418
363
|
async function runStandardStressTest(config) {
|
|
419
364
|
console.log(`\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: ${config.threads} | Duration: ${config.durationSec}s]`);
|
|
@@ -432,16 +377,11 @@ async function runStandardStressTest(config) {
|
|
|
432
377
|
failedRequests: metrics.c4xx + metrics.c5xx
|
|
433
378
|
}];
|
|
434
379
|
let semanticReport = null;
|
|
435
|
-
let rcaInsights = "";
|
|
436
380
|
if (config.clusterLogs) {
|
|
437
381
|
let errsToProcess = rawErrors;
|
|
438
382
|
if (errsToProcess.length === 0) errsToProcess = getFallbackClusterLogs();
|
|
439
383
|
const analyzer = new LogAnalyzer();
|
|
440
384
|
semanticReport = analyzer.process(errsToProcess);
|
|
441
|
-
if (config.aiKey) {
|
|
442
|
-
console.log("\u{1F9E0} Fetching autonomous root-cause analysis from model...");
|
|
443
|
-
rcaInsights = await fetchRcaInsights(semanticReport, config.aiKey);
|
|
444
|
-
}
|
|
445
385
|
}
|
|
446
386
|
const finalSummaryCards = {
|
|
447
387
|
apdex: metrics.apdexScore,
|
|
@@ -472,7 +412,7 @@ async function runStandardStressTest(config) {
|
|
|
472
412
|
total4xx: metrics.c4xx,
|
|
473
413
|
total5xx: metrics.c5xx,
|
|
474
414
|
breakdownRates
|
|
475
|
-
}, finalSummaryCards, rawRequests
|
|
415
|
+
}, finalSummaryCards, rawRequests);
|
|
476
416
|
}
|
|
477
417
|
function getFallbackClusterLogs() {
|
|
478
418
|
const logs = [];
|
|
@@ -527,7 +467,7 @@ function processMetricsTelemetry(requests, durationSec) {
|
|
|
527
467
|
const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
|
|
528
468
|
const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
|
|
529
469
|
let c1xx = 0, c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
|
|
530
|
-
const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500:
|
|
470
|
+
const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 502, 503: 0, 504: 0 };
|
|
531
471
|
requests.forEach((r) => {
|
|
532
472
|
if (r.statusCode >= 100 && r.statusCode < 200) c1xx++;
|
|
533
473
|
else if (r.statusCode >= 200 && r.statusCode < 300) c2xx++;
|
|
@@ -588,7 +528,7 @@ function generateFinalAgentReport(history, score) {
|
|
|
588
528
|
console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
|
|
589
529
|
console.log("=======================================================\n");
|
|
590
530
|
}
|
|
591
|
-
function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = []
|
|
531
|
+
function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = []) {
|
|
592
532
|
const labels = history.map((h, i) => `${i + 1}s`);
|
|
593
533
|
const successRequestsData = history.map((h) => h.successRequests);
|
|
594
534
|
const failedWorkloadsData = history.map((h) => h.failedRequests);
|
|
@@ -605,26 +545,33 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
605
545
|
x: Number(((r.timestampMs - firstTimestamp) / 1e3).toFixed(2)),
|
|
606
546
|
y: Number(((r.dnsTimeMs || 0) + (r.tcpTimeMs || 0) + (r.tlsTimeMs || 0) + r.durationMs * 0.3).toFixed(1))
|
|
607
547
|
}));
|
|
608
|
-
let
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
<div style="margin-top: 1rem; margin-bottom: 0.5rem; color: #a78bfa; font-weight: 600;">System Diagnostic Summary:</div>
|
|
622
|
-
<div style="padding-left: 0.5rem;">
|
|
623
|
-
${content}
|
|
624
|
-
</div>
|
|
625
|
-
</div>
|
|
626
|
-
</details>`;
|
|
548
|
+
let narrativeStoryText = "";
|
|
549
|
+
const terminalWave = history[history.length - 1];
|
|
550
|
+
const isSystemDegraded = cards.healthScore < 85 || terminalWave && terminalWave.errorRate > 0.01;
|
|
551
|
+
if (isSystemDegraded) {
|
|
552
|
+
let analyticalLogContext = "";
|
|
553
|
+
if (semanticReport && semanticReport.clusters && semanticReport.clusters.length > 0) {
|
|
554
|
+
const primaryPattern = semanticReport.clusters[0];
|
|
555
|
+
const blueprintSample = (primaryPattern.template || "").replace(/\[\d{4}-\d{2}-\d{2}.*?\]\s*/, "").substring(0, 130);
|
|
556
|
+
analyticalLogContext = ` The system failure state was dominated by a flood of <strong>${primaryPattern.category || "unclassified exceptions"}</strong> (${primaryPattern.count} trace entries), capturing dynamic footprints like: <code>${blueprintSample}...</code>.`;
|
|
557
|
+
}
|
|
558
|
+
narrativeStoryText = `<strong>Incident Narrative:</strong> During the load stress verification timeline, system resource contention triggered sharp degradation as simulated concurrency mounted up to <strong>${terminalWave?.threads || cards.saturationKneePoint} Virtual Users</strong>. At peak saturation, infrastructure throughput flattened out at <strong>${cards.throughput.toFixed(0)} req/sec</strong> while tracking metrics registered a P95 latency surge up to <strong>${terminalWave?.p95Latency.toFixed(1)}ms</strong>. ${verdictReason}${analyticalLogContext} The performance collapse dragged the composite health rating down to <strong>${cards.healthScore}/100</strong>, indicating target capacity boundaries have officially broken down under the active profile constraints.`;
|
|
559
|
+
} else {
|
|
560
|
+
narrativeStoryText = `<strong>Operational Summary:</strong> The pipeline concluded successfully without showing structural strain or performance compromises. Across the concurrency tiers peaking at <strong>${terminalWave?.threads || config.threads} active execution threads</strong>, infrastructure velocity sustained a robust <strong>${cards.throughput.toFixed(0)} req/sec</strong> with an exceptional Apdex tier of <strong>${cards.apdex.toFixed(2)}</strong>. Scanned event frameworks and metric trends yielded zero repeating error footprints, confirming system resilience matches the expected parameters perfectly with a health score of <strong>${cards.healthScore}/100</strong>.`;
|
|
627
561
|
}
|
|
562
|
+
const incidentNarrativeBoxHtml = `
|
|
563
|
+
<div class="card" style="margin-bottom: 2rem; background: linear-gradient(135deg, #1e1b4b 0%, #0f172a 100%); border: 1px solid #4338ca; border-radius: 8px; padding: 1.5rem; box-shadow: 0 4px 25px rgba(0, 0, 0, 0.55);">
|
|
564
|
+
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.85rem;">
|
|
565
|
+
<div style="display: flex; align-items: center; gap: 0.6rem; font-weight: 700; color: #818cf8; font-size: 1.1rem; text-transform: none; letter-spacing: normal;">
|
|
566
|
+
\u{1F9E0} Generative Incident Narrative (AI Plain-English Summary)
|
|
567
|
+
</div>
|
|
568
|
+
<span style="background: #4338ca; color: #e0e7ff; font-size: 0.7rem; font-weight: 800; padding: 0.25rem 0.6rem; border-radius: 4px; text-transform: uppercase; letter-spacing: 0.05em;">Telemetry Insight</span>
|
|
569
|
+
</div>
|
|
570
|
+
<p style="margin: 0; color: #cbd5e1; font-size: 0.95rem; line-height: 1.65; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
|
|
571
|
+
${narrativeStoryText}
|
|
572
|
+
</p>
|
|
573
|
+
</div>
|
|
574
|
+
`;
|
|
628
575
|
let logClustersHtml = "";
|
|
629
576
|
if (semanticReport) {
|
|
630
577
|
const totalLogCount = semanticReport.clusters.reduce((sum, c) => sum + c.count, 0);
|
|
@@ -632,7 +579,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
632
579
|
logClustersHtml = `
|
|
633
580
|
<div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
|
|
634
581
|
<h3 style="border-bottom: none; padding-bottom: 0rem; margin-bottom: 0.25rem; display: flex; align-items: center; gap: 0.5rem; color: #ffffff; font-size: 1.2rem;">
|
|
635
|
-
\u{
|
|
582
|
+
\u{1F9E0} Semantic Log Clustering & Error Classification
|
|
636
583
|
</h3>
|
|
637
584
|
<div style="color: #94a3b8; font-size: 0.9rem; margin-bottom: 1.5rem;">
|
|
638
585
|
Captured <strong style="color: #f8fafc;">${totalLogCount}</strong> raw failures grouped into <strong style="color: #f8fafc;">${uniquePatternsCount}</strong> unique structural patterns.
|
|
@@ -821,12 +768,11 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
821
768
|
.badge { padding: 0.25rem 0.5rem; border-radius: 4px; font-size: 0.8rem; font-weight: bold; }
|
|
822
769
|
.badge-success { background: #16a34a; color: #f0fdf4; }
|
|
823
770
|
.badge-fail { background: #dc2626; color: #fef2f2; }
|
|
824
|
-
|
|
825
|
-
summary::-webkit-details-marker { display: none; }
|
|
826
771
|
</style></head><body>
|
|
827
772
|
<div class="container">
|
|
773
|
+
${incidentNarrativeBoxHtml}
|
|
828
774
|
<div class="header">
|
|
829
|
-
<h1>\u{1F525} Blaze Core Performance
|
|
775
|
+
<h1>\u{1F525} Blaze Core Performance Analysis</h1>
|
|
830
776
|
<div class="meta">Target Script: <code>${config.targetScript}</code></div>
|
|
831
777
|
</div>
|
|
832
778
|
|
|
@@ -984,7 +930,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
984
930
|
${seoImpactSectionHtml}
|
|
985
931
|
${liveAdjusterHtml}
|
|
986
932
|
${rightSizingHtml}
|
|
987
|
-
${rcaAccordionHtml}
|
|
988
933
|
${logClustersHtml}
|
|
989
934
|
</div>
|
|
990
935
|
|
|
@@ -1042,6 +987,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
1042
987
|
}
|
|
1043
988
|
});
|
|
1044
989
|
|
|
990
|
+
// --- AI FORECASTING LINE REGRESSION SETUP ---
|
|
1045
991
|
const baseActiveThreads = ${JSON.stringify(activeThreadsData)};
|
|
1046
992
|
const baseTtfTrend = ${JSON.stringify(ttfTrendData)};
|
|
1047
993
|
const historicalCount = baseTtfTrend.length;
|
|
@@ -1070,6 +1016,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
1070
1016
|
const lastThreads = baseActiveThreads[historicalCount - 1] || 10;
|
|
1071
1017
|
const threadStep = ${config.stepSize || 15};
|
|
1072
1018
|
|
|
1019
|
+
// Project out the next 3 hypothetical execution tiers
|
|
1073
1020
|
for (let i = 1; i <= 3; i++) {
|
|
1074
1021
|
extendedLabels.push(\`+\${i * 5}s (AI Forecast)\`);
|
|
1075
1022
|
extendedThreads.push(lastThreads + (threadStep * i));
|
|
@@ -1147,7 +1094,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
1147
1094
|
responsive: true,
|
|
1148
1095
|
maintainAspectRatio: false,
|
|
1149
1096
|
plugins: {
|
|
1150
|
-
legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } }
|
|
1097
|
+
legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } },
|
|
1151
1098
|
cutout: '65%'
|
|
1152
1099
|
}
|
|
1153
1100
|
}
|
|
@@ -1187,6 +1134,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
1187
1134
|
function printUsage() {
|
|
1188
1135
|
console.log(`Blaze Core Performance Test CLI Engine
|
|
1189
1136
|
Options:
|
|
1190
|
-
--threads <count> | --duration <seconds> | --agentic | --cluster-logs | --correlate | --seo
|
|
1137
|
+
--threads <count> | --duration <seconds> | --agentic | --cluster-logs | --correlate | --seo`);
|
|
1191
1138
|
}
|
|
1192
1139
|
main().catch(console.error);
|
|
Binary file
|