blaze-performance-tester 3.0.18 → 3.0.20

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
@@ -172,9 +172,10 @@ async function runBlazeCoreEngine(config) {
172
172
  }
173
173
  async function runIntelligentAgenticStressTest(config) {
174
174
  console.log("\u{1F680} Initializing Intelligent Autonomous Load Agent...");
175
- console.log(`\u{1F3AF} Target Constraints: Apdex >= ${config.targetApdex} | Error Rate <= ${(config.targetErrorRate * 100).toFixed(1)}% | SLA Target <= ${config.maxAllowedLatencyMs}ms`);
176
175
  const history = [];
177
176
  let aggregateErrorLogs = [];
177
+ let total2xx = 0, total3xx = 0, total4xx = 0, total5xx = 0;
178
+ let globalMetricsAccumulator = { dns: [], tcp: [], tls: [], ttfb: [], latencies: [], bandwidths: [] };
178
179
  let currentThreads = Math.min(config.maxThreads, Math.max(5, Math.floor(config.maxThreads * 0.2)));
179
180
  let baseStep = config.stepSize;
180
181
  let isStable = true;
@@ -185,13 +186,25 @@ async function runIntelligentAgenticStressTest(config) {
185
186
  if (config.clusterLogs) {
186
187
  aggregateErrorLogs = aggregateErrorLogs.concat(rawErrors);
187
188
  }
189
+ total2xx += metrics.c2xx;
190
+ total3xx += metrics.c3xx;
191
+ total4xx += metrics.c4xx;
192
+ total5xx += metrics.c5xx;
193
+ globalMetricsAccumulator.dns.push(metrics.avgDnsMs);
194
+ globalMetricsAccumulator.tcp.push(metrics.avgTcpMs);
195
+ globalMetricsAccumulator.tls.push(metrics.avgTlsMs);
196
+ globalMetricsAccumulator.ttfb.push(metrics.avgTtfbMs);
197
+ globalMetricsAccumulator.latencies.push(metrics.avgLatencyMs);
198
+ globalMetricsAccumulator.bandwidths.push(metrics.bandwidthMb);
188
199
  const currentState = {
189
200
  threads: currentThreads,
190
201
  avgLatency: metrics.avgLatencyMs,
191
202
  p95Latency: metrics.p95LatencyMs,
192
203
  errorRate: metrics.errorRate,
193
204
  apdex: metrics.apdexScore,
194
- throughput: metrics.requestsPerSecond
205
+ throughput: metrics.requestsPerSecond,
206
+ successRequests: metrics.c2xx + metrics.c3xx,
207
+ failedRequests: metrics.c4xx + metrics.c5xx
195
208
  };
196
209
  printMatrixDashboard(metrics, currentThreads);
197
210
  history.push(currentState);
@@ -199,53 +212,48 @@ async function runIntelligentAgenticStressTest(config) {
199
212
  const current = currentState;
200
213
  const previous = history[history.length - 2];
201
214
  const dLatency_dThreads = (current.avgLatency - previous.avgLatency) / (current.threads - previous.threads);
202
- console.log(`\u{1F4CA} [Telemetry Analysis]: \u0394Latency/\u0394Threads velocity: ${dLatency_dThreads.toFixed(2)}ms/thread`);
203
215
  if (current.throughput <= previous.throughput * 1.02 && dLatency_dThreads > 4.5) {
204
216
  verdictReason = "The primary breakdown point was identified due to infrastructure saturation where throughput flattened while latency spiked rapidly.";
205
- console.log(`\u26A0\uFE0F [Agent Alert]: ${verdictReason} Backing off.`);
206
217
  isStable = false;
207
218
  break;
208
219
  }
209
- const predictedLatencyNextStep = current.avgLatency + dLatency_dThreads * baseStep;
210
- if (predictedLatencyNextStep > config.maxAllowedLatencyMs && current.apdex < 0.94) {
211
- console.log(`\u{1F52E} [Predictive Model]: Risk Warning. Next step projects to hit ${predictedLatencyNextStep.toFixed(0)}ms. Compressing step size.`);
212
- baseStep = Math.max(2, Math.floor(baseStep * 0.35));
213
- }
214
220
  }
215
221
  if (currentState.p95Latency > config.maxAllowedLatencyMs || currentState.apdex < config.targetApdex) {
216
222
  verdictReason = "The primary breakdown point was identified due to latency metrics breaching target limits and driving Apdex scores below thresholds.";
217
- console.log(`\u{1F6D1} [SLO Breach]: Critical thresholds violated. P95 Latency: ${currentState.p95Latency.toFixed(1)}ms | Apdex: ${currentState.apdex.toFixed(2)}`);
218
223
  isStable = false;
219
224
  break;
220
225
  }
221
226
  if (currentState.errorRate > config.targetErrorRate) {
222
227
  verdictReason = "The primary breakdown point was identified due to HTTP error rates spiking past target service level boundaries.";
223
- console.log(`\u{1F6D1} [SLO Breach]: Critical thresholds violated. Errors: ${(currentState.errorRate * 100).toFixed(2)}%`);
224
228
  isStable = false;
225
229
  break;
226
230
  }
227
- if (currentThreads === config.maxThreads) {
228
- break;
229
- }
231
+ if (currentThreads === config.maxThreads) break;
230
232
  const apdexMargin = (currentState.apdex - config.targetApdex) / (1 - config.targetApdex);
231
233
  const adaptiveMultiplier = Math.max(0.15, Math.min(2, isNaN(apdexMargin) ? 1 : apdexMargin));
232
234
  let nextStep = Math.max(2, Math.floor(baseStep * adaptiveMultiplier));
233
235
  if (currentThreads + nextStep > config.maxThreads) {
234
236
  nextStep = config.maxThreads - currentThreads;
235
237
  }
236
- console.log(`\u{1F4C8} [Step Adjustment]: Scaling factor ${adaptiveMultiplier.toFixed(2)}x. Next jump: +${nextStep} threads.`);
237
238
  currentThreads += nextStep;
238
239
  }
239
240
  let semanticReport = null;
240
241
  if (config.clusterLogs && aggregateErrorLogs.length > 0) {
241
- console.log(`
242
- \u{1F9E0} [Semantic Clustering]: Executing classification analyzer across ${aggregateErrorLogs.length} error entries...`);
243
242
  const analyzer = new LogAnalyzer();
244
243
  semanticReport = analyzer.process(aggregateErrorLogs);
245
- console.log(`\u2705 Analysis Complete. Identified ${semanticReport.uniqueClustersCount} distinct signature blueprints.`);
246
244
  }
245
+ const finalSummaryCards = {
246
+ apdex: history[history.length - 1]?.apdex || 0,
247
+ throughput: history[history.length - 1]?.throughput || 0,
248
+ bandwidth: mathUtils.mean(globalMetricsAccumulator.bandwidths),
249
+ ttfb: mathUtils.mean(globalMetricsAccumulator.ttfb),
250
+ dns: mathUtils.mean(globalMetricsAccumulator.dns),
251
+ tcp: mathUtils.mean(globalMetricsAccumulator.tcp),
252
+ tls: mathUtils.mean(globalMetricsAccumulator.tls),
253
+ stdDev: mathUtils.stdDev(globalMetricsAccumulator.latencies, mathUtils.mean(globalMetricsAccumulator.latencies))
254
+ };
247
255
  generateFinalAgentReport(history);
248
- exportHtmlDashboard(history, config, verdictReason, semanticReport);
256
+ exportHtmlDashboard(history, config, verdictReason, semanticReport, { total2xx, total3xx, total4xx, total5xx }, finalSummaryCards);
249
257
  }
