blaze-performance-tester 3.0.4 β†’ 3.0.18

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
@@ -5,6 +5,63 @@ import { createRequire } from "module";
5
5
  import * as path from "path";
6
6
  import { fileURLToPath } from "url";
7
7
  import * as fs from "fs";
8
+
9
+ // src/LogAnalyzer.ts
10
+ var LogAnalyzer = class {
11
+ /**
12
+ * Generates a structural semantic fingerprint by masking dynamic values
13
+ */
14
+ extractLogTemplate(rawLog) {
15
+ return rawLog.trim().replace(/\d{4}-\d{2}-\d{2}[T\s]\d{2}:\d{2}:\d{2}(\.\d{3})?Z?/, "<TIMESTAMP>").replace(/0x[a-fA-F0-9]+/g, "<HEX_ID>").replace(/\b\d+\b/g, "<NUM>").replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, "<UUID>");
16
+ }
17
+ /**
18
+ * Categorizes the structural log signature template based on runtime taxonomy rules
19
+ */
20
+ classifyTemplate(template) {
21
+ const LowercaseTpl = template.toLowerCase();
22
+ if (LowercaseTpl.includes("timeout") || LowercaseTpl.includes("econnrefused") || LowercaseTpl.includes("socket") || LowercaseTpl.includes("network") || LowercaseTpl.includes("hang up") || LowercaseTpl.includes("502") || LowercaseTpl.includes("504")) {
23
+ return { category: "Environment_Infrastructure_Error", severity: "CRITICAL" };
24
+ }
25
+ if (LowercaseTpl.includes("401") || LowercaseTpl.includes("403") || LowercaseTpl.includes("unauthorized") || LowercaseTpl.includes("forbidden") || LowercaseTpl.includes("jwt") || LowercaseTpl.includes("token expired")) {
26
+ return { category: "Authentication_Error", severity: "CRITICAL" };
27
+ }
28
+ return { category: "Product_Error", severity: "WARNING" };
29
+ }
30
+ /**
31
+ * Processes a stream of raw textual error logs into deduplicated clustered fingerprints
32
+ */
33
+ process(rawLogs) {
34
+ const clusterMap = {};
35
+ let totalCapturedErrors = 0;
36
+ for (const log of rawLogs) {
37
+ if (!log || log.trim() === "") continue;
38
+ totalCapturedErrors++;
39
+ const template = this.extractLogTemplate(log);
40
+ if (!clusterMap[template]) {
41
+ const rules = this.classifyTemplate(template);
42
+ clusterMap[template] = {
43
+ template,
44
+ count: 0,
45
+ category: rules.category,
46
+ severity: rules.severity,
47
+ examples: []
48
+ };
49
+ }
50
+ clusterMap[template].count++;
51
+ if (clusterMap[template].examples.length < 3 && !clusterMap[template].examples.includes(log)) {
52
+ clusterMap[template].examples.push(log);
53
+ }
54
+ }
55
+ const sortedClusters = Object.values(clusterMap).sort((a, b) => b.count - a.count);
56
+ return {
57
+ uniqueClustersCount: sortedClusters.length,
58
+ totalCapturedErrors,
59
+ clusters: sortedClusters
60
+ };
61
+ }
62
+ };
63
+
64
+ // cli.ts
8
65
  var __filename = fileURLToPath(import.meta.url);
9
66
  var __dirname = path.dirname(__filename);
10
67
  var require2 = createRequire(import.meta.url);
@@ -44,13 +101,15 @@ async function main() {
44
101
  }
45
102
  }
