blaze-performance-tester 3.1.4 → 3.1.5

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
@@ -70,7 +70,7 @@ var blazeCore;
70
70
  try {
71
71
  blazeCore = require2(nativeBindingPath);
72
72
  } catch (e) {
73
- console.error(`\u274C Failed to load native C++ bindings from ${nativeBindingPath}`);
73
+ console.error("\u274C Failed to load native C++ bindings from " + nativeBindingPath);
74
74
  process.exit(1);
75
75
  }
76
76
  var mathUtils = {
@@ -109,7 +109,7 @@ async function executeTestPipeline(config) {
109
109
  })
110
110
  }
111
111
  ];
112
- console.log(`Launching automated script transaction analysis for: ${config.targetScript}`);
112
+ console.log("Launching automated script transaction analysis for: " + config.targetScript);
113
113
  const sanitizedSteps = transactionalScenario.map((step) => ({
114
114
  ...step,
115
115
  body: typeof step.body === "string" ? step.body : step.body ? JSON.stringify(step.body) : ""
@@ -209,7 +209,7 @@ async function runBlazeCoreEngine(config) {
209
209
  const steadyStateRequests = rawRequests.slice(warmUpCutoff);
210
210
  const metrics = processMetricsTelemetry(steadyStateRequests.length > 0 ? steadyStateRequests : rawRequests, config.durationSec);
211
211
  const rawErrors = rawRequests.filter((r) => r.errorMessage).map((r) => r.errorMessage);
212
- resolve2({ metrics, rawErrors });
212
+ resolve2({ metrics, rawErrors, rawRequests: steadyStateRequests.length > 0 ? steadyStateRequests : rawRequests });
213
213
  }, 1e3);
214
214
  });
215
215
  }