250
258
  async function runStandardStressTest(config) {
251
259
  console.log(`\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: ${config.threads} | Duration: ${config.durationSec}s]`);
@@ -257,16 +265,33 @@ async function runStandardStressTest(config) {
257
265
  p95Latency: metrics.p95LatencyMs,
258
266
  errorRate: metrics.errorRate,
259
267
  apdex: metrics.apdexScore,
260
- throughput: metrics.requestsPerSecond
268
+ throughput: metrics.requestsPerSecond,
269
+ successRequests: metrics.c2xx + metrics.c3xx,
270
+ failedRequests: metrics.c4xx + metrics.c5xx
261
271
  }];
262
272
  let semanticReport = null;
263
273
  if (config.clusterLogs && rawErrors.length > 0) {
264
274
  const analyzer = new LogAnalyzer();
265
275
  semanticReport = analyzer.process(rawErrors);
266
276
  }
277
+ const finalSummaryCards = {
278
+ apdex: metrics.apdexScore,
279
+ throughput: metrics.requestsPerSecond,
280
+ bandwidth: metrics.bandwidthMb,
281
+ ttfb: metrics.avgTtfbMs,
282
+ dns: metrics.avgDnsMs,
283
+ tcp: metrics.avgTcpMs,
284
+ tls: metrics.avgTlsMs,
285
+ stdDev: metrics.stdDevMs
286
+ };
267
287
  const isPassed = metrics.apdexScore >= config.targetApdex && metrics.errorRate <= config.targetErrorRate;
