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 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, rcaInsights);
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, rcaInsights);
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: 0, 502: 0, 503: 0, 504: 0 };
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 = [], rcaInsights = "") {
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 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>`;
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{1F4CA} Semantic Log Clustering & Error Classification
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 Report</h1>
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 | --ai-key <api-key>`);
1137
+ --threads <count> | --duration <seconds> | --agentic | --cluster-logs | --correlate | --seo`);
1191
1138
  }
1192
1139
  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.32",
3
+ "version": "3.1.34",
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",