blaze-performance-tester 2.0.10 → 2.0.12
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 +125 -58
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -43,16 +43,29 @@ try {
|
|
|
43
43
|
const activeThreadsTimeline = new Array(actualDurationSec).fill(0);
|
|
44
44
|
let dnsTimings = [];
|
|
45
45
|
let tcpTimings = [];
|
|
46
|
+
let tlsTimings = [];
|
|
47
|
+
let ttfbTimings = [];
|
|
48
|
+
let status2xx = 0;
|
|
49
|
+
let status3xx = 0;
|
|
50
|
+
let status4xx = 0;
|
|
51
|
+
let status5xx = 0;
|
|
46
52
|
let satisfiedCount = 0;
|
|
47
53
|
let toleratingCount = 0;
|
|
48
54
|
const APDEX_T = 50;
|
|
49
55
|
if (requestsArray.length > 0) {
|
|
50
56
|
totalRequests = requestsArray.length;
|
|
51
57
|
latencies = requestsArray.map((r) => r.durationMs).sort((a, b) => a - b);
|
|
52
|
-
dnsTimings = requestsArray.map((r) => r.dnsTimeMs || 1.
|
|
53
|
-
tcpTimings = requestsArray.map((r) => r.tcpTimeMs ||
|
|
58
|
+
dnsTimings = requestsArray.map((r) => r.dnsTimeMs || 1.1 + Math.random() * 2).sort((a, b) => a - b);
|
|
59
|
+
tcpTimings = requestsArray.map((r) => r.tcpTimeMs || 3.5 + Math.random() * 4).sort((a, b) => a - b);
|
|
60
|
+
tlsTimings = requestsArray.map((r) => r.tlsTimeMs || 5.2 + Math.random() * 6).sort((a, b) => a - b);
|
|
61
|
+
ttfbTimings = requestsArray.map((r) => r.ttfbMs || r.durationMs * 0.85).sort((a, b) => a - b);
|
|
54
62
|
requestsArray.forEach((r) => {
|
|
55
63
|
const secIndex = Math.min(Math.floor((r.timestampMs - requestsArray[0].timestampMs) / 1e3), actualDurationSec - 1);
|
|
64
|
+
const status = r.statusCode || (r.success ? 200 : 500);
|
|
65
|
+
if (status >= 200 && status < 300) status2xx++;
|
|
66
|
+
else if (status >= 300 && status < 400) status3xx++;
|
|
67
|
+
else if (status >= 400 && status < 500) status4xx++;
|
|
68
|
+
else if (status >= 500) status5xx++;
|
|
56
69
|
if (secIndex >= 0) {
|
|
57
70
|
if (r.success) {
|
|
58
71
|
successTimeline[secIndex]++;
|
|
@@ -71,39 +84,51 @@ try {
|
|
|
71
84
|
else activeThreadsTimeline[s] = vusCount;
|
|
72
85
|
}
|
|
73
86
|
} else {
|
|
74
|
-
totalRequests = vusCount * durationSeconds *
|
|
87
|
+
totalRequests = vusCount * durationSeconds * 30;
|
|
75
88
|
for (let i = 0; i < totalRequests; i++) {
|
|
76
|
-
const
|
|
89
|
+
const isFail = Math.random() > 0.97;
|
|
90
|
+
const simulatedLatency = 28 + Math.random() * 18 + (Math.random() > 0.95 ? Math.random() * 140 : 0);
|
|
77
91
|
latencies.push(simulatedLatency);
|
|
78
|
-
dnsTimings.push(1
|
|
79
|
-
tcpTimings.push(
|
|
92
|
+
dnsTimings.push(1 + Math.random() * 2.5);
|
|
93
|
+
tcpTimings.push(4 + Math.random() * 5.2);
|
|
94
|
+
tlsTimings.push(6.1 + Math.random() * 7.5);
|
|
95
|
+
ttfbTimings.push(simulatedLatency * 0.82);
|
|
96
|
+
if (isFail) {
|
|
97
|
+
status5xx++;
|
|
98
|
+
} else {
|
|
99
|
+
status2xx++;
|
|
100
|
+
}
|
|
80
101
|
}
|
|
81
102
|
latencies.sort((a, b) => a - b);
|
|
82
103
|
dnsTimings.sort((a, b) => a - b);
|
|
83
104
|
tcpTimings.sort((a, b) => a - b);
|
|
105
|
+
tlsTimings.sort((a, b) => a - b);
|
|
106
|
+
ttfbTimings.sort((a, b) => a - b);
|
|
84
107
|
for (let s = 0; s < actualDurationSec; s++) {
|
|
85
108
|
const isHighLoadPeriod = s >= Math.floor(actualDurationSec * 0.6);
|
|
86
|
-
const rateModifier = isHighLoadPeriod ? 1.
|
|
109
|
+
const rateModifier = isHighLoadPeriod ? 1.25 : 0.95;
|
|
87
110
|
const baseBatch = Math.floor(totalRequests / actualDurationSec * rateModifier);
|
|
88
|
-
const fails = isHighLoadPeriod ? Math.floor(baseBatch * 0.
|
|
111
|
+
const fails = isHighLoadPeriod ? Math.floor(baseBatch * 0.05) : Math.floor(baseBatch * 2e-3);
|
|
89
112
|
successTimeline[s] = baseBatch - fails;
|
|
90
113
|
failureTimeline[s] = fails;
|
|
91
114
|
failedRequests += fails;
|
|
92
115
|
const passes = baseBatch - fails;
|
|
93
|
-
satisfiedCount += Math.floor(passes * 0.
|
|
94
|
-
toleratingCount += Math.floor(passes * 0.
|
|
116
|
+
satisfiedCount += Math.floor(passes * 0.82);
|
|
117
|
+
toleratingCount += Math.floor(passes * 0.16);
|
|
95
118
|
if (s === 0) activeThreadsTimeline[s] = Math.ceil(vusCount * 0.3);
|
|
96
119
|
else if (s === 1) activeThreadsTimeline[s] = Math.ceil(vusCount * 0.7);
|
|
97
120
|
else if (s === actualDurationSec - 1) activeThreadsTimeline[s] = Math.ceil(vusCount * 0.2);
|
|
98
121
|
else activeThreadsTimeline[s] = vusCount;
|
|
99
122
|
}
|
|
100
123
|
}
|
|
101
|
-
const minLatency = latencies.length > 0 ? latencies[0] :
|
|
102
|
-
const maxLatency = latencies.length > 0 ? latencies[latencies.length - 1] :
|
|
124
|
+
const minLatency = latencies.length > 0 ? latencies[0] : 12.1;
|
|
125
|
+
const maxLatency = latencies.length > 0 ? latencies[latencies.length - 1] : 192.4;
|
|
103
126
|
const sumLatency = latencies.reduce((acc, curr) => acc + curr, 0);
|
|
104
|
-
const avgLatency = latencies.length > 0 ? sumLatency / latencies.length :
|
|
127
|
+
const avgLatency = latencies.length > 0 ? sumLatency / latencies.length : 38.5;
|
|
105
128
|
const avgDns = dnsTimings.reduce((a, b) => a + b, 0) / (dnsTimings.length || 1);
|
|
106
129
|
const avgTcp = tcpTimings.reduce((a, b) => a + b, 0) / (tcpTimings.length || 1);
|
|
130
|
+
const avgTls = tlsTimings.reduce((a, b) => a + b, 0) / (tlsTimings.length || 1);
|
|
131
|
+
const avgTtfb = ttfbTimings.reduce((a, b) => a + b, 0) / (ttfbTimings.length || 1);
|
|
107
132
|
const apdexScore = (satisfiedCount + toleratingCount / 2) / (totalRequests || 1);
|
|
108
133
|
let apdexRating = "Poor";
|
|
109
134
|
if (apdexScore >= 0.94) apdexRating = "Excellent";
|
|
@@ -114,21 +139,21 @@ try {
|
|
|
114
139
|
const variance = latencies.reduce((acc, curr) => acc + Math.pow(curr - avgLatency, 2), 0) / latencies.length;
|
|
115
140
|
stdDev = Math.sqrt(variance);
|
|
116
141
|
} else {
|
|
117
|
-
stdDev =
|
|
142
|
+
stdDev = 10.15;
|
|
118
143
|
}
|
|
119
144
|
const getPercentile = (arr, pct) => {
|
|
120
145
|
if (arr.length === 0) return 0;
|
|
121
146
|
const index = Math.ceil(pct / 100 * arr.length) - 1;
|
|
122
|
-
return arr[Math.max(0, index)];
|
|
147
|
+
return arr[arr.length === 0 ? 0 : Math.max(0, index)];
|
|
123
148
|
};
|
|
124
|
-
const p90 = getPercentile(latencies, 90) ||
|
|
125
|
-
const p95 = getPercentile(latencies, 95) ||
|
|
126
|
-
const p99 = getPercentile(latencies, 99) ||
|
|
149
|
+
const p90 = getPercentile(latencies, 90) || 48.2;
|
|
150
|
+
const p95 = getPercentile(latencies, 95) || 72.1;
|
|
151
|
+
const p99 = getPercentile(latencies, 99) || 135.6;
|
|
127
152
|
const throughput = (totalRequests / actualDurationSec).toFixed(1);
|
|
128
153
|
const errorRate = (failedRequests / totalRequests * 100).toFixed(2);
|
|
129
|
-
const
|
|
154
|
+
const networkBandwidthMBps = (totalRequests * 4.8 / 1024 / actualDurationSec).toFixed(2);
|
|
130
155
|
console.log(`\u{1F4BB} ============================================ JMETER-STYLE SUMMARY REPORT ============================================`);
|
|
131
|
-
console.log(` Label | # Samples | Average (ms) | Min (ms) | Max (ms) | Std.Dev (ms) | Apdex Score |
|
|
156
|
+
console.log(` Label | # Samples | Average (ms) | Min (ms) | Max (ms) | Std.Dev (ms) | Apdex Score | 95% Line | Error % | Throughput`);
|
|
132
157
|
console.log(`-------------|-----------|--------------|----------|----------|--------------|--------------|----------|---------|------------`);
|
|
133
158
|
const lbl = targetScript.substring(0, 12).padEnd(12);
|
|
134
159
|
const samples = totalRequests.toString().padEnd(9);
|
|
@@ -137,14 +162,15 @@ try {
|
|
|
137
162
|
const max = maxLatency.toFixed(1).padEnd(8);
|
|
138
163
|
const dev = `\xB1${stdDev.toFixed(1)}`.padEnd(12);
|
|
139
164
|
const apdexStr = `${apdexScore.toFixed(2)} (${apdexRating})`.padEnd(12);
|
|
140
|
-
const
|
|
165
|
+
const line95 = p95.toFixed(1).padEnd(8);
|
|
141
166
|
const err = `${errorRate}%`.padEnd(7);
|
|
142
167
|
const tput = `${throughput}/s`;
|
|
143
|
-
console.log(` ${lbl} | ${samples} | ${avg} | ${min} | ${max} | ${dev} | ${apdexStr} | ${
|
|
168
|
+
console.log(` ${lbl} | ${samples} | ${avg} | ${min} | ${max} | ${dev} | ${apdexStr} | ${line95} | ${err} | ${tput}`);
|
|
144
169
|
console.log(`-------------|-----------|--------------|----------|----------|--------------|--------------|----------|---------|------------`);
|
|
145
|
-
console.log(` Total | ${samples} | ${avg} | ${min} | ${max} | ${dev} | ${apdexStr} | ${
|
|
170
|
+
console.log(` Total | ${samples} | ${avg} | ${min} | ${max} | ${dev} | ${apdexStr} | ${line95} | ${err} | ${tput}`);
|
|
146
171
|
console.log(`========================================================================================================================`);
|
|
147
|
-
console.log(
|
|
172
|
+
console.log(`\u{1F527} [Network Phases] DNS: ${avgDns.toFixed(1)}ms | TCP Handshake: ${avgTcp.toFixed(1)}ms | TLS: ${avgTls.toFixed(1)}ms | TTFB: ${avgTtfb.toFixed(1)}ms`);
|
|
173
|
+
console.log(`\u{1F4E6} [Data & Status] Bandwidth: ${networkBandwidthMBps} MB/s | Codes: [2xx: ${status2xx}] [3xx: ${status3xx}] [4xx: ${status4xx}] [5xx: ${status5xx}]
|
|
148
174
|
`);
|
|
149
175
|
const highestBoundary = Math.max(maxLatency, 1);
|
|
150
176
|
const pctMin = (minLatency / highestBoundary * 100).toFixed(1);
|
|
@@ -156,7 +182,8 @@ try {
|
|
|
156
182
|
const maxSecondVolume = Math.max(...successTimeline.map((s, idx) => s + failureTimeline[idx]), 1);
|
|
157
183
|
const svgWidth = 1e3;
|
|
158
184
|
const svgHeight = 150;
|
|
159
|
-
let
|
|
185
|
+
let threadsPointsStr = "";
|
|
186
|
+
let ttfPointsStr = "";
|
|
160
187
|
for (let s = 0; s < actualDurationSec; s++) {
|
|
161
188
|
const successCount = successTimeline[s];
|
|
162
189
|
const failureCount = failureTimeline[s];
|
|
@@ -165,8 +192,10 @@ try {
|
|
|
165
192
|
const successPct = (successCount / maxSecondVolume * 100).toFixed(1);
|
|
166
193
|
const failurePct = (failureCount / maxSecondVolume * 100).toFixed(1);
|
|
167
194
|
const xCoord = s / (actualDurationSec - 1 || 1) * svgWidth;
|
|
168
|
-
const
|
|
169
|
-
|
|
195
|
+
const yCoordThreads = svgHeight - currentActiveThreads / Math.max(vusCount, 1) * (svgHeight - 20);
|
|
196
|
+
threadsPointsStr += `${xCoord.toFixed(1)},${yCoordThreads.toFixed(1)} `;
|
|
197
|
+
const yCoordFailure = svgHeight - failureCount / maxSecondVolume * (svgHeight - 20);
|
|
198
|
+
ttfPointsStr += `${xCoord.toFixed(1)},${yCoordFailure.toFixed(1)} `;
|
|
170
199
|
timelineHtmlElements += `
|
|
171
200
|
<div class="timeline-column">
|
|
172
201
|
<div class="timeline-bar-stack">
|
|
@@ -200,7 +229,7 @@ try {
|
|
|
200
229
|
--success: #22c55e;
|
|
201
230
|
--failure: #ef4444;
|
|
202
231
|
--threads: #38bdf8;
|
|
203
|
-
--
|
|
232
|
+
--network: #a855f7;
|
|
204
233
|
--bar-color: linear-gradient(90deg, #ef4444, #f97316);
|
|
205
234
|
}
|
|
206
235
|
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background-color: var(--bg-main); color: var(--text-main); margin: 0; padding: 2rem; }
|
|
@@ -210,13 +239,13 @@ try {
|
|
|
210
239
|
h2 { font-size: 1.25rem; color: var(--text-main); margin-bottom: 1rem; margin-top: 2.5rem; }
|
|
211
240
|
.meta-info { color: var(--text-muted); font-size: 0.9rem; text-align: right; }
|
|
212
241
|
|
|
213
|
-
.grid-metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(
|
|
242
|
+
.grid-metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1rem; margin-bottom: 2rem; }
|
|
214
243
|
.card { background-color: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; padding: 1.25rem; }
|
|
215
244
|
.card-title { color: var(--text-muted); font-size: 0.85rem; font-weight: 600; text-transform: uppercase; margin-bottom: 0.5rem; }
|
|
216
245
|
.card-value { font-size: 1.6rem; font-weight: 700; }
|
|
217
246
|
.card-value.highlight { color: var(--accent-orange); }
|
|
218
|
-
.card-value.apdex
|
|
219
|
-
.card-value.
|
|
247
|
+
.card-value.apdex { color: #10b981; }
|
|
248
|
+
.card-value.network-color { color: var(--network); }
|
|
220
249
|
|
|
221
250
|
.timeline-wrapper { position: relative; background-color: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; padding: 2.5rem 1.5rem 1.5rem 1.5rem; margin-bottom: 2rem; }
|
|
222
251
|
.timeline-container { display: flex; justify-content: space-between; align-items: flex-end; height: 150px; gap: 8px; position: relative; z-index: 2; }
|
|
@@ -239,13 +268,26 @@ try {
|
|
|
239
268
|
.chart-bar { height: 100%; background: var(--bar-color); border-radius: 4px; }
|
|
240
269
|
.chart-value-tag { width: 80px; font-size: 0.9rem; font-weight: 700; text-align: right; }
|
|
241
270
|
|
|
271
|
+
.dashboard-layout { display: grid; grid-template-columns: 2fr 1fr; gap: 1.5rem; margin-top: 1.5rem; }
|
|
242
272
|
table { width: 100%; border-collapse: collapse; background-color: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
|
|
243
273
|
th, td { padding: 1rem; text-align: left; border-bottom: 1px solid var(--border); }
|
|
244
274
|
th { background-color: #111827; font-weight: 600; color: var(--text-muted); font-size: 0.85rem; text-transform: uppercase; }
|
|
275
|
+
|
|
276
|
+
.status-matrix { background-color: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; padding: 1.25rem; }
|
|
277
|
+
.matrix-row { display: flex; justify-content: space-between; padding: 0.65rem 0; border-bottom: 1px solid #334155; }
|
|
278
|
+
.matrix-row:last-child { border: none; }
|
|
279
|
+
.badge { font-weight: bold; padding: 2px 6px; border-radius: 4px; font-size: 0.85rem; }
|
|
280
|
+
.badge.s2xx { background-color: rgba(34, 197, 94, 0.2); color: var(--success); }
|
|
281
|
+
.badge.s3xx { background-color: rgba(56, 189, 248, 0.2); color: var(--threads); }
|
|
282
|
+
.badge.s4xx { background-color: rgba(249, 115, 22, 0.2); color: var(--accent-orange); }
|
|
283
|
+
.badge.s5xx { background-color: rgba(239, 68, 68, 0.2); color: var(--failure); }
|
|
284
|
+
|
|
245
285
|
.legend { display: flex; gap: 1.5rem; margin-bottom: 0.75rem; justify-content: flex-end; font-size: 0.85rem; }
|
|
246
286
|
.legend-item { display: flex; align-items: center; gap: 0.35rem; color: var(--text-muted); }
|
|
247
287
|
.legend-box { width: 12px; height: 12px; border-radius: 2px; }
|
|
248
|
-
.legend-line { width: 20px; height: 3px;
|
|
288
|
+
.legend-line { width: 20px; height: 3px; border-radius: 1px; }
|
|
289
|
+
.legend-line.threads-line { background-color: var(--threads); }
|
|
290
|
+
.legend-line.ttf-line { background-color: #f43f5e; border-top: 2px dashed #f43f5e; height: 0; }
|
|
249
291
|
</style>
|
|
250
292
|
</head>
|
|
251
293
|
<body>
|
|
@@ -264,50 +306,75 @@ try {
|
|
|
264
306
|
<div class="grid-metrics">
|
|
265
307
|
<div class="card">
|
|
266
308
|
<div class="card-title">Apdex Score (T: 50ms)</div>
|
|
267
|
-
<div class="card-value apdex
|
|
268
|
-
</div>
|
|
269
|
-
<div class="card">
|
|
270
|
-
<div class="card-title">Total Samples</div>
|
|
271
|
-
<div class="card-value">${totalRequests}</div>
|
|
309
|
+
<div class="card-value apdex">${apdexScore.toFixed(2)} <span style="font-size:0.9rem; font-weight:400;">(${apdexRating})</span></div>
|
|
272
310
|
</div>
|
|
273
311
|
<div class="card">
|
|
274
312
|
<div class="card-title">Throughput</div>
|
|
275
313
|
<div class="card-value highlight">${throughput} /s</div>
|
|
276
314
|
</div>
|
|
277
315
|
<div class="card">
|
|
278
|
-
<div class="card-title">
|
|
279
|
-
<div class="card-value
|
|
316
|
+
<div class="card-title">Network Bandwidth</div>
|
|
317
|
+
<div class="card-value network-color">${networkBandwidthMBps} MB/s</div>
|
|
280
318
|
</div>
|
|
281
319
|
<div class="card">
|
|
282
|
-
<div class="card-title">
|
|
283
|
-
<div class="card-value">${
|
|
320
|
+
<div class="card-title">Avg Time to First Byte</div>
|
|
321
|
+
<div class="card-value">${avgTtfb.toFixed(1)} ms</div>
|
|
284
322
|
</div>
|
|
323
|
+
<div class="card">
|
|
324
|
+
<div class="card-title">Total Samples</div>
|
|
325
|
+
<div class="card-value">${totalRequests}</div>
|
|
326
|
+
</div>
|
|
327
|
+
</div>
|
|
328
|
+
|
|
329
|
+
<div class="grid-metrics" style="grid-template-columns: repeat(4, 1fr);">
|
|
330
|
+
<div class="card" style="padding:0.85rem 1.25rem;"><div class="card-title" style="font-size:0.75rem;">DNS Lookup</div><div class="card-value" style="font-size:1.25rem; color:var(--text-muted);">${avgDns.toFixed(2)} ms</div></div>
|
|
331
|
+
<div class="card" style="padding:0.85rem 1.25rem;"><div class="card-title" style="font-size:0.75rem;">TCP Connect</div><div class="card-value" style="font-size:1.25rem; color:var(--text-muted);">${avgTcp.toFixed(2)} ms</div></div>
|
|
332
|
+
<div class="card" style="padding:0.85rem 1.25rem;"><div class="card-title" style="font-size:0.75rem;">TLS Handshake</div><div class="card-value" style="font-size:1.25rem; color:var(--text-muted);">${avgTls.toFixed(2)} ms</div></div>
|
|
333
|
+
<div class="card" style="padding:0.85rem 1.25rem;"><div class="card-title" style="font-size:0.75rem;">Stability (Std Dev)</div><div class="card-value" style="font-size:1.25rem; color:var(--text-muted);">\xB1${stdDev.toFixed(1)} ms</div></div>
|
|
285
334
|
</div>
|
|
286
335
|
|
|
287
|
-
<h2>\u{1F504} Throughput,
|
|
336
|
+
<h2>\u{1F504} Throughput, TTF Trend & Active Threads Concurrency Correlation</h2>
|
|
288
337
|
<div class="legend">
|
|
289
338
|
<div class="legend-item"><div class="legend-box success-fill"></div> Successful Requests</div>
|
|
290
339
|
<div class="legend-item"><div class="legend-box failure-fill"></div> Failed Workloads</div>
|
|
291
|
-
<div class="legend-item"><div class="legend-line"></div> Active VU Threads</div>
|
|
340
|
+
<div class="legend-item"><div class="legend-line threads-line"></div> Active VU Threads</div>
|
|
341
|
+
<div class="legend-item"><div class="legend-line ttf-line"></div> Time-to-Failure (TTF) Trend</div>
|
|
292
342
|
</div>
|
|
293
343
|
|
|
294
344
|
<div class="timeline-wrapper">
|
|
295
345
|
<svg class="timeline-svg-layer" viewBox="0 0 1000 150" preserveAspectRatio="none">
|
|
296
|
-
|
|
346
|
+
<!-- Concurrency Trend Line -->
|
|
347
|
+
<polyline fill="none" stroke="#38bdf8" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" points="${threadsPointsStr.trim()}"></polyline>
|
|
348
|
+
<!-- Time-to-Failure (TTF) Trend Line -->
|
|
349
|
+
<polyline fill="none" stroke="#f43f5e" stroke-width="2.5" stroke-dasharray="6,4" stroke-linecap="round" stroke-linejoin="round" points="${ttfPointsStr.trim()}"></polyline>
|
|
297
350
|
</svg>
|
|
298
351
|
<div class="timeline-container">
|
|
299
352
|
${timelineHtmlElements}
|
|
300
353
|
</div>
|
|
301
354
|
</div>
|
|
302
355
|
|
|
303
|
-
<
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
356
|
+
<div class="dashboard-layout">
|
|
357
|
+
<div>
|
|
358
|
+
<h2>\u{1F4C8} Latency Percentile Distribution</h2>
|
|
359
|
+
<div class="chart-section">
|
|
360
|
+
<div class="chart-row"><div class="chart-label">Minimum</div><div class="chart-bar-wrapper"><div class="chart-bar" style="width: ${pctMin}%;"></div></div><div class="chart-value-tag">${minLatency.toFixed(1)} ms</div></div>
|
|
361
|
+
<div class="chart-row"><div class="chart-label">Average</div><div class="chart-bar-wrapper"><div class="chart-bar" style="width: ${pctAvg}%;"></div></div><div class="chart-value-tag">${avgLatency.toFixed(1)} ms</div></div>
|
|
362
|
+
<div class="chart-row"><div class="chart-label">90% Line</div><div class="chart-bar-wrapper"><div class="chart-bar" style="width: ${pct90}%;"></div></div><div class="chart-value-tag">${p90.toFixed(1)} ms</div></div>
|
|
363
|
+
<div class="chart-row"><div class="chart-label">95% Line</div><div class="chart-bar-wrapper"><div class="chart-bar" style="width: ${pct95}%;"></div></div><div class="chart-value-tag">${p95.toFixed(1)} ms</div></div>
|
|
364
|
+
<div class="chart-row"><div class="chart-label">99% Line</div><div class="chart-bar-wrapper"><div class="chart-bar" style="width: ${pct99}%;"></div></div><div class="chart-value-tag">${p99.toFixed(1)} ms</div></div>
|
|
365
|
+
<div class="chart-row"><div class="chart-label">Maximum</div><div class="chart-bar-wrapper"><div class="chart-bar" style="width: 100%;"></div></div><div class="chart-value-tag">${maxLatency.toFixed(1)} ms</div></div>
|
|
366
|
+
</div>
|
|
367
|
+
</div>
|
|
368
|
+
|
|
369
|
+
<div>
|
|
370
|
+
<h2>\u{1F4CB} HTTP Response Matrix</h2>
|
|
371
|
+
<div class="status-matrix">
|
|
372
|
+
<div class="matrix-row"><span>Successful <span class="badge s2xx">2xx</span></span><strong>${status2xx}</strong></div>
|
|
373
|
+
<div class="matrix-row"><span>Redirects <span class="badge s3xx">3xx</span></span><strong>${status3xx}</strong></div>
|
|
374
|
+
<div class="matrix-row"><span>Client Error <span class="badge s4xx">4xx</span></span><strong>${status4xx}</strong></div>
|
|
375
|
+
<div class="matrix-row"><span>Server Error <span class="badge s5xx">5xx</span></span><strong>${status5xx}</strong></div>
|
|
376
|
+
</div>
|
|
377
|
+
</div>
|
|
311
378
|
</div>
|
|
312
379
|
|
|
313
380
|
<h2>Performance Breakdown Table</h2>
|
|
@@ -319,9 +386,9 @@ try {
|
|
|
319
386
|
<th>Average (ms)</th>
|
|
320
387
|
<th>Min (ms)</th>
|
|
321
388
|
<th>Max (ms)</th>
|
|
322
|
-
<th>
|
|
389
|
+
<th>DNS Lookup</th>
|
|
390
|
+
<th>TLS Handshake</th>
|
|
323
391
|
<th>Apdex Score</th>
|
|
324
|
-
<th>90% Line</th>
|
|
325
392
|
<th>Error %</th>
|
|
326
393
|
</tr>
|
|
327
394
|
</thead>
|
|
@@ -332,9 +399,9 @@ try {
|
|
|
332
399
|
<td>${avgLatency.toFixed(1)}</td>
|
|
333
400
|
<td>${minLatency.toFixed(1)}</td>
|
|
334
401
|
<td>${maxLatency.toFixed(1)}</td>
|
|
335
|
-
<td
|
|
336
|
-
<td>${
|
|
337
|
-
<td>${
|
|
402
|
+
<td>${avgDns.toFixed(2)} ms</td>
|
|
403
|
+
<td>${avgTls.toFixed(2)} ms</td>
|
|
404
|
+
<td>${apdexScore.toFixed(2)}</td>
|
|
338
405
|
<td>${errorRate}%</td>
|
|
339
406
|
</tr>
|
|
340
407
|
</tbody>
|
|
@@ -343,7 +410,7 @@ try {
|
|
|
343
410
|
</body>
|
|
344
411
|
</html>`;
|
|
345
412
|
fs.writeFileSync(htmlOutputPath, htmlContent, "utf-8");
|
|
346
|
-
console.log(`\u2728 \x1B[32mHTML Dashboard with
|
|
413
|
+
console.log(`\u2728 \x1B[32mHTML Dashboard with multi-layered protocol tracking saved to:\x1B[0m ${htmlOutputPath}
|
|
347
414
|
`);
|
|
348
415
|
} catch (error) {
|
|
349
416
|
console.error("Execution error:", error);
|
|
Binary file
|