blaze-performance-tester 3.1.28 → 3.1.30
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 +90 -9
- package/dist/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -87,6 +87,52 @@ 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
|
+
}
|
|
90
136
|
async function executeTestPipeline(config) {
|
|
91
137
|
if (!blazeCore || typeof blazeCore.runCorrelatedTransaction !== "function") {
|
|
92
138
|
console.error("\u274C Error: runCorrelatedTransaction function is missing from the compiled binary bindings.");
|
|
@@ -148,6 +194,7 @@ function parseArguments(args) {
|
|
|
148
194
|
let maxThreads = 300;
|
|
149
195
|
let maxAllowedLatencyMs = 800;
|
|
150
196
|
let outputHtml = "blaze-dashboard.html";
|
|
197
|
+
let aiKey = process.env.GEMINI_API_KEY || "";
|
|
151
198
|
const threadsIdx = args.indexOf("--threads");
|
|
152
199
|
if (threadsIdx !== -1) threads = parseInt(args[threadsIdx + 1], 10);
|
|
153
200
|
const durationIdx = args.indexOf("--duration");
|
|
@@ -160,6 +207,8 @@ function parseArguments(args) {
|
|
|
160
207
|
if (maxThreadsIdx !== -1) maxThreads = parseInt(args[maxThreadsIdx + 1], 10);
|
|
161
208
|
const outputIdx = args.indexOf("--output");
|
|
162
209
|
if (outputIdx !== -1) outputHtml = args[outputIdx + 1];
|
|
210
|
+
const aiKeyIdx = args.indexOf("--ai-key");
|
|
211
|
+
if (aiKeyIdx !== -1) aiKey = args[aiKeyIdx + 1];
|
|
163
212
|
const positionalNums = args.slice(1).filter((arg) => !arg.startsWith("-")).map(Number).filter((n) => !isNaN(n));
|
|
164
213
|
if (positionalNums.length > 0 && threadsIdx === -1 && !isAgentic) threads = positionalNums[0];
|
|
165
214
|
if (positionalNums.length > 1 && durationIdx === -1 && !isAgentic) durationSec = positionalNums[1];
|
|
@@ -191,7 +240,8 @@ function parseArguments(args) {
|
|
|
191
240
|
maxThreads,
|
|
192
241
|
stepSize: 15,
|
|
193
242
|
maxAllowedLatencyMs,
|
|
194
|
-
outputHtml
|
|
243
|
+
outputHtml,
|
|
244
|
+
aiKey
|
|
195
245
|
};
|
|
196
246
|
}
|
|
197
247
|
async function runBlazeCoreEngine(config) {
|
|
@@ -327,12 +377,17 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
327
377
|
currentThreads += nextStep;
|
|
328
378
|
}
|
|
329
379
|
let semanticReport = null;
|
|
380
|
+
let rcaInsights = "";
|
|
330
381
|
if (config.clusterLogs) {
|
|
331
382
|
if (aggregateErrorLogs.length === 0) {
|
|
332
383
|
aggregateErrorLogs = getFallbackClusterLogs();
|
|
333
384
|
}
|
|
334
385
|
const analyzer = new LogAnalyzer();
|
|
335
386
|
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
|
+
}
|
|
336
391
|
}
|
|
337
392
|
const finalState = history[history.length - 1] || { apdex: 0, errorRate: 0, p95Latency: 0, throughput: 0 };
|
|
338
393
|
const healthScore = computeHealthScoreValue(finalState.apdex, finalState.errorRate, finalState.p95Latency, config.maxAllowedLatencyMs);
|
|
@@ -358,7 +413,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
358
413
|
Object.keys(globalCodeCounts).forEach((code) => {
|
|
359
414
|
breakdownRates[code] = totalRequestsAccumulator === 0 ? 0 : globalCodeCounts[code] / totalRequestsAccumulator * 100;
|
|
360
415
|
});
|
|
361
|
-
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests);
|
|
416
|
+
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests, rcaInsights);
|
|
362
417
|
}
|
|
363
418
|
async function runStandardStressTest(config) {
|
|
364
419
|
console.log(`\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: ${config.threads} | Duration: ${config.durationSec}s]`);
|
|
@@ -377,11 +432,16 @@ async function runStandardStressTest(config) {
|
|
|
377
432
|
failedRequests: metrics.c4xx + metrics.c5xx
|
|
378
433
|
}];
|
|
379
434
|
let semanticReport = null;
|
|
435
|
+
let rcaInsights = "";
|
|
380
436
|
if (config.clusterLogs) {
|
|
381
437
|
let errsToProcess = rawErrors;
|
|
382
438
|
if (errsToProcess.length === 0) errsToProcess = getFallbackClusterLogs();
|
|
383
439
|
const analyzer = new LogAnalyzer();
|
|
384
440
|
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
|
+
}
|
|
385
445
|
}
|
|
386
446
|
const finalSummaryCards = {
|
|
387
447
|
apdex: metrics.apdexScore,
|
|
@@ -412,7 +472,7 @@ async function runStandardStressTest(config) {
|
|
|
412
472
|
total4xx: metrics.c4xx,
|
|
413
473
|
total5xx: metrics.c5xx,
|
|
414
474
|
breakdownRates
|
|
415
|
-
}, finalSummaryCards, rawRequests);
|
|
475
|
+
}, finalSummaryCards, rawRequests, rcaInsights);
|
|
416
476
|
}
|
|
417
477
|
function getFallbackClusterLogs() {
|
|
418
478
|
const logs = [];
|
|
@@ -528,7 +588,7 @@ function generateFinalAgentReport(history, score) {
|
|
|
528
588
|
console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
|
|
529
589
|
console.log("=======================================================\n");
|
|
530
590
|
}
|
|
531
|
-
function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = []) {
|
|
591
|
+
function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = [], rcaInsights = "") {
|
|
532
592
|
const labels = history.map((h, i) => `${i + 1}s`);
|
|
533
593
|
const successRequestsData = history.map((h) => h.successRequests);
|
|
534
594
|
const failedWorkloadsData = history.map((h) => h.failedRequests);
|
|
@@ -545,6 +605,26 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
545
605
|
x: Number(((r.timestampMs - firstTimestamp) / 1e3).toFixed(2)),
|
|
546
606
|
y: Number(((r.dnsTimeMs || 0) + (r.tcpTimeMs || 0) + (r.tlsTimeMs || 0) + r.durationMs * 0.3).toFixed(1))
|
|
547
607
|
}));
|
|
608
|
+
let rcaAccordionHtml = "";
|
|
609
|
+
if (config.clusterLogs) {
|
|
610
|
+
const content = rcaInsights ? rcaInsights : `
|
|
611
|
+
<div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px dashed #475569; color: #94a3b8;">
|
|
612
|
+
\u{1F4A1} <strong>Autonomous RCA Available:</strong> Pass the <code>--ai-key <your-key></code> flag, or configure a <code>GEMINI_API_KEY</code> environment variable in your PowerShell runtime session to dynamically structure error logs here.
|
|
613
|
+
</div>`;
|
|
614
|
+
rcaAccordionHtml = `
|
|
615
|
+
<details class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #8b5cf6; padding: 0; overflow: hidden;" open>
|
|
616
|
+
<summary style="font-size: 1.2rem; font-weight: bold; color: #c084fc; padding: 1.25rem; display: flex; align-items: center; justify-content: space-between; cursor: pointer; outline: none; user-select: none; list-style: none;">
|
|
617
|
+
<span style="display: flex; align-items: center; gap: 0.6rem;">\u{1F9E0} Autonomous Root-Cause Analysis (RCA) Insights</span>
|
|
618
|
+
<span style="font-size: 0.8rem; color: #64748b; font-weight: normal; font-family: monospace;">[CLICK TO COLLAPSE/EXPAND]</span>
|
|
619
|
+
</summary>
|
|
620
|
+
<div style="padding: 0 1.25rem 1.25rem 1.25rem; border-top: 1px solid #1e293b; color: #cbd5e1; font-size: 0.95rem; line-height: 1.6;">
|
|
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>`;
|
|
627
|
+
}
|
|
548
628
|
let logClustersHtml = "";
|
|
549
629
|
if (semanticReport) {
|
|
550
630
|
const totalLogCount = semanticReport.clusters.reduce((sum, c) => sum + c.count, 0);
|
|
@@ -552,7 +632,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
552
632
|
logClustersHtml = `
|
|
553
633
|
<div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
|
|
554
634
|
<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;">
|
|
555
|
-
\u{
|
|
635
|
+
\u{1F4CA} Semantic Log Clustering & Error Classification
|
|
556
636
|
</h3>
|
|
557
637
|
<div style="color: #94a3b8; font-size: 0.9rem; margin-bottom: 1.5rem;">
|
|
558
638
|
Captured <strong style="color: #f8fafc;">${totalLogCount}</strong> raw failures grouped into <strong style="color: #f8fafc;">${uniquePatternsCount}</strong> unique structural patterns.
|
|
@@ -741,10 +821,12 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
741
821
|
.badge { padding: 0.25rem 0.5rem; border-radius: 4px; font-size: 0.8rem; font-weight: bold; }
|
|
742
822
|
.badge-success { background: #16a34a; color: #f0fdf4; }
|
|
743
823
|
.badge-fail { background: #dc2626; color: #fef2f2; }
|
|
824
|
+
|
|
825
|
+
summary::-webkit-details-marker { display: none; }
|
|
744
826
|
</style></head><body>
|
|
745
827
|
<div class="container">
|
|
746
828
|
<div class="header">
|
|
747
|
-
<h1>\u{1F525} Blaze Core Performance
|
|
829
|
+
<h1>\u{1F525} Blaze Core Performance Report</h1>
|
|
748
830
|
<div class="meta">Target Script: <code>${config.targetScript}</code></div>
|
|
749
831
|
</div>
|
|
750
832
|
|
|
@@ -902,6 +984,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
902
984
|
${seoImpactSectionHtml}
|
|
903
985
|
${liveAdjusterHtml}
|
|
904
986
|
${rightSizingHtml}
|
|
987
|
+
${rcaAccordionHtml}
|
|
905
988
|
${logClustersHtml}
|
|
906
989
|
</div>
|
|
907
990
|
|
|
@@ -959,7 +1042,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
959
1042
|
}
|
|
960
1043
|
});
|
|
961
1044
|
|
|
962
|
-
// --- AI FORECASTING LINE REGRESSION SETUP ---
|
|
963
1045
|
const baseActiveThreads = ${JSON.stringify(activeThreadsData)};
|
|
964
1046
|
const baseTtfTrend = ${JSON.stringify(ttfTrendData)};
|
|
965
1047
|
const historicalCount = baseTtfTrend.length;
|
|
@@ -988,7 +1070,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
988
1070
|
const lastThreads = baseActiveThreads[historicalCount - 1] || 10;
|
|
989
1071
|
const threadStep = ${config.stepSize || 15};
|
|
990
1072
|
|
|
991
|
-
// Project out the next 3 hypothetical execution tiers
|
|
992
1073
|
for (let i = 1; i <= 3; i++) {
|
|
993
1074
|
extendedLabels.push(\`+\${i * 5}s (AI Forecast)\`);
|
|
994
1075
|
extendedThreads.push(lastThreads + (threadStep * i));
|
|
@@ -1106,6 +1187,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
1106
1187
|
function printUsage() {
|
|
1107
1188
|
console.log(`Blaze Core Performance Test CLI Engine
|
|
1108
1189
|
Options:
|
|
1109
|
-
--threads <count> | --duration <seconds> | --agentic | --cluster-logs | --correlate | --seo
|
|
1190
|
+
--threads <count> | --duration <seconds> | --agentic | --cluster-logs | --correlate | --seo | --ai-key <api-key>`);
|
|
1110
1191
|
}
|
|
1111
1192
|
main().catch(console.error);
|
|
Binary file
|