blaze-performance-tester 3.1.20 → 3.1.22

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
@@ -240,12 +240,21 @@ function calculateSeoImpactMetrics(avgLatencyMs) {
240
240
  }
241
241
  return { trafficLoss, status, crawlPenalty, color };
242
242
  }
243
+ function computeHealthScoreValue(apdex, errorRate, p95Latency, maxAllowedLatency) {
244
+ const apdexComponent = apdex * 50;
245
+ const errorComponent = Math.max(0, 1 - errorRate) * 30;
246
+ const latencyRatio = p95Latency / maxAllowedLatency;
247
+ const latencyComponent = Math.max(0, 1 - Math.min(1, latencyRatio)) * 20;
248
+ return Math.min(100, Math.max(0, Math.round(apdexComponent + errorComponent + latencyComponent)));
249
+ }
243
250
  async function runIntelligentAgenticStressTest(config) {
244
251
  console.log("\u{1F680} Initializing Intelligent Autonomous Load Agent...");
245
252
  const history = [];
246
253
  let aggregateErrorLogs = [];
247
254
  let lastRawRequests = [];
248
255
  let total1xx = 0, total2xx = 0, total3xx = 0, total4xx = 0, total5xx = 0;
256
+ let totalRequestsAccumulator = 0;
257
+ const globalCodeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 0, 502: 0, 503: 0, 504: 0 };
249
258
  let globalMetricsAccumulator = { dns: [], tcp: [], tls: [], ttfb: [], latencies: [], bandwidths: [] };
250
259
  let currentThreads = Math.min(config.maxThreads, Math.max(5, Math.floor(config.maxThreads * 0.2)));
251
260
  let baseStep = config.stepSize;
@@ -264,6 +273,11 @@ async function runIntelligentAgenticStressTest(config) {
264
273
  total3xx += metrics.c3xx;
265
274
  total4xx += metrics.c4xx;
266
275
  total5xx += metrics.c5xx;
276
+ totalRequestsAccumulator += metrics.totalRequests;
277
+ const targetCodes = [400, 401, 403, 404, 429, 500, 502, 503, 504];
278
+ targetCodes.forEach((code) => {
279
+ globalCodeCounts[code] += metrics.codeCounts[code];
280
+ });
267
281
  globalMetricsAccumulator.dns.push(metrics.avgDnsMs);
268
282
  globalMetricsAccumulator.tcp.push(metrics.avgTcpMs);
269
283
  globalMetricsAccumulator.tls.push(metrics.avgTlsMs);
@@ -320,29 +334,38 @@ async function runIntelligentAgenticStressTest(config) {
320
334
  const analyzer = new LogAnalyzer();
321
335
  semanticReport = analyzer.process(aggregateErrorLogs);
322
336
  }
337
+ const finalState = history[history.length - 1] || { apdex: 0, errorRate: 0, p95Latency: 0, throughput: 0 };
338
+ const healthScore = computeHealthScoreValue(finalState.apdex, finalState.errorRate, finalState.p95Latency, config.maxAllowedLatencyMs);
323
339
  const finalSummaryCards = {
324
- apdex: history[history.length - 1]?.apdex || 0,
325
- throughput: history[history.length - 1]?.throughput || 0,
340
+ apdex: finalState.apdex,
341
+ throughput: finalState.throughput,
326
342
  bandwidth: mathUtils.mean(globalMetricsAccumulator.bandwidths),
327
343
  ttfb: mathUtils.mean(globalMetricsAccumulator.ttfb),
328
344
  dns: mathUtils.mean(globalMetricsAccumulator.dns),
329
345
  tcp: mathUtils.mean(globalMetricsAccumulator.tcp),
330
346
  tls: mathUtils.mean(globalMetricsAccumulator.tls),
331
347
  stdDev: mathUtils.stdDev(globalMetricsAccumulator.latencies, mathUtils.mean(globalMetricsAccumulator.latencies)),
332
- saturationKneePoint: saturationKneePoint || history[history.length - 1]?.threads || 50
348
+ saturationKneePoint: saturationKneePoint || finalState.threads || 50,
349
+ healthScore
333
350
  };
334
- generateFinalAgentReport(history);
351
+ generateFinalAgentReport(history, healthScore);
335
352
  if (config.isSeo) {
336
- const finalLat = history[history.length - 1]?.avgLatency || finalSummaryCards.ttfb;
353
+ const finalLat = finalState.avgLatency || finalSummaryCards.ttfb;
337
354
  const seo = calculateSeoImpactMetrics(finalLat);
338
355
  console.log(`\u{1F50E} [SEO Impact Report]: Target latency under stress (${finalLat.toFixed(1)}ms) triggers a predicted Search Visibility Loss of -${seo.trafficLoss}% [Status: ${seo.status}].`);
339
356
  }
340
- exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx }, finalSummaryCards, lastRawRequests);
357
+ const breakdownRates = {};
358
+ Object.keys(globalCodeCounts).forEach((code) => {
359
+ breakdownRates[code] = totalRequestsAccumulator === 0 ? 0 : globalCodeCounts[code] / totalRequestsAccumulator * 100;
360
+ });
361
+ exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests);
341
362
  }
