blaze-performance-tester 3.1.22 → 3.1.24
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 +124 -201
- package/dist/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -467,7 +467,7 @@ function processMetricsTelemetry(requests, durationSec) {
|
|
|
467
467
|
const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
|
|
468
468
|
const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
|
|
469
469
|
let c1xx = 0, c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
|
|
470
|
-
const codeCounts = { 400: 0, 401: 0, 403: 0, 404:
|
|
470
|
+
const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 429, 429: 0, 500: 0, 502: 0, 503: 0, 504: 0 };
|
|
471
471
|
requests.forEach((r) => {
|
|
472
472
|
if (r.statusCode >= 100 && r.statusCode < 200) c1xx++;
|
|
473
473
|
else if (r.statusCode >= 200 && r.statusCode < 300) c2xx++;
|
|
@@ -550,7 +550,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
550
550
|
const totalLogCount = semanticReport.clusters.reduce((sum, c) => sum + c.count, 0);
|
|
551
551
|
const uniquePatternsCount = semanticReport.clusters.length;
|
|
552
552
|
logClustersHtml = `
|
|
553
|
-
<div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
|
|
553
|
+
<div class="card p-dev" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
|
|
554
554
|
<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
555
|
\u{1F9E0} Semantic Log Clustering & Error Classification
|
|
556
556
|
</h3>
|
|
@@ -564,7 +564,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
564
564
|
<th style="width: 8%; padding: 0.75rem; text-align: left; color: #64748b; font-size: 0.85rem; font-weight: bold; text-transform: none;">Count</th>
|
|
565
565
|
<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>
|
|
566
566
|
<th style="width: 10%; padding: 0.75rem; text-align: left; color: #64748b; font-size: 0.85rem; font-weight: bold; text-transform: none;">Severity</th>
|
|
567
|
-
<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
|
|
567
|
+
<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</th>
|
|
568
568
|
</tr>
|
|
569
569
|
</thead>
|
|
570
570
|
<tbody>
|
|
@@ -572,7 +572,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
572
572
|
let catColor = "#fb923c";
|
|
573
573
|
if (c.category === "Authentication_Error") catColor = "#c084fc";
|
|
574
574
|
if (c.category === "Product_Error") catColor = "#f87171";
|
|
575
|
-
if (c.category === "Environment_Infrastructure_Error") catColor = "#fb923c";
|
|
576
575
|
let sevBg = c.severity === "CRITICAL" ? "#dc2626" : "#ea580c";
|
|
577
576
|
const rawTemplate = c.template || "";
|
|
578
577
|
const cleanedTemplate = rawTemplate.replace(/\[\d{4}-\d{2}-\d{2}.*?\]\s*/, "");
|
|
@@ -587,9 +586,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
587
586
|
<div style="background: #090d16; border-radius: 4px; padding: 0.6rem 0.8rem; border-left: 3px solid #1e293b; margin-bottom: 0.5rem;">
|
|
588
587
|
<code style="color: #cbd5e1; font-family: monospace; font-size: 0.9rem; white-space: pre-wrap; word-break: break-all;">${cleanedTemplate}</code>
|
|
589
588
|
</div>
|
|
590
|
-
<div style="color: #64748b; font-size: 0.8rem; font-family: monospace; padding-left: 0.2rem; line-height: 1.4;">
|
|
591
|
-
<span style="color: #475569;">Real Example Trace:</span> ${rawTemplate}
|
|
592
|
-
</div>
|
|
593
589
|
</td>
|
|
594
590
|
</tr>`;
|
|
595
591
|
}).join("")}
|
|
@@ -602,25 +598,20 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
602
598
|
const finalLatency = history[history.length - 1]?.avgLatency || cards.ttfb;
|
|
603
599
|
const seoMetrics = calculateSeoImpactMetrics(finalLatency);
|
|
604
600
|
seoImpactSectionHtml = `
|
|
605
|
-
<div class="card" style="margin-top: 2rem; background: #111a2e; border: 1px solid #1e3a8a;">
|
|
601
|
+
<div class="card p-exec" style="margin-top: 2rem; background: #111a2e; border: 1px solid #1e3a8a;">
|
|
606
602
|
<h3 style="color: #f43f5e; display: flex; align-items: center; gap: 0.6rem; font-size: 1.2rem; border-bottom: 1px solid #1e293b; padding-bottom: 0.5rem;">
|
|
607
603
|
\u{1F50E} SEO Rank Impact & Visibility Loss Predictor
|
|
608
604
|
</h3>
|
|
609
|
-
<p style="color: #94a3b8; font-size: 0.9rem; margin-bottom: 1.5rem;">
|
|
610
|
-
Translates response time infrastructure load stress into Core Web Vitals ranking drops and organic search volume degradation metrics.
|
|
611
|
-
</p>
|
|
612
605
|
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem;">
|
|
613
606
|
<div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b; text-align: center;">
|
|
614
607
|
<div class="card-title" style="color: #94a3b8;">Est. Organic Traffic Loss</div>
|
|
615
608
|
<div style="font-size: 2rem; font-weight: bold; color: ${seoMetrics.color};">
|
|
616
609
|
${seoMetrics.trafficLoss > 0 ? "-" : ""}${seoMetrics.trafficLoss}%
|
|
617
610
|
</div>
|
|
618
|
-
<div style="font-size: 0.8rem; color: #64748b; margin-top: 0.25rem;">compared to 200ms sweet-spot</div>
|
|
619
611
|
</div>
|
|
620
612
|
<div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
621
613
|
<div class="card-title">Search Visibility Status</div>
|
|
622
614
|
<div style="font-size: 1.25rem; font-weight: bold; color: ${seoMetrics.color}; margin-top: 0.4rem;">${seoMetrics.status}</div>
|
|
623
|
-
<div style="font-size: 0.8rem; color: #94a3b8; margin-top: 0.25rem;">Target Latency: ${finalLatency.toFixed(1)}ms</div>
|
|
624
615
|
</div>
|
|
625
616
|
<div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
626
617
|
<div class="card-title">Googlebot Crawl Budget Impact</div>
|
|
@@ -630,7 +621,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
630
621
|
</div>`;
|
|
631
622
|
}
|
|
632
623
|
const liveAdjusterHtml = `
|
|
633
|
-
<div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
|
|
624
|
+
<div class="card p-devops" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
|
|
634
625
|
<h3 style="color: #38bdf8; display: flex; align-items: center; gap: 0.5rem; font-size: 1.2rem; margin-bottom: 1rem;">
|
|
635
626
|
\u{1F39B}\uFE0F Live Concurrency Adjuster (Mid-Test Simulation)
|
|
636
627
|
</h3>
|
|
@@ -646,30 +637,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
646
637
|
<div style="font-size: 0.7rem; color: #64748b; text-transform: uppercase;">Sim. Throughput</div>
|
|
647
638
|
<div id="simThroughput" style="font-size: 1.2rem; font-weight: bold; color: #f97316;">${cards.throughput.toFixed(0)}/s</div>
|
|
648
639
|
</div>
|
|
649
|
-
<div style="background: #090d16; padding: 0.75rem 1rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
650
|
-
<div style="font-size: 0.7rem; color: #64748b; text-transform: uppercase;">Sim. Latency</div>
|
|
651
|
-
<div id="simLatency" style="font-size: 1.2rem; font-weight: bold; color: #10b981;">${cards.ttfb.toFixed(1)}ms</div>
|
|
652
|
-
</div>
|
|
653
|
-
</div>
|
|
654
|
-
</div>
|
|
655
|
-
</div>`;
|
|
656
|
-
const rightSizingHtml = `
|
|
657
|
-
<div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
|
|
658
|
-
<h3 style="color: #38bdf8; display: flex; align-items: center; gap: 0.5rem; font-size: 1.2rem;">
|
|
659
|
-
\u2601\uFE0F Infrastructure Right-Sizing & Cloud Cost Projections
|
|
660
|
-
</h3>
|
|
661
|
-
<div style="grid-template-columns: repeat(3, 1fr); display: grid; gap: 1rem; margin-top: 1rem;">
|
|
662
|
-
<div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
663
|
-
<div class="card-title">Est. Monthly Cloud Cost</div>
|
|
664
|
-
<div class="card-value green">$${estimatedMonthlyCost} <span class="unit">/mo</span></div>
|
|
665
|
-
</div>
|
|
666
|
-
<div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
667
|
-
<div class="card-title">Recommended CPU Right-Sizing</div>
|
|
668
|
-
<div class="card-value purple">${recommendedCpuCores} <span class="unit">vCores</span></div>
|
|
669
|
-
</div>
|
|
670
|
-
<div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
671
|
-
<div class="card-title">Recommended Memory Allocation</div>
|
|
672
|
-
<div class="card-value orange">${recommendedRamGb} <span class="unit">GB RAM</span></div>
|
|
673
640
|
</div>
|
|
674
641
|
</div>
|
|
675
642
|
</div>`;
|
|
@@ -692,10 +659,15 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
692
659
|
<style>
|
|
693
660
|
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #0b111e; color: #f8fafc; margin: 0; padding: 2rem; }
|
|
694
661
|
.container { max-width: 1300px; margin: 0 auto; }
|
|
695
|
-
.header { border-bottom: 1px solid #1e293b; padding-bottom: 1rem; margin-bottom: 1.5rem; }
|
|
662
|
+
.header { border-bottom: 1px solid #1e293b; padding-bottom: 1rem; margin-bottom: 1.5rem; display: flex; justify-content: space-between; align-items: center; }
|
|
696
663
|
h1 { color: #38bdf8; margin: 0; font-size: 2rem; }
|
|
697
664
|
.meta { color: #94a3b8; font-size: 0.9rem; margin-top: 0.5rem; }
|
|
698
665
|
|
|
666
|
+
/* Persona Controls Styling */
|
|
667
|
+
.persona-toggle-container { background: #131c2e; padding: 0.5rem 1rem; border-radius: 8px; border: 1px solid #1e293b; display: flex; align-items: center; gap: 0.75rem; }
|
|
668
|
+
.persona-btn { background: #090d16; border: 1px solid #1e293b; color: #94a3b8; padding: 0.4rem 1rem; font-size: 0.85rem; font-weight: 600; border-radius: 6px; cursor: pointer; transition: all 0.2s ease; }
|
|
669
|
+
.persona-btn.active { background: #38bdf8; border-color: #38bdf8; color: #0b111e; }
|
|
670
|
+
|
|
699
671
|
.cards-wrapper { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 1.5rem; }
|
|
700
672
|
.metric-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 6px; padding: 1.25rem; position: relative; }
|
|
701
673
|
.card-title { font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.5rem; }
|
|
@@ -716,7 +688,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
716
688
|
.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
689
|
.gauge-title { font-size: 0.85rem; font-weight: bold; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 1rem; }
|
|
718
690
|
|
|
719
|
-
.matrix-box { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.25rem; }
|
|
691
|
+
.matrix-box { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.25rem; display: flex; flex-direction: column; justify-content: space-between; }
|
|
720
692
|
.matrix-title { font-size: 1.1rem; font-weight: bold; color: #ffffff; margin-bottom: 1rem; }
|
|
721
693
|
.matrix-box .matrix-row { display: flex; justify-content: space-between; align-items: center; padding: 0.6rem 0; border-bottom: 1px solid #1e293b; }
|
|
722
694
|
.matrix-box .matrix-row:last-child { border-bottom: none; }
|
|
@@ -744,127 +716,129 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
744
716
|
</style></head><body>
|
|
745
717
|
<div class="container">
|
|
746
718
|
<div class="header">
|
|
747
|
-
<
|
|
748
|
-
|
|
719
|
+
<div>
|
|
720
|
+
<h1>\u{1F525} Blaze Core Performance Analysis</h1>
|
|
721
|
+
<div class="meta">Target Script: <code>${config.targetScript}</code></div>
|
|
722
|
+
</div>
|
|
723
|
+
|
|
724
|
+
<!-- Persona View Switcher Selector Elements -->
|
|
725
|
+
<div class="persona-toggle-container">
|
|
726
|
+
<span style="font-size: 0.8rem; color: #64748b; font-weight: bold; text-transform: uppercase;">View Perspective:</span>
|
|
727
|
+
<button class="persona-btn active" onclick="switchPersona('developer', this)">Developer</button>
|
|
728
|
+
<button class="persona-btn" onclick="switchPersona('devops', this)">DevOps</button>
|
|
729
|
+
<button class="persona-btn" onclick="switchPersona('executive', this)">Executive</button>
|
|
730
|
+
</div>
|
|
749
731
|
</div>
|
|
750
732
|
|
|
751
733
|
<div class="cards-wrapper">
|
|
752
|
-
<div class="metric-card">
|
|
734
|
+
<div class="metric-card p-dev">
|
|
753
735
|
<div class="card-title">Apdex Score (T: 50ms)</div>
|
|
754
736
|
<div class="card-value green">${cards.apdex.toFixed(2)}<span class="card-subtext">(Good)</span></div>
|
|
755
737
|
</div>
|
|
756
|
-
<div class="metric-card">
|
|
738
|
+
<div class="metric-card p-devops p-exec">
|
|
757
739
|
<div class="card-title">Throughput</div>
|
|
758
740
|
<div class="card-value orange">${cards.throughput.toFixed(1)}<span class="unit">/s</span></div>
|
|
759
741
|
</div>
|
|
760
|
-
<div class="metric-card">
|
|
742
|
+
<div class="metric-card p-devops">
|
|
761
743
|
<div class="card-title">Network Bandwidth</div>
|
|
762
744
|
<div class="card-value purple">${cards.bandwidth.toFixed(2)}<span class="unit">MB/s</span></div>
|
|
763
745
|
</div>
|
|
764
|
-
<div class="metric-card">
|
|
746
|
+
<div class="metric-card p-devops">
|
|
765
747
|
<div class="card-title">Avg Time To First Byte</div>
|
|
766
748
|
<div class="card-value">${cards.ttfb.toFixed(1)}<span class="unit">ms</span></div>
|
|
767
749
|
</div>
|
|
768
|
-
<div class="metric-card">
|
|
750
|
+
<div class="metric-card p-dev">
|
|
769
751
|
<div class="card-title">DNS Lookup</div>
|
|
770
752
|
<div class="card-value">${cards.dns.toFixed(2)}<span class="unit">ms</span></div>
|
|
771
753
|
</div>
|
|
772
|
-
<div class="metric-card">
|
|
754
|
+
<div class="metric-card p-dev">
|
|
773
755
|
<div class="card-title">TCP Connect</div>
|
|
774
756
|
<div class="card-value">${cards.tcp.toFixed(2)}<span class="unit">ms</span></div>
|
|
775
757
|
</div>
|
|
776
|
-
<div class="metric-card">
|
|
758
|
+
<div class="metric-card p-dev">
|
|
777
759
|
<div class="card-title">TLS Handshake</div>
|
|
778
760
|
<div class="card-value">${cards.tls.toFixed(2)}<span class="unit">ms</span></div>
|
|
779
761
|
</div>
|
|
780
|
-
<div class="metric-card">
|
|
762
|
+
<div class="metric-card p-dev p-exec">
|
|
781
763
|
<div class="card-title">Stability (Std Dev)</div>
|
|
782
764
|
<div class="card-value">±${cards.stdDev.toFixed(1)}<span class="unit">ms</span></div>
|
|
783
765
|
</div>
|
|
784
766
|
</div>
|
|
785
767
|
|
|
786
768
|
<div class="top-layout-grid">
|
|
787
|
-
<div class="verdict-box">
|
|
769
|
+
<div class="verdict-box p-devops p-exec">
|
|
788
770
|
<div class="verdict-title">\u{1F916} AI Stress-Testing Agent Verdict</div>
|
|
789
771
|
<div class="verdict-text">${verdictReason}</div>
|
|
790
772
|
<div class="verdict-waves">${waveListItems}</div>
|
|
791
773
|
</div>
|
|
792
774
|
|
|
793
|
-
|
|
794
|
-
<div class="gauge-container-box">
|
|
775
|
+
<div class="gauge-container-box p-exec p-devops">
|
|
795
776
|
<div class="gauge-title">Blaze Run Health Score</div>
|
|
796
777
|
<div style="position: relative; width: 140px; height: 140px; display: flex; align-items: center; justify-content: center;">
|
|
797
778
|
<svg width="140" height="140" viewBox="0 0 140 140" style="transform: rotate(-90deg);">
|
|
798
779
|
<circle cx="70" cy="70" r="58" stroke="#1e293b" stroke-width="12" fill="transparent"/>
|
|
799
780
|
<circle cx="70" cy="70" r="58" stroke="${gaugeColor}" stroke-width="12" fill="transparent"
|
|
800
781
|
stroke-dasharray="364.4" stroke-dashoffset="${364.4 - 364.4 * cards.healthScore / 100}"
|
|
801
|
-
stroke-linecap="round"
|
|
782
|
+
stroke-linecap="round"/>
|
|
802
783
|
</svg>
|
|
803
784
|
<div style="position: absolute; text-align: center;">
|
|
804
785
|
<div style="font-size: 2.2rem; font-weight: 800; color: #ffffff; line-height: 1;">${cards.healthScore}</div>
|
|
805
786
|
<div style="font-size: 0.75rem; color: #64748b; font-weight: bold; margin-top: 0.2rem; text-transform: uppercase;">/ 100</div>
|
|
806
787
|
</div>
|
|
807
788
|
</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
789
|
</div>
|
|
812
790
|
|
|
813
|
-
<div class="matrix-box">
|
|
814
|
-
<div
|
|
815
|
-
|
|
816
|
-
<div class="matrix-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
<div class="matrix-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
<div class="matrix-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
<div class="matrix-label">Client Error <span class="matrix-badge badge-4xx">4xx</span></div>
|
|
829
|
-
<div class="matrix-value">${responseMatrix.total4xx}</div>
|
|
830
|
-
</div>
|
|
831
|
-
<div class="matrix-row">
|
|
832
|
-
<div class="matrix-label">Server Error <span class="matrix-badge badge-5xx">5xx</span></div>
|
|
833
|
-
<div class="matrix-value">${responseMatrix.total5xx}</div>
|
|
791
|
+
<div class="matrix-box p-devops p-dev">
|
|
792
|
+
<div>
|
|
793
|
+
<div class="matrix-title">\u{1F4CB} HTTP Response Matrix</div>
|
|
794
|
+
<div class="matrix-row">
|
|
795
|
+
<div class="matrix-label">Successful <span class="matrix-badge badge-2xx">2xx</span></div>
|
|
796
|
+
<div class="matrix-value">${responseMatrix.total2xx}</div>
|
|
797
|
+
</div>
|
|
798
|
+
<div class="matrix-row">
|
|
799
|
+
<div class="matrix-label">Client Error <span class="matrix-badge badge-4xx">4xx</span></div>
|
|
800
|
+
<div class="matrix-value">${responseMatrix.total4xx}</div>
|
|
801
|
+
</div>
|
|
802
|
+
<div class="matrix-row">
|
|
803
|
+
<div class="matrix-label">Server Error <span class="matrix-badge badge-5xx">5xx</span></div>
|
|
804
|
+
<div class="matrix-value">${responseMatrix.total5xx}</div>
|
|
805
|
+
</div>
|
|
834
806
|
</div>
|
|
835
807
|
|
|
836
|
-
<div
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
808
|
+
<div>
|
|
809
|
+
<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;">
|
|
810
|
+
\u{1F522} HTTP Status Code Breakdown Rate
|
|
811
|
+
</div>
|
|
812
|
+
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; margin-top: 0.5rem;">
|
|
813
|
+
${breakdownGridHtml}
|
|
814
|
+
</div>
|
|
841
815
|
</div>
|
|
842
816
|
</div>
|
|
843
817
|
</div>
|
|
844
818
|
|
|
845
819
|
<div class="charts-grid">
|
|
846
|
-
<div class="graph-card">
|
|
820
|
+
<div class="graph-card p-devops">
|
|
847
821
|
<div class="graph-title">\u{1F4CA} Throughput Velocity & Workload Volume</div>
|
|
848
822
|
<div style="height: 280px; position: relative;">
|
|
849
823
|
<canvas id="volumeChart"></canvas>
|
|
850
824
|
</div>
|
|
851
825
|
</div>
|
|
852
826
|
|
|
853
|
-
<div class="graph-card">
|
|
827
|
+
<div class="graph-card p-devops">
|
|
854
828
|
<div class="graph-title">\u{1F504} Active Concurrency (VUs) vs. TTF Trend</div>
|
|
855
829
|
<div style="height: 280px; position: relative;">
|
|
856
830
|
<canvas id="concurrencyChart"></canvas>
|
|
857
831
|
</div>
|
|
858
832
|
</div>
|
|
859
833
|
|
|
860
|
-
<div class="graph-card">
|
|
834
|
+
<div class="graph-card p-dev">
|
|
861
835
|
<div class="graph-title">\u{1F369} HTTP Status Code Proportions</div>
|
|
862
836
|
<div style="height: 280px; position: relative;">
|
|
863
837
|
<canvas id="statusDonutChart"></canvas>
|
|
864
838
|
</div>
|
|
865
839
|
</div>
|
|
866
840
|
|
|
867
|
-
<div class="graph-card">
|
|
841
|
+
<div class="graph-card p-dev">
|
|
868
842
|
<div class="graph-title">\u{1F4C8} Time-to-First-Byte Scatter Plot</div>
|
|
869
843
|
<div style="height: 280px; position: relative;">
|
|
870
844
|
<canvas id="ttfbScatterChart"></canvas>
|
|
@@ -872,7 +846,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
872
846
|
</div>
|
|
873
847
|
</div>
|
|
874
848
|
|
|
875
|
-
<div class="card">
|
|
849
|
+
<div class="card p-dev">
|
|
876
850
|
<h3>Telemetry Matrix Logs</h3>
|
|
877
851
|
<table>
|
|
878
852
|
<thead>
|
|
@@ -881,7 +855,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
881
855
|
<th>Throughput</th>
|
|
882
856
|
<th>Avg Latency</th>
|
|
883
857
|
<th>P95 Latency</th>
|
|
884
|
-
<th>Error Rate</th>
|
|
885
858
|
<th>Status</th>
|
|
886
859
|
</tr>
|
|
887
860
|
</thead>
|
|
@@ -893,7 +866,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
893
866
|
<td>${h.throughput.toFixed(0)} req/sec</td>
|
|
894
867
|
<td>${h.avgLatency.toFixed(1)} ms</td>
|
|
895
868
|
<td>${h.p95Latency.toFixed(1)} ms</td>
|
|
896
|
-
<td>${(h.errorRate * 100).toFixed(2)}%</td>
|
|
897
869
|
<td><span class="badge ${isPassed ? "badge-success" : "badge-fail"}">${isPassed ? "SLO PASS" : "SLO BREACH"}</span></td>
|
|
898
870
|
</tr>`;
|
|
899
871
|
}).join("")}
|
|
@@ -909,142 +881,93 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
909
881
|
<script>
|
|
910
882
|
const labels = ${JSON.stringify(labels)};
|
|
911
883
|
const baseThroughput = ${cards.throughput};
|
|
912
|
-
const baseLatency = ${cards.ttfb};
|
|
913
884
|
|
|
914
885
|
const slider = document.getElementById('concurrencySlider');
|
|
915
886
|
const sliderVal = document.getElementById('sliderValue');
|
|
916
887
|
const simThroughput = document.getElementById('simThroughput');
|
|
917
|
-
const simLatency = document.getElementById('simLatency');
|
|
918
888
|
|
|
919
|
-
slider
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
889
|
+
if(slider) {
|
|
890
|
+
slider.addEventListener('input', (e) => {
|
|
891
|
+
const val = parseInt(e.target.value, 10);
|
|
892
|
+
sliderVal.textContent = val;
|
|
893
|
+
const factor = val / ${config.threads || 10};
|
|
894
|
+
simThroughput.textContent = (baseThroughput * Math.min(factor, 2.5)).toFixed(0) + '/s';
|
|
895
|
+
});
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
// Global register tracking charts for explicit redraw logic execution
|
|
899
|
+
const activeCharts = [];
|
|
900
|
+
|
|
901
|
+
function switchPersona(persona, targetBtn) {
|
|
902
|
+
if (targetBtn) {
|
|
903
|
+
document.querySelectorAll('.persona-btn').forEach(btn => btn.classList.remove('active'));
|
|
904
|
+
targetBtn.classList.add('active');
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
// Hide all dynamic viewport configurations
|
|
908
|
+
const layouts = ['.p-dev', '.p-devops', '.p-exec'];
|
|
909
|
+
layouts.forEach(selector => {
|
|
910
|
+
document.querySelectorAll(selector).forEach(el => el.style.display = 'none');
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
// Target current selector views for block visibility execution
|
|
914
|
+
document.querySelectorAll('.p-' + persona).forEach(el => {
|
|
915
|
+
if (el.tagName === 'TR') el.style.display = 'table-row';
|
|
916
|
+
else if (el.classList.contains('metric-card')) el.style.display = 'block';
|
|
917
|
+
else el.style.display = '';
|
|
918
|
+
});
|
|
919
|
+
|
|
920
|
+
// AUTO-REFRESH IMPLEMENTATION: Triggers sizing layout re-calculations on unhidden canvases
|
|
921
|
+
activeCharts.forEach(chart => {
|
|
922
|
+
if (chart) {
|
|
923
|
+
chart.resize();
|
|
924
|
+
chart.update('active');
|
|
925
|
+
}
|
|
926
|
+
});
|
|
927
|
+
}
|
|
926
928
|
|
|
927
|
-
new Chart(document.getElementById('volumeChart'), {
|
|
929
|
+
activeCharts.push(new Chart(document.getElementById('volumeChart'), {
|
|
928
930
|
type: 'bar',
|
|
929
931
|
data: {
|
|
930
932
|
labels: labels,
|
|
931
933
|
datasets: [
|
|
932
|
-
{
|
|
933
|
-
|
|
934
|
-
data: ${JSON.stringify(successRequestsData)},
|
|
935
|
-
backgroundColor: '#10b981',
|
|
936
|
-
stack: 'requests',
|
|
937
|
-
barPercentage: 0.95,
|
|
938
|
-
categoryPercentage: 0.95
|
|
939
|
-
},
|
|
940
|
-
{
|
|
941
|
-
label: 'Failed Workloads',
|
|
942
|
-
data: ${JSON.stringify(failedWorkloadsData)},
|
|
943
|
-
backgroundColor: '#ef4444',
|
|
944
|
-
stack: 'requests',
|
|
945
|
-
barPercentage: 0.95,
|
|
946
|
-
categoryPercentage: 0.95
|
|
947
|
-
}
|
|
934
|
+
{ label: 'Successful Requests', data: ${JSON.stringify(successRequestsData)}, backgroundColor: '#10b981', stack: 'requests' },
|
|
935
|
+
{ label: 'Failed Workloads', data: ${JSON.stringify(failedWorkloadsData)}, backgroundColor: '#ef4444', stack: 'requests' }
|
|
948
936
|
]
|
|
949
937
|
},
|
|
950
|
-
options: {
|
|
951
|
-
|
|
952
|
-
maintainAspectRatio: false,
|
|
953
|
-
plugins: {
|
|
954
|
-
legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } }
|
|
955
|
-
},
|
|
956
|
-
scales: {
|
|
957
|
-
x: { grid: { color: '#1e293b' }, ticks: { color: '#64748b' } },
|
|
958
|
-
y: { stacked: true, grid: { color: '#1e293b' }, ticks: { color: '#64748b' } }
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
});
|
|
938
|
+
options: { responsive: true, maintainAspectRatio: false, scales: { x: { grid: { color: '#1e293b' } }, y: { stacked: true, grid: { color: '#1e293b' } } } }
|
|
939
|
+
}));
|
|
962
940
|
|
|
963
|
-
new Chart(document.getElementById('concurrencyChart'), {
|
|
941
|
+
activeCharts.push(new Chart(document.getElementById('concurrencyChart'), {
|
|
964
942
|
type: 'line',
|
|
965
943
|
data: {
|
|
966
944
|
labels: labels,
|
|
967
945
|
datasets: [
|
|
968
|
-
{
|
|
969
|
-
|
|
970
|
-
data: ${JSON.stringify(activeThreadsData)},
|
|
971
|
-
borderColor: '#38bdf8',
|
|
972
|
-
backgroundColor: 'rgba(56, 189, 248, 0.1)',
|
|
973
|
-
borderWidth: 2.5,
|
|
974
|
-
pointRadius: 4,
|
|
975
|
-
fill: true,
|
|
976
|
-
yAxisID: 'yThreads'
|
|
977
|
-
},
|
|
978
|
-
{
|
|
979
|
-
label: 'Time-to-Failure (TTF) Trend',
|
|
980
|
-
data: ${JSON.stringify(ttfTrendData)},
|
|
981
|
-
borderColor: '#f43f5e',
|
|
982
|
-
borderWidth: 2,
|
|
983
|
-
borderDash: [5, 5],
|
|
984
|
-
pointRadius: 3,
|
|
985
|
-
fill: false,
|
|
986
|
-
yAxisID: 'yTtf'
|
|
987
|
-
}
|
|
946
|
+
{ label: 'Active VU Threads', data: ${JSON.stringify(activeThreadsData)}, borderColor: '#38bdf8', yAxisID: 'yThreads' },
|
|
947
|
+
{ label: 'Time-to-Failure Trend', data: ${JSON.stringify(ttfTrendData)}, borderColor: '#f43f5e', yAxisID: 'yTtf' }
|
|
988
948
|
]
|
|
989
949
|
},
|
|
990
|
-
options: {
|
|
991
|
-
|
|
992
|
-
maintainAspectRatio: false,
|
|
993
|
-
plugins: {
|
|
994
|
-
legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } }
|
|
995
|
-
},
|
|
996
|
-
scales: {
|
|
997
|
-
x: { grid: { color: '#1e293b' }, ticks: { color: '#64748b' } },
|
|
998
|
-
y_threads: { position: 'left', grid: { color: '#1e293b' }, ticks: { color: '#38bdf8' }, title: { display: true, text: 'VUs / Threads', color: '#38bdf8' } },
|
|
999
|
-
y_ttf: { position: 'right', grid: { drawOnChartArea: false }, ticks: { color: '#f43f5e' }, title: { display: true, text: 'TTF Index / Latency ms', color: '#f43f5e' } }
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
});
|
|
950
|
+
options: { responsive: true, maintainAspectRatio: false }
|
|
951
|
+
}));
|
|
1003
952
|
|
|
1004
|
-
new Chart(document.getElementById('statusDonutChart'), {
|
|
953
|
+
activeCharts.push(new Chart(document.getElementById('statusDonutChart'), {
|
|
1005
954
|
type: 'doughnut',
|
|
1006
955
|
data: {
|
|
1007
|
-
labels: ['
|
|
1008
|
-
datasets: [{
|
|
1009
|
-
data: [${responseMatrix.total1xx}, ${responseMatrix.total2xx}, ${responseMatrix.total3xx}, ${responseMatrix.total4xx}, ${responseMatrix.total5xx}],
|
|
1010
|
-
backgroundColor: ['#38bdf8', '#4ade80', '#cbd5e1', '#fde047', '#f87171'],
|
|
1011
|
-
borderWidth: 1,
|
|
1012
|
-
borderColor: '#1e293b'
|
|
1013
|
-
}]
|
|
956
|
+
labels: ['Success', 'Client Err', 'Server Err'],
|
|
957
|
+
datasets: [{ data: [${responseMatrix.total2xx}, ${responseMatrix.total4xx}, ${responseMatrix.total5xx}], backgroundColor: ['#4ade80', '#fde047', '#f87171'] }]
|
|
1014
958
|
},
|
|
1015
|
-
options: {
|
|
1016
|
-
|
|
1017
|
-
maintainAspectRatio: false,
|
|
1018
|
-
plugins: {
|
|
1019
|
-
legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } },
|
|
1020
|
-
cutout: '65%'
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
});
|
|
959
|
+
options: { responsive: true, maintainAspectRatio: false }
|
|
960
|
+
}));
|
|
1024
961
|
|
|
1025
|
-
new Chart(document.getElementById('ttfbScatterChart'), {
|
|
962
|
+
activeCharts.push(new Chart(document.getElementById('ttfbScatterChart'), {
|
|
1026
963
|
type: 'scatter',
|
|
1027
|
-
data: {
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
}]
|
|
1035
|
-
},
|
|
1036
|
-
options: {
|
|
1037
|
-
responsive: true,
|
|
1038
|
-
maintainAspectRatio: false,
|
|
1039
|
-
plugins: {
|
|
1040
|
-
legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } }
|
|
1041
|
-
},
|
|
1042
|
-
scales: {
|
|
1043
|
-
x: { grid: { color: '#1e293b' }, ticks: { color: '#64748b' }, title: { display: true, text: 'Time offset (s)', color: '#64748b' } },
|
|
1044
|
-
y: { grid: { color: '#1e293b' }, ticks: { color: '#64748b' }, title: { display: true, text: 'TTFB / Delay (ms)', color: '#64748b' } }
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
});
|
|
964
|
+
data: { datasets: [{ label: 'Processing Delay', data: ${JSON.stringify(scatterPoints)}, backgroundColor: '#a855f7' }] },
|
|
965
|
+
options: { responsive: true, maintainAspectRatio: false }
|
|
966
|
+
}));
|
|
967
|
+
|
|
968
|
+
// Bootstrapped configuration state defaults dashboard load view to Developer
|
|
969
|
+
document.querySelectorAll('.p-devops, .p-exec').forEach(el => el.style.display = 'none');
|
|
970
|
+
document.querySelectorAll('.p-dev').forEach(el => el.style.display = '');
|
|
1048
971
|
</script></body></html>`;
|
|
1049
972
|
try {
|
|
1050
973
|
fs.writeFileSync(config.outputHtml, htmlContent, "utf-8");
|
|
Binary file
|