46
103
  function parseArguments(args) {
47
- const targetScript = path.resolve(args[0]);
104
+ const targetScript = path.resolve(args[0] || ".");
48
105
  const isAgentic = args.includes("--agentic");
106
+ const clusterLogs = args.includes("--cluster-logs");
49
107
  let threads = 10;
50
108
  let durationSec = 10;
51
109
  let targetApdex = 0.85;
52
110
  let targetErrorRate = 0.01;
53
111
  let maxThreads = 300;
112
+ let maxAllowedLatencyMs = 800;
54
113
  let outputHtml = "blaze-dashboard.html";
55
114
  const threadsIdx = args.indexOf("--threads");
56
115
  if (threadsIdx !== -1) threads = parseInt(args[threadsIdx + 1], 10);
@@ -64,16 +123,31 @@ function parseArguments(args) {
64
123
  if (maxThreadsIdx !== -1) maxThreads = parseInt(args[maxThreadsIdx + 1], 10);
65
124
  const outputIdx = args.indexOf("--output");
66
125
  if (outputIdx !== -1) outputHtml = args[outputIdx + 1];
126
+ if (isAgentic) {
127
+ const agenticIdx = args.indexOf("--agentic");
128
+ const trailingArgs = args.slice(agenticIdx + 1).filter((arg) => !arg.startsWith("--"));
129
+ if (trailingArgs[0]) maxThreads = parseInt(trailingArgs[0], 10);
130
+ if (trailingArgs[1]) {
131
+ let rawLatency = parseFloat(trailingArgs[1]);
132
+ if (rawLatency < 50) {
133
+ maxAllowedLatencyMs = rawLatency * 1e3;
134
+ } else {
135
+ maxAllowedLatencyMs = rawLatency;
136
+ }
137
+ }
138
+ if (trailingArgs[2]) targetErrorRate = parseFloat(trailingArgs[2]) / 100;
139
+ }
67
140
  return {
68
141
  targetScript,
69
142
  isAgentic,
143
+ clusterLogs,
70
144
  threads,
71
145
  durationSec,
72
146
  targetApdex,
73
147
  targetErrorRate,
74
148
  maxThreads,
75
149
  stepSize: 15,
76
- maxAllowedLatencyMs: 800,
150
+ maxAllowedLatencyMs,
77
151
  outputHtml
78
152
  };
79
153
  }
@@ -88,24 +162,29 @@ async function runBlazeCoreEngine(config) {
88
162
  } catch (err) {
89
163
  }
90
164
  if (!rawRequests || rawRequests.length === 0) {
91
- rawRequests = generateSimulationData(config.threads, config.durationSec);
165
+ rawRequests = generateSimulationData(config.threads, config.durationSec, config.maxAllowedLatencyMs);
92
166
  }
93
- resolve2(processMetricsTelemetry(rawRequests, config.durationSec));
167
+ const metrics = processMetricsTelemetry(rawRequests, config.durationSec);
168
+ const rawErrors = rawRequests.filter((r) => r.errorMessage).map((r) => r.errorMessage);
169
+ resolve2({ metrics, rawErrors });
94
170
  }, 1e3);
95
171
  });
96
172
  }