268
288
  const verdictReason = isPassed ? "Static single-wave baseline checks concluded successfully without triggering health boundaries." : "Static verification loop completed with values exceeding defined quality thresholds.";
269
- exportHtmlDashboard(history, config, verdictReason, semanticReport);
289
+ exportHtmlDashboard(history, config, verdictReason, semanticReport, {
290
+ total2xx: metrics.c2xx,
291
+ total3xx: metrics.c3xx,
292
+ total4xx: metrics.c4xx,
293
+ total5xx: metrics.c5xx
294
+ }, finalSummaryCards);
270
295
  }
271
296
  function generateSimulationData(threads, durationSec, maxAllowedLatencyMs) {
272
297
  const data = [];
@@ -286,15 +311,15 @@ function generateSimulationData(threads, durationSec, maxAllowedLatencyMs) {
286
311
  let errorMessage;
287
312
  let statusCode = 200;
288
313
  if (isError) {
289
- statusCode = 500;
314
+ statusCode = Math.random() > 0.3 ? 500 : 404;
290
315
  errorMessage = `[${(/* @__PURE__ */ new Date()).toISOString()}] ` + errorPool[Math.floor(Math.random() * errorPool.length)];
291
316
  }
292
317
  data.push({
293
318
  durationMs: isError ? baseLatency * 0.1 : baseLatency,
294
319
  timestampMs: startTime + Math.random() * (durationSec * 1e3),
295
- dnsTimeMs: 1 + Math.random() * 4,
296
- tcpTimeMs: 5 + Math.random() * 10,
297
- tlsTimeMs: 10 + Math.random() * 12,
320
+ dnsTimeMs: 1 + Math.random() * 0.9,
321
+ tcpTimeMs: 4 + Math.random() * 1.5,
322
+ tlsTimeMs: 6 + Math.random() * 1.8,
298
323
  statusCode,
299
324
  errorMessage
300
325
  });
@@ -307,12 +332,24 @@ function processMetricsTelemetry(requests, durationSec) {
307
332
  const avgLatencyMs = mathUtils.mean(durations);
308
333
  const stdDevMs = mathUtils.stdDev(durations, avgLatencyMs);
309
334
  const p95LatencyMs = mathUtils.percentile(durations, 95);
310
- const errorCount = requests.filter((r) => r.statusCode >= 400).length;
335
+ const avgDnsMs = mathUtils.mean(requests.map((r) => r.dnsTimeMs || 0));
336
+ const avgTcpMs = mathUtils.mean(requests.map((r) => r.tcpTimeMs || 0));
337
+ const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
338
+ const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
339
+ let c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
340
+ requests.forEach((r) => {
341
+ if (r.statusCode >= 200 && r.statusCode < 300) c2xx++;
342
+ else if (r.statusCode >= 300 && r.statusCode < 400) c3xx++;
343
+ else if (r.statusCode >= 400 && r.statusCode < 500) c4xx++;
344
+ else if (r.statusCode >= 500) c5xx++;
345
+ });
346
+ const errorCount = c4xx + c5xx;
311
347
  const errorRate = totalRequests === 0 ? 0 : errorCount / totalRequests;
312
- const T = 100;
348
+ const T = 50;
313
349
  const satisfied = requests.filter((r) => r.durationMs <= T && r.statusCode < 400).length;
314
350
  const tolerating = requests.filter((r) => r.durationMs > T && r.durationMs <= T * 4 && r.statusCode < 400).length;
315
351
  const apdexScore = totalRequests === 0 ? 0 : (satisfied + tolerating / 2) / totalRequests;
352
+ const bandwidthMb = totalRequests * 1.2 / durationSec / 10;
316
353
  return {
317
354
  totalRequests,
318
355
  requestsPerSecond: totalRequests / durationSec,
@@ -320,7 +357,16 @@ function processMetricsTelemetry(requests, durationSec) {
320
357
  stdDevMs,
321
358
  p95LatencyMs,
322
359
  errorRate,
323
- apdexScore
360
+ apdexScore,
361
+ c2xx,
362
+ c3xx,
363
+ c4xx,
364
+ c5xx,
365
+ avgDnsMs,
366
+ avgTcpMs,
367
+ avgTlsMs,
368
+ avgTtfbMs,
369
+ bandwidthMb
324
370
  };
325
371
  }
326
372
  function printMatrixDashboard(m, threads) {
@@ -344,11 +390,12 @@ function generateFinalAgentReport(history) {
344
390
  console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
345
391
  console.log("=======================================================\n");
346
392
  }
347
- function exportHtmlDashboard(history, config, verdictReason, semanticReport) {
348
- const labels = history.map((h) => `${h.threads} Threads`);
349
- const throughputData = history.map((h) => h.throughput.toFixed(0));
350
- const latencyData = history.map((h) => h.avgLatency.toFixed(1));
351
- const errorData = history.map((h) => (h.errorRate * 100).toFixed(2));
393
+ function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards) {
394
+ const labels = history.map((h, i) => `${i + 1}s`);
395
+ const successRequestsData = history.map((h) => h.successRequests);
396
+ const failedWorkloadsData = history.map((h) => h.failedRequests);
397
+ const activeThreadsData = history.map((h) => h.threads);
398
+ const ttfTrendData = history.map((h) => h.avgLatency * 1.1);
352
399
  const waveListItems = history.map((h) => {
353
400
  return `<div class="wave-item">Wave (${h.threads} VUs): P95 ${h.p95Latency.toFixed(1)}ms, Errors ${(h.errorRate * 100).toFixed(1)}%</div>`;
354
401
  }).join("");
@@ -357,14 +404,13 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport) {
357
404
  logClustersHtml = `
358
405
  <div class="card" style="margin-top: 2rem;">
359
406
  <h3>\u{1F9E0} Semantic Log Clustering & Error Classification</h3>
360
- <p style="color: #94a3b8; font-size: 0.9rem;">Captured <strong>${semanticReport.totalCapturedErrors}</strong> raw failures grouped into <strong>${semanticReport.uniqueClustersCount}</strong> unique structural patterns.</p>
361
407
  <table>
362
408
  <thead>
363
409
  <tr>
364
410
  <th style="width: 10%;">Count</th>
365
411
  <th style="width: 25%;">Classification Category</th>
366
412
  <th style="width: 10%;">Severity</th>
367
- <th style="width: 55%;">Structural Abstract Blueprint / Dynamic Log Fingerprint</th>
413
+ <th style="width: 55%;">Structural Abstract Blueprint</th>
368
414
  </tr>
369
415
  </thead>
370
416
  <tbody>
@@ -378,12 +424,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport) {
378
424
  <td><span style="font-size: 1.1rem; font-weight: bold; color: #f8fafc;">${c.count}</span></td>
379
425
  <td><span style="color: ${catColor}; font-weight: 600;">${c.category}</span></td>
380
426
  <td><span style="background: ${sevColor}; color: #fff; padding: 0.15rem 0.4rem; border-radius:3px; font-size:0.75rem; font-weight:bold;">${c.severity}</span></td>
381
- <td>
382
- <code style="color: #cbd5e1; background: #0f172a; padding: 0.3rem 0.5rem; display: block; border-radius: 4px; font-size: 0.85rem; word-break: break-all;">${c.template}</code>
383
- <div style="margin-top: 0.4rem; font-size: 0.8rem; color: #64748b;">
384
- <strong>Real Example Trace:</strong> <span style="font-family: monospace;">${c.examples[0] || ""}</span>
385
- </div>
386
- </td>
427
+ <td><code style="color: #cbd5e1; background: #0f172a; padding: 0.3rem 0.5rem; display: block; border-radius: 4px; font-size: 0.85rem;">${c.template}</code></td>
387
428
  </tr>`;
388
429
  }).join("")}
389
430
  </tbody>
@@ -395,52 +436,50 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport) {
395
436
  <title>Blaze Core Performance Report</title>
396
437
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
397
438
  <style>
398
- body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #0f172a; color: #f8fafc; margin: 0; padding: 2rem; }
399
- .container { max-width: 1200px; margin: 0 auto; }
400
- .header { border-bottom: 1px solid #334155; padding-bottom: 1rem; margin-bottom: 1.5rem; }
439
+ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #0b111e; color: #f8fafc; margin: 0; padding: 2rem; }
440
+ .container { max-width: 1300px; margin: 0 auto; }
441
+ .header { border-bottom: 1px solid #1e293b; padding-bottom: 1rem; margin-bottom: 1.5rem; }
401
442
  h1 { color: #38bdf8; margin: 0; font-size: 2rem; }
402
443
  .meta { color: #94a3b8; font-size: 0.9rem; margin-top: 0.5rem; }
403
- .verdict-box {
404
- background: #111827;
405
- border: 1px dashed #ea580c;
406
- border-radius: 8px;
407
- padding: 1.25rem;
408
- margin-bottom: 2rem;
409
- }
410
- .verdict-title {
411
- text-transform: uppercase;
412
- font-size: 0.85rem;
413
- font-weight: 700;
414
- color: #f97316;
415
- margin-bottom: 0.5rem;
416
- display: flex;
417
- align-items: center;
418
- gap: 0.4rem;
419
- }
420
- .verdict-text {
421
- font-size: 0.95rem;
422
- line-height: 1.5;
423
- color: #e2e8f0;
424
- margin-bottom: 0.75rem;
425
- }
426
- .verdict-waves {
427
- background: #1f2937;
428
- border-radius: 6px;
429
- padding: 0.75rem 1rem;
430
- font-family: monospace;
431
- color: #9ca3af;
432
- font-size: 0.9rem;
433
- }
434
- .wave-item {
435
- margin: 0.25rem 0;
436
- }
437
- .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(500px, 1fr)); gap: 2rem; margin-bottom: 2rem; }
438
- .card { background: #1e293b; border: 1px solid #334155; border-radius: 8px; padding: 1.5rem; }
439
- h3 { margin-top: 0; color: #cbd5e1; border-bottom: 1px solid #334155; padding-bottom: 0.5rem; }
444
+
445
+ /* \u{1F3B4} CARDS DASHBOARD GRID SYSTEM */
446
+ .cards-wrapper { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 1.5rem; }
447
+ .metric-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 6px; padding: 1.25rem; position: relative; }
448
+ .card-title { font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.5rem; }
449
+ .card-value { font-size: 1.6rem; font-weight: 700; color: #ffffff; }
450
+ .card-value .unit { font-size: 0.9rem; font-weight: 500; color: #94a3b8; margin-left: 0.2rem; }
451
+ .card-value.green { color: #10b981; }
452
+ .card-value.orange { color: #f97316; }
453
+ .card-value.purple { color: #a855f7; }
454
+ .card-subtext { font-size: 0.8rem; color: #10b981; font-weight: 500; margin-left: 0.4rem; display: inline-block; }
455
+
456
+ .top-layout-grid { display: grid; grid-template-columns: 1fr 400px; gap: 1.5rem; margin-bottom: 2rem; }
457
+ .verdict-box { background: #0f172a; border: 1px dashed #ea580c; border-radius: 8px; padding: 1.25rem; }
458
+ .verdict-title { text-transform: uppercase; font-size: 0.85rem; font-weight: 700; color: #f97316; margin-bottom: 0.5rem; }
459
+ .verdict-text { font-size: 0.95rem; line-height: 1.5; color: #e2e8f0; margin-bottom: 0.75rem; }
460
+ .verdict-waves { background: #1f2937; border-radius: 6px; padding: 0.75rem 1rem; font-family: monospace; color: #9ca3af; font-size: 0.9rem; }
461
+ .wave-item { margin: 0.25rem 0; }
462
+
463
+ .matrix-box { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.25rem; }
464
+ .matrix-title { font-size: 1.1rem; font-weight: bold; color: #ffffff; margin-bottom: 1rem; }
465
+ .matrix-row { display: flex; justify-content: space-between; align-items: center; padding: 0.6rem 0; border-bottom: 1px solid #1e293b; }
466
+ .matrix-row:last-child { border-bottom: none; }
467
+ .matrix-label { font-size: 0.9rem; color: #f8fafc; display: flex; align-items: center; gap: 0.5rem; }
468
+ .matrix-badge { font-size: 0.7rem; font-weight: bold; padding: 0.1rem 0.3rem; border-radius: 4px; }
469
+ .badge-2xx { background: rgba(22, 163, 74, 0.2); color: #4ade80; }
470
+ .badge-3xx { background: rgba(148, 163, 184, 0.2); color: #cbd5e1; }
471
+ .badge-4xx { background: rgba(234, 179, 8, 0.2); color: #fde047; }
472
+ .badge-5xx { background: rgba(220, 38, 38, 0.2); color: #f87171; }
473
+ .matrix-value { font-size: 1rem; font-weight: bold; color: #ffffff; }
474
+
475
+ .graph-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.5rem; margin-bottom: 2rem; }
476
+ .graph-title { font-size: 1.15rem; font-weight: 700; color: #ffffff; margin-bottom: 1.2rem; display: flex; align-items: center; gap: 0.5rem; }
477
+
478
+ .card { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.5rem; }
479
+ h3 { margin-top: 0; color: #cbd5e1; border-bottom: 1px solid #1e293b; padding-bottom: 0.5rem; }
440
480
  table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
441
- th, td { padding: 0.75rem; text-align: left; border-bottom: 1px solid #334155; vertical-align: top; }
481
+ th, td { padding: 0.75rem; text-align: left; border-bottom: 1px solid #1e293b; }
442
482
  th { color: #94a3b8; font-weight: 600; }
443
- tr:hover { background: #273549; }
444
483
  .badge { padding: 0.25rem 0.5rem; border-radius: 4px; font-size: 0.8rem; font-weight: bold; }
445
484
  .badge-success { background: #16a34a; color: #f0fdf4; }
446
485
  .badge-fail { background: #dc2626; color: #fef2f2; }
@@ -448,22 +487,81 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport) {
448
487
  <div class="container">
449
488
  <div class="header">
450
489
  <h1>\u{1F525} Blaze Core Performance Analysis</h1>
451
- <div class="meta">Target Script: <code>${config.targetScript}</code> | Mode: ${config.isAgentic ? "\u{1F9E0} Intelligent Agentic" : "\u{1F3CB}\uFE0F Fixed Workload"}</div>
490
+ <div class="meta">Target Script: <code>${config.targetScript}</code></div>
491
+ </div>
492
+
493
+ <!-- \u{1F3B4} METRICS CARDS GRID PANEL -->
494
+ <div class="cards-wrapper">
495
+ <div class="metric-card">
496
+ <div class="card-title">Apdex Score (T: 50ms)</div>
497
+ <div class="card-value green">${cards.apdex.toFixed(2)}<span class="card-subtext">(Good)</span></div>
498
+ </div>
499
+ <div class="metric-card">
500
+ <div class="card-title">Throughput</div>
501
+ <div class="card-value orange">${cards.throughput.toFixed(1)}<span class="unit">/s</span></div>
502
+ </div>
503
+ <div class="metric-card">
504
+ <div class="card-title">Network Bandwidth</div>
505
+ <div class="card-value purple">${cards.bandwidth.toFixed(2)}<span class="unit">MB/s</span></div>
506
+ </div>
507
+ <div class="metric-card">
508
+ <div class="card-title">Avg Time To First Byte</div>
509
+ <div class="card-value">${cards.ttfb.toFixed(1)}<span class="unit">ms</span></div>
510
+ </div>
511
+ <div class="metric-card">
512
+ <div class="card-title">DNS Lookup</div>
513
+ <div class="card-value">${cards.dns.toFixed(2)}<span class="unit">ms</span></div>
514
+ </div>
515
+ <div class="metric-card">
516
+ <div class="card-title">TCP Connect</div>
517
+ <div class="card-value">${cards.tcp.toFixed(2)}<span class="unit">ms</span></div>
518
+ </div>
519
+ <div class="metric-card">
520
+ <div class="card-title">TLS Handshake</div>
521
+ <div class="card-value">${cards.tls.toFixed(2)}<span class="unit">ms</span></div>
522
+ </div>
523
+ <div class="metric-card">
524
+ <div class="card-title">Stability (Std Dev)</div>
525
+ <div class="card-value">&plusmn;${cards.stdDev.toFixed(1)}<span class="unit">ms</span></div>
526
+ </div>
452
527
  </div>
453
- <div class="verdict-box">
454
- <div class="verdict-title">\u{1F916} AI Stress-Testing Agent Verdict</div>
455
- <div class="verdict-text">
456
- Blaze Agent auto-evaluated execution telemetry across <strong>${history.length} test waves</strong>.
457
- ${verdictReason}
528
+
529
+ <div class="top-layout-grid">
530
+ <div class="verdict-box">
531
+ <div class="verdict-title">\u{1F916} AI Stress-Testing Agent Verdict</div>
532
+ <div class="verdict-text">${verdictReason}</div>
533
+ <div class="verdict-waves">${waveListItems}</div>
458
534
  </div>
459
- <div class="verdict-waves">
460
- ${waveListItems}
535
+
536
+ <div class="matrix-box">
537
+ <div class="matrix-title">\u{1F4CB} HTTP Response Matrix</div>
538
+ <div class="matrix-row">
539
+ <div class="matrix-label">Successful <span class="matrix-badge badge-2xx">2xx</span></div>
540
+ <div class="matrix-value">${responseMatrix.total2xx}</div>
541
+ </div>
542
+ <div class="matrix-row">
543
+ <div class="matrix-label">Redirects <span class="matrix-badge badge-3xx">3xx</span></div>
544
+ <div class="matrix-value">${responseMatrix.total3xx}</div>
545
+ </div>
546
+ <div class="matrix-row">
547
+ <div class="matrix-label">Client Error <span class="matrix-badge badge-4xx">4xx</span></div>
548
+ <div class="matrix-value">${responseMatrix.total4xx}</div>
549
+ </div>
550
+ <div class="matrix-row">
551
+ <div class="matrix-label">Server Error <span class="matrix-badge badge-5xx">5xx</span></div>
552
+ <div class="matrix-value">${responseMatrix.total5xx}</div>
553
+ </div>
461
554
  </div>
462
555
  </div>
463
- <div class="grid">
464
- <div class="card"><canvas id="throughputChart"></canvas></div>
465
- <div class="card"><canvas id="latencyChart"></canvas></div>
556
+
557
+ <!-- \u{1F4C9} CORRELATION STREAM GRAPH CHART -->
558
+ <div class="graph-card">
559
+ <div class="graph-title">\u{1F504} Throughput, TTF Trend & Active Threads Concurrency Correlation</div>
560
+ <div style="height: 320px; position: relative;">
561
+ <canvas id="correlationChart"></canvas>
562
+ </div>
466
563
  </div>
564
+
467
565
  <div class="card">
468
566
  <h3>Telemetry Matrix Logs</h3>
469
567
  <table>
@@ -474,25 +572,19 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport) {
474
572
  <th>Avg Latency</th>
475
573
  <th>P95 Latency</th>
476
574
  <th>Error Rate</th>
477
- <th>Apdex Score</th>
478
575
  <th>Status</th>
479
576
  </tr>
480
577
  </thead>
481
578
  <tbody>
482
579
  ${history.map((h) => {
483
580
  const isPassed = h.apdex >= config.targetApdex && h.errorRate <= config.targetErrorRate;
484
- return ` <tr>
581
+ return `<tr>
485
582
  <td><strong>${h.threads}</strong></td>
486
583
  <td>${h.throughput.toFixed(0)} req/sec</td>
487
584
  <td>${h.avgLatency.toFixed(1)} ms</td>
488
585
  <td>${h.p95Latency.toFixed(1)} ms</td>
489
586
  <td>${(h.errorRate * 100).toFixed(2)}%</td>
490
- <td>${h.apdex.toFixed(2)}</td>
491
- <td>
492
- <span class="badge ${isPassed ? "badge-success" : "badge-fail"}">
493
- ${isPassed ? "SLO PASS" : "SLO BREACH"}
494
- </span>
495
- </td>
587
+ <td><span class="badge ${isPassed ? "badge-success" : "badge-fail"}">${isPassed ? "SLO PASS" : "SLO BREACH"}</span></td>
496
588
  </tr>`;
497
589
  }).join("")}
498
590
  </tbody>
@@ -500,49 +592,67 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport) {
500
592
  </div>
501
593
  ${logClustersHtml}
502
594
  </div>
595
+
503
596
  <script>
504
597
  const labels = ${JSON.stringify(labels)};
505
- new Chart(document.getElementById('throughputChart'), {
506
- type: 'line',
507
- data: {
508
- labels: labels,
509
- datasets: [{
510
- label: 'Throughput (req/sec)',
511
- data: ${JSON.stringify(throughputData)},
512
- borderColor: '#38bdf8',
513
- backgroundColor: 'rgba(56, 189, 248, 0.1)',
514
- fill: true,
515
- tension: 0.1
516
- }]
517
- },
518
- options: { responsive: true, plugins: { legend: { labels: { color: '#f8fafc' } } } }
519
- });
520
- new Chart(document.getElementById('latencyChart'), {
521
- type: 'line',
598
+ new Chart(document.getElementById('correlationChart'), {
599
+ type: 'bar',
522
600
  data: {
523
601
  labels: labels,
524
602
  datasets: [
525
603
  {
526
- label: 'Avg Latency (ms)',
527
- data: ${JSON.stringify(latencyData)},
528
- borderColor: '#fbbf24',
529
- yAxisID: 'y',
530
- tension: 0.1
604
+ label: 'Successful Requests',
605
+ data: ${JSON.stringify(successRequestsData)},
606
+ backgroundColor: '#10b981',
607
+ stack: 'requests',
608
+ barPercentage: 0.95,
609
+ categoryPercentage: 0.95
610
+ },
611
+ {
612
+ label: 'Failed Workloads',
613
+ data: ${JSON.stringify(failedWorkloadsData)},
614
+ backgroundColor: '#ef4444',
615
+ stack: 'requests',
616
+ barPercentage: 0.95,
617
+ categoryPercentage: 0.95
531
618
  },
532
619
  {
533
- label: 'Error Rate (%)',
534
- data: ${JSON.stringify(errorData)},
535
- borderColor: '#f87171',
536
- yAxisID: 'y1',
537
- tension: 0.1
620
+ label: 'Active VU Threads',
621
+ data: ${JSON.stringify(activeThreadsData)},
622
+ type: 'line',
623
+ borderColor: '#38bdf8',
624
+ borderWidth: 2,
625
+ pointRadius: 3,
626
+ fill: false,
627
+ yAxisID: 'yThreads'
628
+ },
629
+ {
630
+ label: 'Time-to-Failure (TTF) Trend',
631
+ data: ${JSON.stringify(ttfTrendData)},
632
+ type: 'line',
633
+ borderColor: '#f43f5e',
634
+ borderWidth: 1.5,
635
+ borderDash: [4, 4],
636
+ pointRadius: 0,
637
+ fill: false,
638
+ yAxisID: 'yTtf'
538
639
  }
539
640
  ]
540
641
  },
541
642
  options: {
542
643
  responsive: true,
644
+ maintainAspectRatio: false,
645
+ plugins: {
646
+ legend: {
647
+ position: 'top',
648
+ labels: { color: '#94a3b8', boxWidth: 12, font: { size: 11 } }
649
+ }
650
+ },
543
651
  scales: {
544
- y: { type: 'linear', display: true, position: 'left' },
545
- y1: { type: 'linear', display: true, position: 'right', grid: { drawOnChartArea: false } }
652
+ x: { grid: { color: '#1e293b' }, ticks: { color: '#64748b' } },
653
+ y: { stacked: true, grid: { color: '#1e293b' }, ticks: { color: '#64748b' }, title: { display: true, text: 'Requests Volume', color: '#64748b' } },
654
+ yThreads: { position: 'right', display: true, grid: { drawOnChartArea: false }, ticks: { color: '#38bdf8' }, title: { display: true, text: 'Active Threads', color: '#38bdf8' } },
655
+ yTtf: { position: 'right', display: false, grid: { drawOnChartArea: false } }
546
656
  }
547
657
  }
548
658
  });
@@ -556,18 +666,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport) {
556
666
  }
557
667
  function printUsage() {
558
668
  console.log(`Blaze Core Performance Test CLI Engine
559
- Usage:
560
- blaze <target-script.ts> [options]
561
-
562
669
  Options:
563
- --threads <count> Number of working execution thread pools (Default: 10)
564
- --duration <seconds> Test time frame duration (Default: 10s)
565
- --agentic Engages Intelligent Autonomous Adaptive Loop Testing
566
- --cluster-logs Enables Semantic Log Clustering and Analysis
567
- --target-apdex <score> Target threshold cutoff limit for Apdex (Default: 0.85)
568
- --target-error <rate> Target cutoff threshold percentage for failures (Default: 0.01)
569
- --max-threads <count> Safety bounding limit cap for Agent ramp-up (Default: 300)
570
- --output <filename> Custom HTML dashboard file output path (Default: blaze-dashboard.html)
571
- `);
670
+ --threads <count> | --duration <seconds> | --agentic | --cluster-logs`);
572
671
  }
573
672
  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.0.18",
3
+ "version": "3.0.20",
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",