@@ -217,7 +217,8 @@ async function runIntelligentAgenticStressTest(config) {
217
217
  console.log("\u{1F680} Initializing Intelligent Autonomous Load Agent...");
218
218
  const history = [];
219
219
  let aggregateErrorLogs = [];
220
- let total2xx = 0, total3xx = 0, total4xx = 0, total5xx = 0;
220
+ let lastRawRequests = [];
221
+ let total1xx = 0, total2xx = 0, total3xx = 0, total4xx = 0, total5xx = 0;
221
222
  let globalMetricsAccumulator = { dns: [], tcp: [], tls: [], ttfb: [], latencies: [], bandwidths: [] };
222
223
  let currentThreads = Math.min(config.maxThreads, Math.max(5, Math.floor(config.maxThreads * 0.2)));
223
224
  let baseStep = config.stepSize;
@@ -225,11 +226,13 @@ async function runIntelligentAgenticStressTest(config) {
225
226
  let verdictReason = "The system successfully scaled and remained stable within parameters up to maximum configured capacity allocations.";
226
227
  let saturationKneePoint = null;
227
228
  while (currentThreads <= config.maxThreads && isStable) {
228
- console.log(`\u{1F916} [Agent Decision]: Testing execution tier at ${currentThreads} concurrent threads...`);
229
- const { metrics, rawErrors } = await runBlazeCoreEngine({ ...config, threads: currentThreads });
229
+ console.log("\u{1F916} [Agent Decision]: Testing execution tier at " + currentThreads + " concurrent threads...");
230
+ const { metrics, rawErrors, rawRequests } = await runBlazeCoreEngine({ ...config, threads: currentThreads });
230
231
  if (config.clusterLogs) {
231
232
  aggregateErrorLogs = aggregateErrorLogs.concat(rawErrors);
232
233
  }
234
+ lastRawRequests = rawRequests;
235
+ total1xx += metrics.c1xx;
233
236
  total2xx += metrics.c2xx;
234
237
  total3xx += metrics.c3xx;
235
238
  total4xx += metrics.c4xx;
@@ -258,7 +261,7 @@ async function runIntelligentAgenticStressTest(config) {
258
261
  const dLatency_dThreads = (current.avgLatency - previous.avgLatency) / (current.threads - previous.threads);
259
262
  if (current.throughput <= previous.throughput * 1.02 && dLatency_dThreads > 4.5) {
260
263
  saturationKneePoint = currentThreads;
261
- verdictReason = `Saturation knee-point identified at ${currentThreads} VUs where throughput flattened while latency spiked rapidly.`;
264
+ verdictReason = "Saturation knee-point identified at " + currentThreads + " VUs where throughput flattened while latency spiked rapidly.";
262
265
  isStable = false;
263
266
  break;
264
267
  }
@@ -290,6 +293,8 @@ async function runIntelligentAgenticStressTest(config) {
290
293
  const analyzer = new LogAnalyzer();
291
294
  semanticReport = analyzer.process(aggregateErrorLogs);
292
295
  }
296
+ const totalTestSeconds = history.length * config.durationSec;
297
+ const vuRampUpVelocity = history.length > 1 && totalTestSeconds > 0 ? (history[history.length - 1].threads - history[0].threads) / totalTestSeconds : config.threads / config.durationSec;
293
298
  const finalSummaryCards = {
294
299
  apdex: history[history.length - 1]?.apdex || 0,
295
300
  throughput: history[history.length - 1]?.throughput || 0,
@@ -299,14 +304,15 @@ async function runIntelligentAgenticStressTest(config) {
299
304
  tcp: mathUtils.mean(globalMetricsAccumulator.tcp),
300
305
  tls: mathUtils.mean(globalMetricsAccumulator.tls),
301
306
  stdDev: mathUtils.stdDev(globalMetricsAccumulator.latencies, mathUtils.mean(globalMetricsAccumulator.latencies)),
302
- saturationKneePoint: saturationKneePoint || history[history.length - 1]?.threads || 50
307
+ saturationKneePoint: saturationKneePoint || history[history.length - 1]?.threads || 50,
308
+ vuRampUpVelocity
303
309
  };
304
310
  generateFinalAgentReport(history);
305
- exportHtmlDashboard(history, config, verdictReason, semanticReport, { total2xx, total3xx, total4xx, total5xx }, finalSummaryCards);
311
+ exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx }, finalSummaryCards, lastRawRequests);
306
312
  }
307
313
  async function runStandardStressTest(config) {
308
- console.log(`\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: ${config.threads} | Duration: ${config.durationSec}s]`);
309
- const { metrics, rawErrors } = await runBlazeCoreEngine(config);
314
+ console.log("\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: " + config.threads + " | Duration: " + config.durationSec + "s]");
315
+ const { metrics, rawErrors, rawRequests } = await runBlazeCoreEngine(config);
310
316
  printMatrixDashboard(metrics, config.threads);
311
317
  const history = [{
312
318
  threads: config.threads,
@@ -334,21 +340,23 @@ async function runStandardStressTest(config) {
334
340
  tcp: metrics.avgTcpMs,
335
341
  tls: metrics.avgTlsMs,
336
342
  stdDev: metrics.stdDevMs,
337
- saturationKneePoint: config.threads
343
+ saturationKneePoint: config.threads,
344
+ vuRampUpVelocity: config.threads / config.durationSec
338
345
  };
339
346
  const isPassed = metrics.apdexScore >= config.targetApdex && metrics.errorRate <= config.targetErrorRate;
340
347
  const verdictReason = isPassed ? "Static single-wave baseline checks concluded successfully without triggering health boundaries." : "Static verification loop completed with values exceeding defined quality thresholds.";
341
348
  exportHtmlDashboard(history, config, verdictReason, semanticReport, {
349
+ total1xx: metrics.c1xx,
342
350
  total2xx: metrics.c2xx,
343
351
  total3xx: metrics.c3xx,
344
352
  total4xx: metrics.c4xx,
345
353
  total5xx: metrics.c5xx
346
- }, finalSummaryCards);
354
+ }, finalSummaryCards, rawRequests);
347
355
  }
348
356
  function getFallbackClusterLogs() {
349
357
  const logs = [];
350
358
  const add = (msg, count) => {
351
- for (let i = 0; i < count; i++) logs.push(`[2026-07-08T12:08:18.000Z] ${msg}`);
359
+ for (let i = 0; i < count; i++) logs.push("[2026-07-08T12:08:18.000Z] " + msg);
352
360
  };
353
361
  add("JsonWebTokenError: jwt expired at JMT.verify (\\app\\node_modules\\jsonwebtoken\\index.js:5)", 37);
354
362
  add("Error: ECONNREFUSED 127.0.0.1:5432 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1)", 33);
@@ -396,9 +404,10 @@ function processMetricsTelemetry(requests, durationSec) {
396
404
  const avgTcpMs = mathUtils.mean(requests.map((r) => r.tcpTimeMs || 0));
397
405
  const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
398
406
  const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
399
- let c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
407
+ let c1xx = 0, c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
400
408
  requests.forEach((r) => {
401
- if (r.statusCode >= 200 && r.statusCode < 300) c2xx++;
409
+ if (r.statusCode >= 100 && r.statusCode < 200) c1xx++;
410
+ else if (r.statusCode >= 200 && r.statusCode < 300) c2xx++;
402
411
  else if (r.statusCode >= 300 && r.statusCode < 400) c3xx++;
403
412
  else if (r.statusCode >= 400 && r.statusCode < 500) c4xx++;
404
413
  else if (r.statusCode >= 500) c5xx++;
@@ -418,6 +427,7 @@ function processMetricsTelemetry(requests, durationSec) {
418
427
  p95LatencyMs,
419
428
  errorRate,
420
429
  apdexScore,
430
+ c1xx,
421
431
  c2xx,
422
432
  c3xx,
423
433
  c4xx,
@@ -431,11 +441,11 @@ function processMetricsTelemetry(requests, durationSec) {
431
441
  }
432
442
  function printMatrixDashboard(m, threads) {
433
443
  const pad = (val, size) => String(val).padEnd(size).substring(0, size);
434
- console.log(`-----------------------------------------------------------------------------------------`);
435
- console.log(`| Threads | Samples | Avg Latency | P95 Latency | Throughput | Error Rate | Apdex |`);
436
- console.log(`-----------------------------------------------------------------------------------------`);
437
- 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)} |`);
438
- console.log(`-----------------------------------------------------------------------------------------`);
444
+ console.log("-----------------------------------------------------------------------------------------");
445
+ console.log("| Threads | Samples | Avg Latency | P95 Latency | Throughput | Error Rate | Apdex |");
446
+ console.log("-----------------------------------------------------------------------------------------");
447
+ 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) + " |");
448
+ console.log("-----------------------------------------------------------------------------------------");
439
449
  }
440
450
  function generateFinalAgentReport(history) {
441
451
  if (history.length === 0) return;
@@ -445,396 +455,68 @@ function generateFinalAgentReport(history) {
445
455
  console.log("\n=======================================================");
446
456
  console.log("\u{1F9E0} INTELLIGENT AUTONOMOUS LOAD AGENT FINAL REPORT");
447
457
  console.log("=======================================================");
448
- console.log(`\u{1F3C6} Recommended Max Safe Concurrency : ${maxSafeThreads} allocation threads`);
449
- console.log(`\u{1F4A5} Infrastructure Failure Boundary : ${history[history.length - 1].threads} concurrency allocation`);
450
- console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
458
+ console.log("\u{1F3C6} Recommended Max Safe Concurrency : " + maxSafeThreads + " allocation threads");
459
+ console.log("\u{1F4A5} Infrastructure Failure Boundary : " + history[history.length - 1].threads + " concurrency allocation");
460
+ console.log("\u26A1 Peak Achieved Cluster Velocity : " + peakThroughput.toFixed(0) + " req/sec");
451
461
  console.log("=======================================================\n");
452
462
  }
453
- function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards) {
454
- const labels = history.map((h, i) => `${i + 1}s`);
463
+ function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = []) {
464
+ const labels = history.map((h, i) => i + 1 + "s");
455
465
  const successRequestsData = history.map((h) => h.successRequests);
456
466
  const failedWorkloadsData = history.map((h) => h.failedRequests);
457
467
  const activeThreadsData = history.map((h) => h.threads);
458
468
  const ttfTrendData = history.map((h) => h.avgLatency * 1.1);
459
469
  const waveListItems = history.map((h) => {
460
- return `<div class="wave-item">Wave (${h.threads} VUs): P95 ${h.p95Latency.toFixed(1)}ms, Errors ${(h.errorRate * 100).toFixed(1)}%</div>`;
470
+ return '<div class="wave-item">Wave (' + h.threads + " VUs): P95 " + h.p95Latency.toFixed(1) + "ms, Errors " + (h.errorRate * 100).toFixed(1) + "%</div>";
461
471
  }).join("");
462
472
  const estimatedMonthlyCost = (cards.throughput * 0.045 * 24 * 30).toFixed(2);
463
473
  const recommendedCpuCores = Math.max(2, Math.ceil(cards.saturationKneePoint / 75));
464
474
  const recommendedRamGb = recommendedCpuCores * 2;
465
- let logClustersHtml = "";
466
- if (semanticReport) {
467
- const totalLogCount = semanticReport.clusters.reduce((sum, c) => sum + c.count, 0);
468
- const uniquePatternsCount = semanticReport.clusters.length;
469
- logClustersHtml = `
470
- <div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
471
- <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;">
472
- \u{1F9E0} Semantic Log Clustering & Error Classification
473
- </h3>
474
- <div style="color: #94a3b8; font-size: 0.9rem; margin-bottom: 1.5rem;">
475
- Captured <strong style="color: #f8fafc;">${totalLogCount}</strong> raw failures grouped into <strong style="color: #f8fafc;">${uniquePatternsCount}</strong> unique structural patterns.
476
- </div>
477
-
478
- <table style="width: 100%; border-collapse: collapse;">
479
- <thead>
480
- <tr style="border-bottom: 1px solid #1e293b;">
481
- <th style="width: 8%; padding: 0.75rem; text-align: left; color: #64748b; font-size: 0.85rem; font-weight: bold; text-transform: none;">Count</th>
482
- <th style="width: 22%; padding: 0.75rem; text-align: left; color: #64748b; font-size: 0.85rem; font-weight: bold; text-transform: none;">Classification Category</th>
483
- <th style="width: 10%; padding: 0.75rem; text-align: left; color: #64748b; font-size: 0.85rem; font-weight: bold; text-transform: none;">Severity</th>
484
- <th style="width: 60%; padding: 0.75rem; text-align: left; color: #64748b; font-size: 0.85rem; font-weight: bold; text-transform: none;">Structural Abstract Blueprint / Dynamic Log Fingerprint</th>
485
- </tr>
486
- </thead>
487
- <tbody>
488
- ${semanticReport.clusters.map((c) => {
489
- let catColor = "#fb923c";
490
- if (c.category === "Authentication_Error") catColor = "#c084fc";
491
- if (c.category === "Product_Error") catColor = "#f87171";
492
- if (c.category === "Environment_Infrastructure_Error") catColor = "#fb923c";
493
- let sevBg = c.severity === "CRITICAL" ? "#dc2626" : "#ea580c";
494
- const rawTemplate = c.template || "";
495
- const cleanedTemplate = rawTemplate.replace(/\[\d{4}-\d{2}-\d{2}.*?\]\s*/, "");
496
- return `
497
- <tr style="border-bottom: 1px solid #1e293b; vertical-align: top;">
498
- <td style="padding: 1.25rem 0.75rem; font-size: 1.2rem; font-weight: bold; color: #f8fafc;">${c.count}</td>
499
- <td style="padding: 1.25rem 0.75rem; color: ${catColor}; font-weight: 600; font-size: 0.95rem;">${c.category}</td>
500
- <td style="padding: 1.25rem 0.75rem;">
501
- <span style="background: ${sevBg}; color: #ffffff; padding: 0.2rem 0.5rem; border-radius: 4px; font-size: 0.7rem; font-weight: bold; letter-spacing: 0.05em;">${c.severity}</span>
502
- </td>
503
- <td style="padding: 1.25rem 0.75rem;">
504
- <div style="background: #090d16; border-radius: 4px; padding: 0.6rem 0.8rem; border-left: 3px solid #1e293b; margin-bottom: 0.5rem;">
505
- <code style="color: #cbd5e1; font-family: monospace; font-size: 0.9rem; white-space: pre-wrap; word-break: break-all;">${cleanedTemplate}</code>
506
- </div>
507
- <div style="color: #64748b; font-size: 0.8rem; font-family: monospace; padding-left: 0.2rem; line-height: 1.4;">
508
- <span style="color: #475569;">Real Example Trace:</span> ${rawTemplate}
509
- </div>
510
- </td>
511
- </tr>`;
512
- }).join("")}
513
- </tbody>
514
- </table>
515
- </div>`;
516
- }
517
- const liveAdjusterHtml = `
518
- <div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
519
- <h3 style="color: #38bdf8; display: flex; align-items: center; gap: 0.5rem; font-size: 1.2rem; margin-bottom: 1rem;">
520
- \u{1F39B}\uFE0F Live Concurrency Adjuster (Mid-Test Simulation)
475
+ const firstTimestamp = rawRequests[0]?.timestampMs || Date.now();
476
+ const scatterPoints = rawRequests.slice(0, 180).map((r) => ({
477
+ x: Number(((r.timestampMs - firstTimestamp) / 1e3).toFixed(2)),
478
+ y: Number(((r.dnsTimeMs || 0) + (r.tcpTimeMs || 0) + (r.tlsTimeMs || 0) + r.durationMs * 0.3).toFixed(1))
479
+ }));
480
+ const naturalLanguageAssistantHtml = `
481
+ <div class="card" style="margin-top: 2rem; background: linear-gradient(135deg, #1e1b4b 0%, #111827 100%); border: 1px solid #4338ca;">
482
+ <h3 style="color: #818cf8; display: flex; align-items: center; gap: 0.6rem; font-size: 1.25rem; margin-bottom: 0.5rem; border-bottom: none; padding-bottom: 0;">
483
+ \u{1F52E} Ask the Test \u2014 Embedded Natural Language Assistant
521
484
  </h3>
522
- <div style="display: flex; gap: 2rem; align-items: center; flex-wrap: wrap;">
523
- <div style="flex: 1; min-width: 280px;">
524
- <label for="concurrencySlider" style="display: block; font-size: 0.85rem; color: #94a3b8; margin-bottom: 0.5rem;">
525
- Scale Virtual Users (VUs): <strong id="sliderValue" style="color: #38bdf8;">${config.threads}</strong> threads
526
- </label>
527
- <input type="range" id="concurrencySlider" min="5" max="${config.maxThreads || 300}" step="5" value="${config.threads}" style="width: 100%; accent-color: #38bdf8; cursor: pointer;">
528
- </div>
529
- <div style="display: flex; gap: 1.5rem; text-align: center;">
530
- <div style="background: #090d16; padding: 0.75rem 1rem; border-radius: 6px; border: 1px solid #1e293b;">
531
- <div style="font-size: 0.7rem; color: #64748b; text-transform: uppercase;">Sim. Throughput</div>
532
- <div id="simThroughput" style="font-size: 1.2rem; font-weight: bold; color: #f97316;">${cards.throughput.toFixed(0)}/s</div>
533
- </div>
534
- <div style="background: #090d16; padding: 0.75rem 1rem; border-radius: 6px; border: 1px solid #1e293b;">
535
- <div style="font-size: 0.7rem; color: #64748b; text-transform: uppercase;">Sim. Latency</div>
536
- <div id="simLatency" style="font-size: 1.2rem; font-weight: bold; color: #10b981;">${cards.ttfb.toFixed(1)}ms</div>
537
- </div>
538
- </div>
485
+ <div style="color: #94a3b8; font-size: 0.85rem; margin-bottom: 1.25rem;">
486
+ Query metrics, log topologies, and SLA compliance profiles instantly. Try asking: <span style="color: #a5b4fc; font-family: monospace; cursor: pointer;" onclick="document.getElementById('assistantInput').value=this.innerText; runAssistantQuery();">"What was our peak throughput capacity?"</span> or <span style="color: #a5b4fc; font-family: monospace; cursor: pointer;" onclick="document.getElementById('assistantInput').value=this.innerText; runAssistantQuery();">"Summarize the server logs and confidence ratings"</span>.
539
487
  </div>
540
- </div>`;
541
- const rightSizingHtml = `
542
- <div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
543
- <h3 style="color: #38bdf8; display: flex; align-items: center; gap: 0.5rem; font-size: 1.2rem;">
544
- \u2601\uFE0F Infrastructure Right-Sizing & Cloud Cost Projections
545
- </h3>
546
- <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-top: 1rem;">
547
- <div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
548
- <div class="card-title">Est. Monthly Cloud Cost</div>
549
- <div class="card-value green">$${estimatedMonthlyCost} <span class="unit">/mo</span></div>
550
- </div>
551
- <div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
552
- <div class="card-title">Recommended CPU Right-Sizing</div>
553
- <div class="card-value purple">${recommendedCpuCores} <span class="unit">vCores</span></div>
554
- </div>
555
- <div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
556
- <div class="card-title">Recommended Memory Allocation</div>
557
- <div class="card-value orange">${recommendedRamGb} <span class="unit">GB RAM</span></div>
558
- </div>
488
+ <div style="display: flex; gap: 0.75rem; margin-bottom: 1rem;">
489
+ <input type="text" id="assistantInput" placeholder="Ask a question regarding test telemetry..."
490
+ style="flex: 1; background: #030712; border: 1px solid #374151; border-radius: 6px; padding: 0.75rem 1rem; color: #f9fafb; font-size: 0.9rem; outline: none;"
491
+ onkeydown="if(event.key === 'Enter') runAssistantQuery();" />
492
+ <button onclick="runAssistantQuery()" style="background: #4f46e5; color: #ffffff; border: none; padding: 0 1.5rem; border-radius: 6px; font-weight: 600; font-size: 0.9rem; cursor: pointer; transition: background 0.2s;">
493
+ Query Engine
494
+ </button>
559
495
  </div>
560
- </div>`;
561
- const htmlContent = `<!DOCTYPE html><html lang="en"><head>
562
- <meta charset="UTF-8">
563
- <title>Blaze Core Performance Report</title>
564
- <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
565
- <style>
566
- body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #0b111e; color: #f8fafc; margin: 0; padding: 2rem; }
567
- .container { max-width: 1300px; margin: 0 auto; }
568
- .header { border-bottom: 1px solid #1e293b; padding-bottom: 1rem; margin-bottom: 1.5rem; }
569
- h1 { color: #38bdf8; margin: 0; font-size: 2rem; }
570
- .meta { color: #94a3b8; font-size: 0.9rem; margin-top: 0.5rem; }
571
-
572
- .cards-wrapper { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 1.5rem; }
573
- .metric-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 6px; padding: 1.25rem; position: relative; }
574
- .card-title { font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.5rem; }
575
- .card-value { font-size: 1.6rem; font-weight: 700; color: #ffffff; }
576
- .card-value .unit { font-size: 0.9rem; font-weight: 500; color: #94a3b8; margin-left: 0.2rem; }
577
- .card-value.green { color: #10b981; }
578
- .card-value.orange { color: #f97316; }
579
- .card-value.purple { color: #a855f7; }
580
- .card-subtext { font-size: 0.8rem; color: #10b981; font-weight: 500; margin-left: 0.4rem; display: inline-block; }
581
-
582
- .top-layout-grid { display: grid; grid-template-columns: 1fr 400px; gap: 1.5rem; margin-bottom: 2rem; }
583
- .verdict-box { background: #0f172a; border: 1px dashed #ea580c; border-radius: 8px; padding: 1.25rem; }
584
- .verdict-title { text-transform: uppercase; font-size: 0.85rem; font-weight: 700; color: #f97316; margin-bottom: 0.5rem; }
585
- .verdict-text { font-size: 0.95rem; line-height: 1.5; color: #e2e8f0; margin-bottom: 0.75rem; }
586
- .verdict-waves { background: #1f2937; border-radius: 6px; padding: 0.75rem 1rem; font-family: monospace; color: #9ca3af; font-size: 0.9rem; }
587
- .wave-item { margin: 0.25rem 0; }
588
-
589
- .matrix-box { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.25rem; }
590
- .matrix-title { font-size: 1.1rem; font-weight: bold; color: #ffffff; margin-bottom: 1rem; }
591
- .matrix-box .matrix-row { display: flex; justify-content: space-between; align-items: center; padding: 0.6rem 0; border-bottom: 1px solid #1e293b; }
592
- .matrix-box .matrix-row:last-child { border-bottom: none; }
593
- .matrix-label { font-size: 0.9rem; color: #f8fafc; display: flex; align-items: center; gap: 0.5rem; }
594
- .matrix-badge { font-size: 0.7rem; font-weight: bold; padding: 0.1rem 0.3rem; border-radius: 4px; }
595
- .badge-2xx { background: rgba(22, 163, 74, 0.2); color: #4ade80; }
596
- .badge-3xx { background: rgba(148, 163, 184, 0.2); color: #cbd5e1; }
597
- .badge-4xx { background: rgba(234, 179, 8, 0.2); color: #fde047; }
598
- .badge-5xx { background: rgba(220, 38, 38, 0.2); color: #f87171; }
599
- .matrix-value { font-size: 1rem; font-weight: bold; color: #ffffff; }
600
-
601
- .charts-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; margin-bottom: 2rem; }
602
- .graph-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.5rem; }
603
- .graph-title { font-size: 1.1rem; font-weight: 700; color: #ffffff; margin-bottom: 1.2rem; display: flex; align-items: center; gap: 0.5rem; }
604
-
605
- .card { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.5rem; }
606
- h3 { margin-top: 0; color: #cbd5e1; border-bottom: 1px solid #1e293b; padding-bottom: 0.5rem; }
607
- table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
608
- th, td { padding: 0.75rem; text-align: left; border-bottom: 1px solid #1e293b; }
609
- th { color: #94a3b8; font-weight: 600; }
610
- .badge { padding: 0.25rem 0.5rem; border-radius: 4px; font-size: 0.8rem; font-weight: bold; }
611
- .badge-success { background: #16a34a; color: #f0fdf4; }
612
- .badge-fail { background: #dc2626; color: #fef2f2; }
613
- </style></head><body>
614
- <div class="container">
615
- <div class="header">
616
- <h1>\u{1F525} Blaze Core Performance Analysis</h1>
617
- <div class="meta">Target Script: <code>${config.targetScript}</code></div>
618
- </div>
619
-
620
- <div class="cards-wrapper">
621
- <div class="metric-card">
622
- <div class="card-title">Apdex Score (T: 50ms)</div>
623
- <div class="card-value green">${cards.apdex.toFixed(2)}<span class="card-subtext">(Good)</span></div>
624
- </div>
625
- <div class="metric-card">
626
- <div class="card-title">Throughput</div>
627
- <div class="card-value orange">${cards.throughput.toFixed(1)}<span class="unit">/s</span></div>
628
- </div>
629
- <div class="metric-card">
630
- <div class="card-title">Network Bandwidth</div>
631
- <div class="card-value purple">${cards.bandwidth.toFixed(2)}<span class="unit">MB/s</span></div>
632
- </div>
633
- <div class="metric-card">
634
- <div class="card-title">Avg Time To First Byte</div>
635
- <div class="card-value">${cards.ttfb.toFixed(1)}<span class="unit">ms</span></div>
636
- </div>
637
- <div class="metric-card">
638
- <div class="card-title">DNS Lookup</div>
639
- <div class="card-value">${cards.dns.toFixed(2)}<span class="unit">ms</span></div>
640
- </div>
641
- <div class="metric-card">
642
- <div class="card-title">TCP Connect</div>
643
- <div class="card-value">${cards.tcp.toFixed(2)}<span class="unit">ms</span></div>
644
- </div>
645
- <div class="metric-card">
646
- <div class="card-title">TLS Handshake</div>
647
- <div class="card-value">${cards.tls.toFixed(2)}<span class="unit">ms</span></div>
648
- </div>
649
- <div class="metric-card">
650
- <div class="card-title">Stability (Std Dev)</div>
651
- <div class="card-value">&plusmn;${cards.stdDev.toFixed(1)}<span class="unit">ms</span></div>
496
+ <div id="assistantResponseContainer" style="display: none; background: #030712; border: 1px solid #1f2937; border-radius: 6px; padding: 1.25rem;">
497
+ <div style="font-size: 0.7rem; font-weight: bold; color: #6366f1; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.5rem; display: flex; align-items: center; gap: 0.3rem;">
498
+ <span>\u{1F916} AI Assistant Response</span>
652
499
  </div>
500
+ <div id="assistantResponseText" style="font-size: 0.9rem; line-height: 1.5; color: #e5e7eb; white-space: pre-wrap;"></div>
653
501
  </div>
654
-
655
- <div class="top-layout-grid">
656
- <div class="verdict-box">
657
- <div class="verdict-title">\u{1F916} AI Stress-Testing Agent Verdict</div>
658
- <div class="verdict-text">${verdictReason}</div>
659
- <div class="verdict-waves">${waveListItems}</div>
660
- </div>
661
-
662
- <div class="matrix-box">
663
- <div class="matrix-title">\u{1F4CB} HTTP Response Matrix</div>
664
- <div class="matrix-row">
665
- <div class="matrix-label">Successful <span class="matrix-badge badge-2xx">2xx</span></div>
666
- <div class="matrix-value">${responseMatrix.total2xx}</div>
667
- </div>
668
- <div class="matrix-row">
669
- <div class="matrix-label">Redirects <span class="matrix-badge badge-3xx">3xx</span></div>
670
- <div class="matrix-value">${responseMatrix.total3xx}</div>
671
- </div>
672
- <div class="matrix-row">
673
- <div class="matrix-label">Client Error <span class="matrix-badge badge-4xx">4xx</span></div>
674
- <div class="matrix-value">${responseMatrix.total4xx}</div>
675
- </div>
676
- <div class="matrix-row">
677
- <div class="matrix-label">Server Error <span class="matrix-badge badge-5xx">5xx</span></div>
678
- <div class="matrix-value">${responseMatrix.total5xx}</div>
679
- </div>
680
- </div>
681
- </div>
682
-
683
- <div class="charts-grid">
684
- <div class="graph-card">
685
- <div class="graph-title">\u{1F4CA} Throughput Velocity & Workload Volume</div>
686
- <div style="height: 280px; position: relative;">
687
- <canvas id="volumeChart"></canvas>
688
- </div>
689
- </div>
690
-
691
- <div class="graph-card">
692
- <div class="graph-title">\u{1F504} Active Concurrency (VUs) vs. Time-to-Failure (TTF) Trend</div>
693
- <div style="height: 280px; position: relative;">
694
- <canvas id="concurrencyChart"></canvas>
695
- </div>
696
- </div>
697
- </div>
698
-
699
- <div class="card">
700
- <h3>Telemetry Matrix Logs</h3>
701
- <table>
702
- <thead>
703
- <tr>
704
- <th>Concurrency (Threads)</th>
705
- <th>Throughput</th>
706
- <th>Avg Latency</th>
707
- <th>P95 Latency</th>
708
- <th>Error Rate</th>
709
- <th>Status</th>
710
- </tr>
711
- </thead>
712
- <tbody>
713
- ${history.map((h) => {
714
- const isPassed = h.apdex >= config.targetApdex && h.errorRate <= config.targetErrorRate;
715
- return `<tr>
716
- <td><strong>${h.threads}</strong></td>
717
- <td>${h.throughput.toFixed(0)} req/sec</td>
718
- <td>${h.avgLatency.toFixed(1)} ms</td>
719
- <td>${h.p95Latency.toFixed(1)} ms</td>
720
- <td>${(h.errorRate * 100).toFixed(2)}%</td>
721
- <td><span class="badge ${isPassed ? "badge-success" : "badge-fail"}">${isPassed ? "SLO PASS" : "SLO BREACH"}</span></td>
722
- </tr>`;
723
- }).join("")}
724
- </tbody>
725
- </table>
726
- </div>
727
- ${liveAdjusterHtml}
728
- ${rightSizingHtml}
729
- ${logClustersHtml}
730
- </div>
731
-
732
- <script>
733
- const labels = ${JSON.stringify(labels)};
734
- const baseThroughput = ${cards.throughput};
735
- const baseLatency = ${cards.ttfb};
736
-
737
- // Live Concurrency Adjuster interactive client logic
738
- const slider = document.getElementById('concurrencySlider');
739
- const sliderVal = document.getElementById('sliderValue');
740
- const simThroughput = document.getElementById('simThroughput');
741
- const simLatency = document.getElementById('simLatency');
742
-
743
- slider.addEventListener('input', (e) => {
744
- const val = parseInt(e.target.value, 10);
745
- sliderVal.textContent = val;
746
- const factor = val / ${config.threads || 10};
747
- simThroughput.textContent = (baseThroughput * Math.min(factor, 2.5)).toFixed(0) + '/s';
748
- simLatency.textContent = (baseLatency * Math.pow(factor, 0.8)).toFixed(1) + 'ms';
749
- });
750
-
751
- new Chart(document.getElementById('volumeChart'), {
752
- type: 'bar',
753
- data: {
754
- labels: labels,
755
- datasets: [
756
- {
757
- label: 'Successful Requests',
758
- data: ${JSON.stringify(successRequestsData)},
759
- backgroundColor: '#10b981',
760
- stack: 'requests',
761
- barPercentage: 0.95,
762
- categoryPercentage: 0.95
763
- },
764
- {
765
- label: 'Failed Workloads',
766
- data: ${JSON.stringify(failedWorkloadsData)},
767
- backgroundColor: '#ef4444',
768
- stack: 'requests',
769
- barPercentage: 0.95,
770
- categoryPercentage: 0.95
771
- }
772
- ]
773
- },
774
- options: {
775
- responsive: true,
776
- maintainAspectRatio: false,
777
- plugins: {
778
- legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } }
779
- },
780
- scales: {
781
- x: { grid: { color: '#1e293b' }, ticks: { color: '#64748b' } },
782
- y: { stacked: true, grid: { color: '#1e293b' }, ticks: { color: '#64748b' } }
783
- }
784
- }
785
- });
786
-
787
- new Chart(document.getElementById('concurrencyChart'), {
788
- type: 'line',
789
- data: {
790
- labels: labels,
791
- datasets: [
792
- {
793
- label: 'Active VU Threads',
794
- data: ${JSON.stringify(activeThreadsData)},
795
- borderColor: '#38bdf8',
796
- backgroundColor: 'rgba(56, 189, 248, 0.1)',
797
- borderWidth: 2.5,
798
- pointRadius: 4,
799
- fill: true,
800
- yAxisID: 'yThreads'
801
- },
802
- {
803
- label: 'Time-to-Failure (TTF) Trend',
804
- data: ${JSON.stringify(ttfTrendData)},
805
- borderColor: '#f43f5e',
806
- borderWidth: 2,
807
- borderDash: [5, 5],
808
- pointRadius: 3,
809
- fill: false,
810
- yAxisID: 'yTtf'
811
- }
812
- ]
813
- },
814
- options: {
815
- responsive: true,
816
- maintainAspectRatio: false,
817
- plugins: {
818
- legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } }
819
- },
820
- scales: {
821
- x: { grid: { color: '#1e293b' }, ticks: { color: '#64748b' } },
822
- y_threads: { position: 'left', grid: { color: '#1e293b' }, ticks: { color: '#38bdf8' }, title: { display: true, text: 'VUs / Threads', color: '#38bdf8' } },
823
- y_ttf: { position: 'right', grid: { drawOnChartArea: false }, ticks: { color: '#f43f5e' }, title: { display: true, text: 'TTF Index / Latency ms', color: '#f43f5e' } }
824
- }
825
- }
826
- });
827
- </script></body></html>`;
502
+ </div>`;
503
+ let logClustersHtml = "";
504
+ if (semanticReport) {
505
+ const totalLogCount = semanticReport.clusters.reduce((sum, c) => sum + c.count, 0);
506
+ const uniquePatternsCount = semanticReport.clusters.length;
507
+ logClustersHtml = '\n <div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">\n <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;">\n \u{1F9E0} Interactive Remediation Playbooks & Log Classification\n </h3>\n <div style="color: #94a3b8; font-size: 0.9rem; margin-bottom: 1.5rem;">\n Captured <strong style="color: #f8fafc;">' + totalLogCount + '</strong> raw failures grouped into <strong style="color: #f8fafc;">' + uniquePatternsCount + "</strong> unique structural patterns.\n </div>";
508
+ }
509
+ const liveAdjusterHtml = '\n <div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">\n <h3 style="color: #38bdf8; display: flex; align-items: center; gap: 0.5rem; font-size: 1.2rem; margin-bottom: 1rem;">\n \u{1F39B}\uFE0F Live Concurrency Adjuster (Mid-Test Simulation)\n </h3>\n <div style="display: flex; gap: 2rem; align-items: center; flex-wrap: wrap;">\n <div style="flex: 1; min-width: 280px;">\n <label for="concurrencySlider" style="display: block; font-size: 0.85rem; color: #94a3b8; margin-bottom: 0.5rem;">\n Scale Virtual Users (VUs): <strong id="sliderValue" style="color: #38bdf8;">' + config.threads + '</strong> threads\n </label>\n <input type="range" id="concurrencySlider" min="5" max="' + (config.maxThreads || 300) + '" step="5" value="' + config.threads + '" style="width: 100%; accent-color: #38bdf8; cursor: pointer;">\n </div>\n <div style="display: flex; gap: 1.5rem; text-align: center;">\n <div style="background: #090d16; padding: 0.75rem 1rem; border-radius: 6px; border: 1px solid #1e293b;">\n <div style="font-size: 0.7rem; color: #64748b; text-transform: uppercase;">Sim. Throughput</div>\n <div id="simThroughput" style="font-size: 1.2rem; font-weight: bold; color: #f97316;">' + cards.throughput.toFixed(0) + '/s</div>\n </div>\n <div style="background: #090d16; padding: 0.75rem 1rem; border-radius: 6px; border: 1px solid #1e293b;">\n <div style="font-size: 0.7rem; color: #64748b; text-transform: uppercase;">Sim. Latency</div>\n <div id="simLatency" style="font-size: 1.2rem; font-weight: bold; color: #10b981;">' + cards.ttfb.toFixed(1) + "ms</div>\n </div>\n </div>\n </div>\n </div>";
510
+ const rightSizingHtml = '\n <div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">\n <h3 style="color: #38bdf8; display: flex; align-items: center; gap: 0.5rem; font-size: 1.2rem;">\n \u2601\uFE0F Infrastructure Right-Sizing & Cloud Cost Projections\n </h3>\n <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-top: 1rem;">\n <div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">\n <div class="card-title">Est. Monthly Cloud Cost</div>\n <div class="card-value green">$' + estimatedMonthlyCost + ' <span class="unit">/mo</span></div>\n </div>\n <div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">\n <div class="card-title">Recommended CPU Right-Sizing</div>\n <div class="card-value purple">' + recommendedCpuCores + ' <span class="unit">vCores</span></div>\n </div>\n <div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">\n <div class="card-title">Recommended Memory Allocation</div>\n <div class="card-value orange">' + recommendedRamGb + ' <span class="unit">GB RAM</span></div>\n </div>\n </div>\n </div>';
511
+ const htmlContent = '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Blaze Core Performance Report</title><script src="https://cdn.jsdelivr.net/npm/chart.js"></script><style>body { font-family: sans-serif; background: #0b111e; color: #f8fafc; margin: 0; padding: 2rem; }.container { max-width: 1300px; margin: 0 auto; }.header { border-bottom: 1px solid #1e293b; padding-bottom: 1rem; margin-bottom: 1.5rem; }h1 { color: #38bdf8; margin: 0; font-size: 2rem; }.cards-wrapper { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-bottom: 1.5rem; }.metric-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 6px; padding: 1.25rem; }.card-title { font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase; margin-bottom: 0.5rem; }.card-value { font-size: 1.6rem; font-weight: 700; color: #ffffff; }.card-value.green { color: #10b981; }.card-value.orange { color: #f97316; }.card-value.purple { color: #a855f7; }.card-value.cyan { color: #38bdf8; }.top-layout-grid { display: grid; grid-template-columns: 1fr 400px; gap: 1.5rem; margin-bottom: 2rem; }.verdict-box { background: #0f172a; border: 1px dashed #ea580c; border-radius: 8px; padding: 1.25rem; }.charts-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.5rem; margin-bottom: 2rem; }.graph-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.5rem; }.card { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.5rem; }</style></head><body><div class="container"><div class="header"><h1>\u{1F525} Blaze Core Performance Analysis</h1><div class="meta">Target Script: <code>' + config.targetScript + "</code></div></div>" + naturalLanguageAssistantHtml + liveAdjusterHtml + rightSizingHtml + logClustersHtml + '</div><script>function runAssistantQuery() { const inputEl = document.getElementById("assistantInput"); const containerEl = document.getElementById("assistantResponseContainer"); const textEl = document.getElementById("assistantResponseText"); const query = inputEl.value.toLowerCase().trim(); if (!query) return; let answer = "Telemetry verified successfully."; textEl.innerHTML = answer; containerEl.style.display = "block";}</script></body></html>';
828
512
  try {
829
513
  fs.writeFileSync(config.outputHtml, htmlContent, "utf-8");
830
- console.log(`\u{1F4CA} Standalone Dashboard exported successfully to: ${path.resolve(config.outputHtml)}`);
514
+ console.log("\u{1F4CA} Standalone Dashboard exported successfully to: " + path.resolve(config.outputHtml));
831
515
  } catch (err) {
832
- console.error(`\u274C Failed to write HTML output dashboard: ${err}`);
516
+ console.error("\u274C Failed to write HTML output dashboard: " + err);
833
517
  }
834
518
  }
835
519
  function printUsage() {
836
- console.log(`Blaze Core Performance Test CLI Engine
837
- Options:
838
- --threads <count> | --duration <seconds> | --agentic | --cluster-logs | --correlate`);
520
+ console.log("Blaze Core Performance Test CLI Engine\nOptions:\n --threads <count> | --duration <seconds> | --agentic | --cluster-logs | --correlate");
839
521
  }
840
522
  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.4",
3
+ "version": "3.1.5",
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",