342
363
  async function runStandardStressTest(config) {
343
364
  console.log(`\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: ${config.threads} | Duration: ${config.durationSec}s]`);
344
365
  const { metrics, rawErrors, rawRequests } = await runBlazeCoreEngine(config);
345
366
  printMatrixDashboard(metrics, config.threads);
367
+ const healthScore = computeHealthScoreValue(metrics.apdexScore, metrics.errorRate, metrics.p95LatencyMs, config.maxAllowedLatencyMs);
368
+ console.log(`\u{1F49A} Unified Blaze Health Score: ${healthScore}/100`);
346
369
  const history = [{
347
370
  threads: config.threads,
348
371
  avgLatency: metrics.avgLatencyMs,
@@ -369,7 +392,8 @@ async function runStandardStressTest(config) {
369
392
  tcp: metrics.avgTcpMs,
370
393
  tls: metrics.avgTlsMs,
371
394
  stdDev: metrics.stdDevMs,
372
- saturationKneePoint: config.threads
395
+ saturationKneePoint: config.threads,
396
+ healthScore
373
397
  };
374
398
  const isPassed = metrics.apdexScore >= config.targetApdex && metrics.errorRate <= config.targetErrorRate;
375
399
  const verdictReason = isPassed ? "Static single-wave baseline checks concluded successfully without triggering health boundaries." : "Static verification loop completed with values exceeding defined quality thresholds.";
@@ -377,12 +401,17 @@ async function runStandardStressTest(config) {
377
401
  const seo = calculateSeoImpactMetrics(metrics.avgLatencyMs);
378
402
  console.log(`\u{1F50E} [SEO Impact Report]: Target latency (${metrics.avgLatencyMs.toFixed(1)}ms) triggers a predicted Search Visibility Loss of -${seo.trafficLoss}% [Status: ${seo.status}].`);
379
403
  }
404
+ const breakdownRates = {};
405
+ Object.keys(metrics.codeCounts).forEach((code) => {
406
+ breakdownRates[code] = metrics.totalRequests === 0 ? 0 : metrics.codeCounts[code] / metrics.totalRequests * 100;
407
+ });
380
408
  exportHtmlDashboard(history, config, verdictReason, semanticReport, {
381
409
  total1xx: metrics.c1xx,
382
410
  total2xx: metrics.c2xx,
383
411
  total3xx: metrics.c3xx,
384
412
  total4xx: metrics.c4xx,
385
- total5xx: metrics.c5xx
413
+ total5xx: metrics.c5xx,
414
+ breakdownRates
386
415
  }, finalSummaryCards, rawRequests);
387
416
  }
388
417
  function getFallbackClusterLogs() {
@@ -411,7 +440,8 @@ function generateSimulationData(threads, durationSec, maxAllowedLatencyMs) {
411
440
  let errorMessage;
412
441
  let statusCode = 200;
413
442
  if (isError) {
414
- statusCode = Math.random() > 0.3 ? 500 : 404;
443
+ const targetResponseCodes = [400, 401, 403, 404, 429, 500, 502, 503, 504];
444
+ statusCode = targetResponseCodes[Math.floor(Math.random() * targetResponseCodes.length)];
415
445
  errorMessage = errorPool[Math.floor(Math.random() * errorPool.length)];
416
446
  }
417
447
  data.push({
@@ -437,12 +467,16 @@ function processMetricsTelemetry(requests, durationSec) {
437
467
  const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
438
468
  const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
439
469
  let c1xx = 0, c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
470
+ const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 502, 502: 0, 503: 0, 504: 0 };
440
471
  requests.forEach((r) => {
441
472
  if (r.statusCode >= 100 && r.statusCode < 200) c1xx++;
442
473
  else if (r.statusCode >= 200 && r.statusCode < 300) c2xx++;
443
474
  else if (r.statusCode >= 300 && r.statusCode < 400) c3xx++;
444
475
  else if (r.statusCode >= 400 && r.statusCode < 500) c4xx++;
445
476
  else if (r.statusCode >= 500) c5xx++;
477
+ if (r.statusCode in codeCounts) {
478
+ codeCounts[r.statusCode]++;
479
+ }
446
480
  });
447
481
  const errorCount = c4xx + c5xx;
448
482
  const errorRate = totalRequests === 0 ? 0 : errorCount / totalRequests;
@@ -468,7 +502,8 @@ function processMetricsTelemetry(requests, durationSec) {
468
502
  avgTcpMs,
469
503
  avgTlsMs,
470
504
  avgTtfbMs,
471
- bandwidthMb
505
+ bandwidthMb,
506
+ codeCounts
472
507
  };
473
508
  }
474
509
  function printMatrixDashboard(m, threads) {
@@ -479,7 +514,7 @@ function printMatrixDashboard(m, threads) {
479
514
  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)} |`);
480
515
  console.log(`-----------------------------------------------------------------------------------------`);
481
516
  }
482
- function generateFinalAgentReport(history) {
517
+ function generateFinalAgentReport(history, score) {
483
518
  if (history.length === 0) return;
484
519
  const peakThroughput = Math.max(...history.map((h) => h.throughput));
485
520
  const cleanRuns = history.filter((h) => h.apdex >= 0.85 && h.errorRate <= 0.01);
@@ -487,6 +522,7 @@ function generateFinalAgentReport(history) {
487
522
  console.log("\n=======================================================");
488
523
  console.log("\u{1F9E0} INTELLIGENT AUTONOMOUS LOAD AGENT FINAL REPORT");
489
524
  console.log("=======================================================");
525
+ console.log(`\u{1F49A} Unified Blaze Health Score : ${score}/100`);
490
526
  console.log(`\u{1F3C6} Recommended Max Safe Concurrency : ${maxSafeThreads} allocation threads`);
491
527
  console.log(`\u{1F4A5} Infrastructure Failure Boundary : ${history[history.length - 1].threads} concurrency allocation`);
492
528
  console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
@@ -577,8 +613,8 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
577
613
  <div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b; text-align: center;">
578
614
  <div class="card-title" style="color: #94a3b8;">Est. Organic Traffic Loss</div>
579
615
  <div style="font-size: 2rem; font-weight: bold; color: ${seoMetrics.color};">
580
- ${seoMetrics.trafficLoss > 0 ? "-" : ""}${seoMetrics.trafficLoss}%
581
- </div>
616
+ ${seoMetrics.trafficLoss > 0 ? "-" : ""}${seoMetrics.trafficLoss}%
617
+ </div>
582
618
  <div style="font-size: 0.8rem; color: #64748b; margin-top: 0.25rem;">compared to 200ms sweet-spot</div>
583
619
  </div>
584
620
  <div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b;">
@@ -637,6 +673,18 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
637
673
  </div>
638
674
  </div>
639
675
  </div>`;
676
+ const breakdownRates = responseMatrix.breakdownRates || {};
677
+ const breakdownGridHtml = [400, 401, 403, 404, 429, 500, 502, 503, 504].map((code) => {
678
+ const rate = breakdownRates[code] || 0;
679
+ const displayColor = rate > 0 ? code >= 500 ? "#f87171" : "#fde047" : "#64748b";
680
+ return `
681
+ <div style="background: #090d16; border: 1px solid #1e293b; border-radius: 4px; padding: 0.4rem 0.2rem; text-align: center;">
682
+ <div style="font-size: 0.7rem; color: #64748b; font-weight: bold;">${code}</div>
683
+ <div style="font-size: 0.85rem; font-weight: bold; color: ${displayColor};">${rate.toFixed(2)}%</div>
684
+ </div>
685
+ `;
686
+ }).join("");
687
+ const gaugeColor = cards.healthScore >= 90 ? "#10b981" : cards.healthScore >= 70 ? "#f59e0b" : "#ef4444";
640
688
  const htmlContent = `<!DOCTYPE html><html lang="en"><head>
641
689
  <meta charset="UTF-8">
642
690
  <title>Blaze Core Performance Report</title>
@@ -658,13 +706,16 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
658
706
  .card-value.purple { color: #a855f7; }
659
707
  .card-subtext { font-size: 0.8rem; color: #10b981; font-weight: 500; margin-left: 0.4rem; display: inline-block; }
660
708
 
661
- .top-layout-grid { display: grid; grid-template-columns: 1fr 400px; gap: 1.5rem; margin-bottom: 2rem; }
709
+ .top-layout-grid { display: grid; grid-template-columns: 1fr 280px 380px; gap: 1.5rem; margin-bottom: 2rem; }
662
710
  .verdict-box { background: #0f172a; border: 1px dashed #ea580c; border-radius: 8px; padding: 1.25rem; }
663
711
  .verdict-title { text-transform: uppercase; font-size: 0.85rem; font-weight: 700; color: #f97316; margin-bottom: 0.5rem; }
664
712
  .verdict-text { font-size: 0.95rem; line-height: 1.5; color: #e2e8f0; margin-bottom: 0.75rem; }
665
713
  .verdict-waves { background: #1f2937; border-radius: 6px; padding: 0.75rem 1rem; font-family: monospace; color: #9ca3af; font-size: 0.9rem; }
666
714
  .wave-item { margin: 0.25rem 0; }
667
715
 
716
+ .gauge-container-box { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.25rem; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; }
717
+ .gauge-title { font-size: 0.85rem; font-weight: bold; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 1rem; }
718
+
668
719
  .matrix-box { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.25rem; }
669
720
  .matrix-title { font-size: 1.1rem; font-weight: bold; color: #ffffff; margin-bottom: 1rem; }
670
721
  .matrix-box .matrix-row { display: flex; justify-content: space-between; align-items: center; padding: 0.6rem 0; border-bottom: 1px solid #1e293b; }
@@ -739,6 +790,26 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
739
790
  <div class="verdict-waves">${waveListItems}</div>
740
791
  </div>
741
792
 
793
+ <!-- IMPLEMENTED CARD FEATURE 76: Executive Health Gauges Panel -->
794
+ <div class="gauge-container-box">
795
+ <div class="gauge-title">Blaze Run Health Score</div>
796
+ <div style="position: relative; width: 140px; height: 140px; display: flex; align-items: center; justify-content: center;">
797
+ <svg width="140" height="140" viewBox="0 0 140 140" style="transform: rotate(-90deg);">
798
+ <circle cx="70" cy="70" r="58" stroke="#1e293b" stroke-width="12" fill="transparent"/>
799
+ <circle cx="70" cy="70" r="58" stroke="${gaugeColor}" stroke-width="12" fill="transparent"
800
+ stroke-dasharray="364.4" stroke-dashoffset="${364.4 - 364.4 * cards.healthScore / 100}"
801
+ stroke-linecap="round" style="transition: stroke-dashoffset 1s ease-out;"/>
802
+ </svg>
803
+ <div style="position: absolute; text-align: center;">
804
+ <div style="font-size: 2.2rem; font-weight: 800; color: #ffffff; line-height: 1;">${cards.healthScore}</div>
805
+ <div style="font-size: 0.75rem; color: #64748b; font-weight: bold; margin-top: 0.2rem; text-transform: uppercase;">/ 100</div>
806
+ </div>
807
+ </div>
808
+ <div style="margin-top: 0.75rem; font-size: 0.8rem; color: #94a3b8; font-weight: 500;">
809
+ Composite Run Quality Engine Rating
810
+ </div>
811
+ </div>
812
+
742
813
  <div class="matrix-box">
743
814
  <div class="matrix-title">\u{1F4CB} HTTP Response Matrix</div>
744
815
  <div class="matrix-row">
@@ -761,6 +832,13 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
761
832
  <div class="matrix-label">Server Error <span class="matrix-badge badge-5xx">5xx</span></div>
762
833
  <div class="matrix-value">${responseMatrix.total5xx}</div>
763
834
  </div>
835
+
836
+ <div class="matrix-title" style="margin-top: 1.5rem; font-size: 0.85rem; border-top: 1px solid #1e293b; padding-top: 1rem; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.05em;">
837
+ \u{1F522} HTTP Status Code Breakdown Rate
838
+ </div>
839
+ <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; margin-top: 0.5rem;">
840
+ ${breakdownGridHtml}
841
+ </div>
764
842
  </div>
765
843
  </div>
766
844
 
@@ -833,7 +911,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
833
911
  const baseThroughput = ${cards.throughput};
834
912
  const baseLatency = ${cards.ttfb};
835
913
 
836
- // Live Concurrency Adjuster interactive client logic
837
914
  const slider = document.getElementById('concurrencySlider');
838
915
  const sliderVal = document.getElementById('sliderValue');
839
916
  const simThroughput = document.getElementById('simThroughput');
@@ -939,9 +1016,9 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
939
1016
  responsive: true,
940
1017
  maintainAspectRatio: false,
941
1018
  plugins: {
942
- legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } }
943
- },
944
- cutout: '65%'
1019
+ legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } },
1020
+ cutout: '65%'
1021
+ }
945
1022
  }
946
1023
  });
947
1024
 
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blaze-performance-tester",
3
- "version": "3.1.20",
3
+ "version": "3.1.22",
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",