97
173
  async function runIntelligentAgenticStressTest(config) {
98
174
  console.log("\u{1F680} Initializing Intelligent Autonomous Load Agent...");
99
- console.log(`\u{1F3AF} Target Constraints: Apdex >= ${config.targetApdex} | Error Rate <= ${config.targetErrorRate * 100}%`);
175
+ console.log(`\u{1F3AF} Target Constraints: Apdex >= ${config.targetApdex} | Error Rate <= ${(config.targetErrorRate * 100).toFixed(1)}% | SLA Target <= ${config.maxAllowedLatencyMs}ms`);
100
176
  const history = [];
101
- let currentThreads = Math.max(5, Math.floor(config.threads * 0.5));
177
+ let aggregateErrorLogs = [];
178
+ let currentThreads = Math.min(config.maxThreads, Math.max(5, Math.floor(config.maxThreads * 0.2)));
102
179
  let baseStep = config.stepSize;
103
180
  let isStable = true;
104
181
  let verdictReason = "The system successfully scaled and remained stable within parameters up to maximum configured capacity allocations.";
105
182
  while (currentThreads <= config.maxThreads && isStable) {
106
- console.log(`
107
- \u{1F916} [Agent Decision]: Testing execution tier at ${currentThreads} concurrent threads...`);
108
- const metrics = await runBlazeCoreEngine({ ...config, threads: currentThreads });
183
+ console.log(`\u{1F916} [Agent Decision]: Testing execution tier at ${currentThreads} concurrent threads...`);
184
+ const { metrics, rawErrors } = await runBlazeCoreEngine({ ...config, threads: currentThreads });
185
+ if (config.clusterLogs) {
186
+ aggregateErrorLogs = aggregateErrorLogs.concat(rawErrors);
187
+ }
109
188
  const currentState = {
110
189
  threads: currentThreads,
111
190
  avgLatency: metrics.avgLatencyMs,
@@ -124,7 +203,6 @@ async function runIntelligentAgenticStressTest(config) {
124
203
  if (current.throughput <= previous.throughput * 1.02 && dLatency_dThreads > 4.5) {
125
204
  verdictReason = "The primary breakdown point was identified due to infrastructure saturation where throughput flattened while latency spiked rapidly.";
126
205
  console.log(`\u26A0\uFE0F [Agent Alert]: ${verdictReason} Backing off.`);
127
- currentThreads = Math.floor(currentThreads * 0.8);
128
206
  isStable = false;
129
207
  break;
130
208
  }
@@ -134,9 +212,9 @@ async function runIntelligentAgenticStressTest(config) {
134
212
  baseStep = Math.max(2, Math.floor(baseStep * 0.35));
135
213
  }
136
214
  }
137
- if (currentState.apdex < config.targetApdex) {
215
+ if (currentState.p95Latency > config.maxAllowedLatencyMs || currentState.apdex < config.targetApdex) {
138
216
  verdictReason = "The primary breakdown point was identified due to latency metrics breaching target limits and driving Apdex scores below thresholds.";
139
- console.log(`\u{1F6D1} [SLO Breach]: Critical thresholds violated. Apdex: ${currentState.apdex.toFixed(2)}`);
217
+ console.log(`\u{1F6D1} [SLO Breach]: Critical thresholds violated. P95 Latency: ${currentState.p95Latency.toFixed(1)}ms | Apdex: ${currentState.apdex.toFixed(2)}`);
140
218
  isStable = false;
141
219
  break;
142
220
  }
@@ -146,18 +224,32 @@ async function runIntelligentAgenticStressTest(config) {
146
224
  isStable = false;
147
225
  break;
148
226
  }
227
+ if (currentThreads === config.maxThreads) {
228
+ break;
229
+ }
149
230
  const apdexMargin = (currentState.apdex - config.targetApdex) / (1 - config.targetApdex);
150
- const adaptiveMultiplier = Math.max(0.15, Math.min(2, apdexMargin));
151
- const nextStep = Math.max(2, Math.floor(baseStep * adaptiveMultiplier));
231
+ const adaptiveMultiplier = Math.max(0.15, Math.min(2, isNaN(apdexMargin) ? 1 : apdexMargin));
232
+ let nextStep = Math.max(2, Math.floor(baseStep * adaptiveMultiplier));
233
+ if (currentThreads + nextStep > config.maxThreads) {
234
+ nextStep = config.maxThreads - currentThreads;
235
+ }
152
236
  console.log(`\u{1F4C8} [Step Adjustment]: Scaling factor ${adaptiveMultiplier.toFixed(2)}x. Next jump: +${nextStep} threads.`);
153
237
  currentThreads += nextStep;
154
238
  }
239
+ let semanticReport = null;
240
+ if (config.clusterLogs && aggregateErrorLogs.length > 0) {
241
+ console.log(`
242
+ \u{1F9E0} [Semantic Clustering]: Executing classification analyzer across ${aggregateErrorLogs.length} error entries...`);
243
+ const analyzer = new LogAnalyzer();
244
+ semanticReport = analyzer.process(aggregateErrorLogs);
245
+ console.log(`\u2705 Analysis Complete. Identified ${semanticReport.uniqueClustersCount} distinct signature blueprints.`);
246
+ }
155
247
  generateFinalAgentReport(history);
156
- exportHtmlDashboard(history, config, verdictReason);
248
+ exportHtmlDashboard(history, config, verdictReason, semanticReport);
157
249
  }
158
250
  async function runStandardStressTest(config) {
159
251
  console.log(`\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: ${config.threads} | Duration: ${config.durationSec}s]`);
160
- const metrics = await runBlazeCoreEngine(config);
252
+ const { metrics, rawErrors } = await runBlazeCoreEngine(config);
161
253
  printMatrixDashboard(metrics, config.threads);
162
254
  const history = [{
163
255
  threads: config.threads,
@@ -167,25 +259,44 @@ async function runStandardStressTest(config) {
167
259
  apdex: metrics.apdexScore,
168
260
  throughput: metrics.requestsPerSecond
169
261
  }];
262
+ let semanticReport = null;
263
+ if (config.clusterLogs && rawErrors.length > 0) {
264
+ const analyzer = new LogAnalyzer();
265
+ semanticReport = analyzer.process(rawErrors);
266
+ }
170
267
  const isPassed = metrics.apdexScore >= config.targetApdex && metrics.errorRate <= config.targetErrorRate;
171
268
  const verdictReason = isPassed ? "Static single-wave baseline checks concluded successfully without triggering health boundaries." : "Static verification loop completed with values exceeding defined quality thresholds.";
172
- exportHtmlDashboard(history, config, verdictReason);
269
+ exportHtmlDashboard(history, config, verdictReason, semanticReport);
173
270
  }
174
- function generateSimulationData(threads, durationSec) {
271
+ function generateSimulationData(threads, durationSec, maxAllowedLatencyMs) {
175
272
  const data = [];
176
- const totalRequests = threads * durationSec * 45;
273
+ const totalRequests = Math.max(15, threads * durationSec * 30);
177
274
  const startTime = Date.now();
178
- const stressFactor = threads > 120 ? Math.pow(threads / 120, 2.2) : 1;
275
+ const targetThresholdBreak = Math.max(5, Math.floor(maxAllowedLatencyMs * 0.05));
276
+ const isBreached = threads > targetThresholdBreak;
277
+ const stressFactor = isBreached ? Math.pow(threads / targetThresholdBreak, 1.5) : 1;
278
+ const errorPool = [
279
+ `Error: ECONNREFUSED 127.0.0.1:5432 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1605:16)`,
280
+ `HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 15000ms`,
281
+ `TypeError: Cannot read properties of undefined (reading 'config_id') at Object.execute (${path.sep}app${path.sep}dist${path.sep}handler.js:42:19)`
282
+ ];
179
283
  for (let i = 0; i < totalRequests; i++) {
180
- const isError = Math.random() < (threads > 180 ? 0.08 : 2e-3);
284
+ const isError = Math.random() < (isBreached ? 0.05 : 1e-3);
181
285
  const baseLatency = (25 + Math.random() * 35) * stressFactor;
286
+ let errorMessage;
287
+ let statusCode = 200;
288
+ if (isError) {
289
+ statusCode = 500;
290
+ errorMessage = `[${(/* @__PURE__ */ new Date()).toISOString()}] ` + errorPool[Math.floor(Math.random() * errorPool.length)];
291
+ }
182
292
  data.push({
183
293
  durationMs: isError ? baseLatency * 0.1 : baseLatency,
184
294
  timestampMs: startTime + Math.random() * (durationSec * 1e3),
185
295
  dnsTimeMs: 1 + Math.random() * 4,
186
296
  tcpTimeMs: 5 + Math.random() * 10,
187
297
  tlsTimeMs: 10 + Math.random() * 12,
188
- statusCode: isError ? 500 : 200
298
+ statusCode,
299
+ errorMessage
189
300
  });
190
301
  }
191
302
  return data.sort((a, b) => a.timestampMs - b.timestampMs);
@@ -197,7 +308,7 @@ function processMetricsTelemetry(requests, durationSec) {
197
308
  const stdDevMs = mathUtils.stdDev(durations, avgLatencyMs);
198
309
  const p95LatencyMs = mathUtils.percentile(durations, 95);
199
310
  const errorCount = requests.filter((r) => r.statusCode >= 400).length;
200
- const errorRate = errorCount / totalRequests;
311
+ const errorRate = totalRequests === 0 ? 0 : errorCount / totalRequests;
201
312
  const T = 100;
202
313
  const satisfied = requests.filter((r) => r.durationMs <= T && r.statusCode < 400).length;
203
314
  const tolerating = requests.filter((r) => r.durationMs > T && r.durationMs <= T * 4 && r.statusCode < 400).length;
@@ -217,9 +328,7 @@ function printMatrixDashboard(m, threads) {
217
328
  console.log(`-----------------------------------------------------------------------------------------`);
218
329
  console.log(`| Threads | Samples | Avg Latency | P95 Latency | Throughput | Error Rate | Apdex |`);
219
330
  console.log(`-----------------------------------------------------------------------------------------`);
220
- console.log(
221
- `| ${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)} |`
222
- );
331
+ 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)} |`);
223
332
  console.log(`-----------------------------------------------------------------------------------------`);
224
333
  }
225
334
  function generateFinalAgentReport(history) {
@@ -235,7 +344,7 @@ function generateFinalAgentReport(history) {
235
344
  console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
236
345
  console.log("=======================================================\n");
237
346
  }
238
- function exportHtmlDashboard(history, config, verdictReason) {
347
+ function exportHtmlDashboard(history, config, verdictReason, semanticReport) {
239
348
  const labels = history.map((h) => `${h.threads} Threads`);
240
349
  const throughputData = history.map((h) => h.throughput.toFixed(0));
241
350
  const latencyData = history.map((h) => h.avgLatency.toFixed(1));
@@ -243,9 +352,45 @@ function exportHtmlDashboard(history, config, verdictReason) {
243
352
  const waveListItems = history.map((h) => {
244
353
  return `<div class="wave-item">Wave (${h.threads} VUs): P95 ${h.p95Latency.toFixed(1)}ms, Errors ${(h.errorRate * 100).toFixed(1)}%</div>`;
245
354
  }).join("");
246
- const htmlContent = `<!DOCTYPE html>
247
- <html lang="en">
248
- <head>
355
+ let logClustersHtml = "";
356
+ if (semanticReport) {
357
+ logClustersHtml = `
358
+ <div class="card" style="margin-top: 2rem;">
359
+ <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
+ <table>
362
+ <thead>
363
+ <tr>
364
+ <th style="width: 10%;">Count</th>
365
+ <th style="width: 25%;">Classification Category</th>
366
+ <th style="width: 10%;">Severity</th>
367
+ <th style="width: 55%;">Structural Abstract Blueprint / Dynamic Log Fingerprint</th>
368
+ </tr>
369
+ </thead>
370
+ <tbody>
371
+ ${semanticReport.clusters.map((c) => {
372
+ let catColor = "#f87171";
373
+ if (c.category === "Environment_Infrastructure_Error") catColor = "#fb923c";
374
+ if (c.category === "Authentication_Error") catColor = "#c084fc";
375
+ let sevColor = c.severity === "CRITICAL" ? "#dc2626" : "#eab308";
376
+ return `
377
+ <tr>
378
+ <td><span style="font-size: 1.1rem; font-weight: bold; color: #f8fafc;">${c.count}</span></td>
379
+ <td><span style="color: ${catColor}; font-weight: 600;">${c.category}</span></td>
380
+ <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>
387
+ </tr>`;
388
+ }).join("")}
389
+ </tbody>
390
+ </table>
391
+ </div>`;
392
+ }
393
+ const htmlContent = `<!DOCTYPE html><html lang="en"><head>
249
394
  <meta charset="UTF-8">
250
395
  <title>Blaze Core Performance Report</title>
251
396
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
@@ -255,8 +400,6 @@ function exportHtmlDashboard(history, config, verdictReason) {
255
400
  .header { border-bottom: 1px solid #334155; padding-bottom: 1rem; margin-bottom: 1.5rem; }
256
401
  h1 { color: #38bdf8; margin: 0; font-size: 2rem; }
257
402
  .meta { color: #94a3b8; font-size: 0.9rem; margin-top: 0.5rem; }
258
-
259
- /* \u{1F916} AI VERDICT COMPONENT STYLING */
260
403
  .verdict-box {
261
404
  background: #111827;
262
405
  border: 1px dashed #ea580c;
@@ -291,27 +434,22 @@ function exportHtmlDashboard(history, config, verdictReason) {
291
434
  .wave-item {
292
435
  margin: 0.25rem 0;
293
436
  }
294
-
295
437
  .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(500px, 1fr)); gap: 2rem; margin-bottom: 2rem; }
296
438
  .card { background: #1e293b; border: 1px solid #334155; border-radius: 8px; padding: 1.5rem; }
297
439
  h3 { margin-top: 0; color: #cbd5e1; border-bottom: 1px solid #334155; padding-bottom: 0.5rem; }
298
440
  table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
299
- th, td { padding: 0.75rem; text-align: left; border-bottom: 1px solid #334155; }
441
+ th, td { padding: 0.75rem; text-align: left; border-bottom: 1px solid #334155; vertical-align: top; }
300
442
  th { color: #94a3b8; font-weight: 600; }
301
443
  tr:hover { background: #273549; }
302
444
  .badge { padding: 0.25rem 0.5rem; border-radius: 4px; font-size: 0.8rem; font-weight: bold; }
303
445
  .badge-success { background: #16a34a; color: #f0fdf4; }
304
446
  .badge-fail { background: #dc2626; color: #fef2f2; }
305
- </style>
306
- </head>
307
- <body>
447
+ </style></head><body>
308
448
  <div class="container">
309
449
  <div class="header">
310
450
  <h1>\u{1F525} Blaze Core Performance Analysis</h1>
311
451
  <div class="meta">Target Script: <code>${config.targetScript}</code> | Mode: ${config.isAgentic ? "\u{1F9E0} Intelligent Agentic" : "\u{1F3CB}\uFE0F Fixed Workload"}</div>
312
452
  </div>
313
-
314
- <!-- \u{1F916} AUTOMATED VERDICT CONTAINER -->
315
453
  <div class="verdict-box">
316
454
  <div class="verdict-title">\u{1F916} AI Stress-Testing Agent Verdict</div>
317
455
  <div class="verdict-text">
@@ -322,12 +460,10 @@ function exportHtmlDashboard(history, config, verdictReason) {
322
460
  ${waveListItems}
323
461
  </div>
324
462
  </div>
325
-
326
463
  <div class="grid">
327
464
  <div class="card"><canvas id="throughputChart"></canvas></div>
328
465
  <div class="card"><canvas id="latencyChart"></canvas></div>
329
466
  </div>
330
-
331
467
  <div class="card">
332
468
  <h3>Telemetry Matrix Logs</h3>
333
469
  <table>
@@ -345,8 +481,7 @@ function exportHtmlDashboard(history, config, verdictReason) {
345
481
  <tbody>
346
482
  ${history.map((h) => {
347
483
  const isPassed = h.apdex >= config.targetApdex && h.errorRate <= config.targetErrorRate;
348
- return `
349
- <tr>
484
+ return ` <tr>
350
485
  <td><strong>${h.threads}</strong></td>
351
486
  <td>${h.throughput.toFixed(0)} req/sec</td>
352
487
  <td>${h.avgLatency.toFixed(1)} ms</td>
@@ -363,12 +498,11 @@ function exportHtmlDashboard(history, config, verdictReason) {
363
498
  </tbody>
364
499
  </table>
365
500
  </div>
501
+ ${logClustersHtml}
366
502
  </div>
367
-
368
503
  <script>
369
504
  const labels = ${JSON.stringify(labels)};
370
-
371
- new Chart(document.getElementById('throughputChart'), {
505
+ new Chart(document.getElementById('throughputChart'), {
372
506
  type: 'line',
373
507
  data: {
374
508
  labels: labels,
@@ -383,7 +517,6 @@ function exportHtmlDashboard(history, config, verdictReason) {
383
517
  },
384
518
  options: { responsive: true, plugins: { legend: { labels: { color: '#f8fafc' } } } }
385
519
  });
386
-
387
520
  new Chart(document.getElementById('latencyChart'), {
388
521
  type: 'line',
389
522
  data: {
@@ -413,9 +546,7 @@ function exportHtmlDashboard(history, config, verdictReason) {
413
546
  }
414
547
  }
415
548
  });
416
- </script>
417
- </body>
418
- </html>`;
549
+ </script></body></html>`;
419
550
  try {
420
551
  fs.writeFileSync(config.outputHtml, htmlContent, "utf-8");
421
552
  console.log(`\u{1F4CA} Standalone Dashboard exported successfully to: ${path.resolve(config.outputHtml)}`);
@@ -424,9 +555,7 @@ function exportHtmlDashboard(history, config, verdictReason) {
424
555
  }
425
556
  }
426
557
  function printUsage() {
427
- console.log(`
428
- Blaze Core Performance Test CLI Engine
429
-
558
+ console.log(`Blaze Core Performance Test CLI Engine
430
559
  Usage:
431
560
  blaze <target-script.ts> [options]
432
561
 
@@ -434,6 +563,7 @@ Options:
434
563
  --threads <count> Number of working execution thread pools (Default: 10)
435
564
  --duration <seconds> Test time frame duration (Default: 10s)
436
565
  --agentic Engages Intelligent Autonomous Adaptive Loop Testing
566
+ --cluster-logs Enables Semantic Log Clustering and Analysis
437
567
  --target-apdex <score> Target threshold cutoff limit for Apdex (Default: 0.85)
438
568
  --target-error <rate> Target cutoff threshold percentage for failures (Default: 0.01)
439
569
  --max-threads <count> Safety bounding limit cap for Agent ramp-up (Default: 300)
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blaze-performance-tester",
3
- "version": "3.0.4",
3
+ "version": "3.0.18",
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",
package/readme.md CHANGED
@@ -48,7 +48,7 @@ Execution Example
48
48
  To launch 10 concurrent virtual user threads pounding your target workload continuously for an execution duration window of 5 seconds, run this exact command inside your terminal:
49
49
 
50
50
  DOS
51
- C:\perf>npx blaze-performance-tester@1.1.22 tests/test-script.ts 10 5
51
+ C:\perf>npx blaze-performance-tester@latest tests/test-script.ts 10 5
52
52
  πŸ“Š Analytics & Telemetry Engine
53
53
  Upon wrapping up its concurrency window, Blaze automatically maps, calculates, and dumps a dual-layered architectural metrics profile straight into your working path.
54
54
 
@@ -68,4 +68,30 @@ Plaintext
68
68
  Test Execution Finished. Elapsed time: 5.03s | Target VUs: 10
69
69
  2. Beautiful HTML Interactive Dashboard
70
70
  Alongside the console logs, a fully styled, portable, dark-mode data visualization dashboard file is generated on-disk:
71
- πŸ“ Location: ./blaze-html-report.html
71
+ πŸ“ Location: ./blaze-html-report.html
72
+
73
+ AI Mode (Agentic AI)
74
+
75
+ πŸ“‘ Blaze Performance TesterAn ultra-high-performance, native C++ accelerated performance engineering framework with built-in Intelligent Autonomous Agent Mode. Blaze lets you design script-based load configurations, profile core infrastructure capacity boundaries safely, and automatically generate telemetry dashboards.
76
+
77
+ πŸš€ Getting Started
78
+
79
+ You can invoke the runner globally without installing dependencies directly from npm.Standard Fixed-Workload Command PatternTo spin up a rigid, predefined benchmark wave, pass your metrics targets as standard CLI flags:
80
+
81
+ npx blaze-performance-tester@latest tests/test-script.ts --threads 50 --duration 5 --target-error 0.02
82
+
83
+ 🧠 Agentic AI Mode (Autonomous Performance Engineering)Don’t know your system limits? Just define your SLA parameters and let the AI agent discover your infrastructure breaking points safely.
84
+
85
+ npx blaze-performance-tester@latest tests/test-script.ts --agentic 100 250 2.0
86
+
87
+
88
+ πŸ“Š Analytics & Automated Reporting
89
+ Every run automatically generates a self-contained, interactive blaze-dashboard.html visualization suite.
90
+
91
+ Features Includes:
92
+
93
+ πŸ’€ AI Stress-Testing Agent Verdict: A visual diagnostic block summarizing the exact nature of system constraints (e.g., infrastructure saturation vs direct SLA latency/error guardrail breaches) alongside detailed logs of each evaluated test wave.
94
+
95
+ πŸ“ˆ Dual-Axis Telemetry Tracking: Real-time visual tracking mapping throughput ($req/sec$) directly alongside corresponding $P_{95}$ latency metrics scaling over your execution timeline.
96
+
97
+ πŸ“‹ JMeter-Style Matrix Log: Detailed breakdown charts outputting comprehensive metrics matrices (Samples, Average Latency, $P_{95}$ Latency, Error Rates, Apdex Scores) across every incremental concurrency level tested.