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 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 &lt;your-key&gt;</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{1F9E0} Semantic Log Clustering & Error Classification
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 Analysis</h1>
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blaze-performance-tester",
3
- "version": "3.1.28",
3
+ "version": "3.1.30",
4
4
  "description": "A high-performance, multi-threaded load testing engine built with Rust and QuickJS.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",