blaze-performance-tester 3.1.60 → 3.1.62
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/bin.js +2 -0
- package/dist/cli.js +312 -302
- package/dist/index.win32-x64-msvc.node +0 -0
- package/package.json +6 -8
package/bin.js
ADDED
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env ts-node
|
|
3
2
|
|
|
4
3
|
// cli.ts
|
|
5
|
-
import { Command } from "commander";
|
|
6
|
-
import chalk from "chalk";
|
|
7
4
|
import { createRequire } from "module";
|
|
8
5
|
import * as path from "path";
|
|
9
6
|
import { fileURLToPath } from "url";
|
|
@@ -26,7 +23,13 @@ var LogAnalyzer = class {
|
|
|
26
23
|
return { category: "Environment_Infrastructure_Error", severity: "CRITICAL" };
|
|
27
24
|
}
|
|
28
25
|
if (LowercaseTpl.includes("401") || LowercaseTpl.includes("403") || LowercaseTpl.includes("unauthorized") || LowercaseTpl.includes("forbidden") || LowercaseTpl.includes("jwt") || LowercaseTpl.includes("token expired")) {
|
|
29
|
-
return { category: "Authentication_Error", severity: "
|
|
26
|
+
return { category: "Authentication_Error", severity: "HIGH" };
|
|
27
|
+
}
|
|
28
|
+
if (LowercaseTpl.includes("429") || LowercaseTpl.includes("rate limit") || LowercaseTpl.includes("too many requests")) {
|
|
29
|
+
return { category: "Traffic_Management_Error", severity: "MEDIUM" };
|
|
30
|
+
}
|
|
31
|
+
if (LowercaseTpl.includes("typeerror") || LowercaseTpl.includes("undefined") || LowercaseTpl.includes("nullpointer") || LowercaseTpl.includes("cannot read properties")) {
|
|
32
|
+
return { category: "Product_Error", severity: "CRITICAL" };
|
|
30
33
|
}
|
|
31
34
|
return { category: "Product_Error", severity: "WARNING" };
|
|
32
35
|
}
|
|
@@ -34,16 +37,17 @@ var LogAnalyzer = class {
|
|
|
34
37
|
* Generates actionable architectural and code-level fixes based on log structural fingerprints
|
|
35
38
|
*/
|
|
36
39
|
generatePlaybook(template, severity) {
|
|
37
|
-
if (severity !== "CRITICAL" && severity !== "HIGH") {
|
|
40
|
+
if (severity !== "CRITICAL" && severity !== "HIGH" && severity !== "MEDIUM") {
|
|
38
41
|
return void 0;
|
|
39
42
|
}
|
|
43
|
+
const lowerTemplate = template.toLowerCase();
|
|
40
44
|
if (template.includes("ECONNREFUSED") || template.includes("5432")) {
|
|
41
45
|
return `**Database Connectivity Failure**
|
|
42
46
|
1. **Service Triage:** Verify the target PostgreSQL instance at 127.0.0.1:5432 is running using \`pg_isready\`.
|
|
43
47
|
2. **Resource Exhaustion:** Scale up the \`max_connections\` configuration value within \`postgresql.conf\`.
|
|
44
48
|
3. **Pool Allocation:** Implement an intermediate connection pool architecture (e.g., PgBouncer) to multiplex open client socket handles under heavy concurrent execution paths.`;
|
|
45
49
|
}
|
|
46
|
-
if (template.includes("504 Gateway Timeout") || template.includes("upstream socket drop")) {
|
|
50
|
+
if (template.includes("504 Gateway Timeout") || template.includes("upstream socket drop") || template.includes("Timeout")) {
|
|
47
51
|
return `**Upstream Gateway Timeout Saturation**
|
|
48
52
|
1. **Timeout Alignment:** Ensure proxy gateway network ingress drop timeouts align tightly with upstream processing deadlines.
|
|
49
53
|
2. **Circuit Breaking:** Introduce adaptive circuit breakers around the processing endpoint to fail fast during database or background service degradation.
|
|
@@ -61,10 +65,19 @@ var LogAnalyzer = class {
|
|
|
61
65
|
2. **Clock Alignment:** Synchronize target nodes against global Network Time Protocol (NTP) servers to resolve microsecond runtime verification discrepancies.
|
|
62
66
|
3. **Grace Window:** Configure a short crypto-signature processing grace duration window (e.g., 5-10 seconds) to tolerate delayed network transfer offsets gracefully.`;
|
|
63
67
|
}
|
|
64
|
-
|
|
68
|
+
if (lowerTemplate.includes("429") || lowerTemplate.includes("rate limit") || lowerTemplate.includes("too many requests")) {
|
|
69
|
+
return `**Traffic Rate Limit Triggered**
|
|
70
|
+
1. **Backoff Mechanism:** Implement exponential backoff with jitter on client-side application logic to safely space out request retry cascades.
|
|
71
|
+
2. **Threshold Tuning:** Calibrate upstream API Gateway rate-limit configurations to align with real-time horizontal capacity thresholds.
|
|
72
|
+
3. **Tiered Allocations:** Map client credentials or IP subnets to segmented capacity bands to protect core consumer endpoints.`;
|
|
73
|
+
}
|
|
74
|
+
if (severity === "CRITICAL" || severity === "HIGH") {
|
|
75
|
+
return `**High-Severity System Anomaly Action Plan**
|
|
65
76
|
1. **Telemetry Trace Mapping:** Isolate the context block Trace ID and map performance timelines to identify execution resource constraints.
|
|
66
77
|
2. **Host Allocation Audit:** Verify host environment memory usage limits, network interface drops, and CPU usage trends at the time of the fault.
|
|
67
78
|
3. **Isolation Testing:** Repro the exact exception signature inside sandbox configurations utilizing targeted load testing sweeps.`;
|
|
79
|
+
}
|
|
80
|
+
return void 0;
|
|
68
81
|
}
|
|
69
82
|
/**
|
|
70
83
|
* Processes a stream of raw textual error logs into deduplicated clustered fingerprints
|
|
@@ -89,12 +102,16 @@ var LogAnalyzer = class {
|
|
|
89
102
|
template = "Error: ECONNREFUSED 127.0.0.1:5432 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1)";
|
|
90
103
|
} else if (cleanLog.includes("TypeError") || cleanLog.includes("Cannot read properties")) {
|
|
91
104
|
category = "Product_Error";
|
|
92
|
-
severity = "
|
|
105
|
+
severity = "CRITICAL";
|
|
93
106
|
template = "TypeError: Cannot read properties of undefined (reading 'config_id') at Object.execute (\\app\\dist\\handler.js:42:19)";
|
|
94
|
-
} else if (cleanLog.includes("504 Gateway Timeout")) {
|
|
107
|
+
} else if (cleanLog.includes("504 Gateway Timeout") || cleanLog.includes("upstream socket drop")) {
|
|
95
108
|
category = "Environment_Infrastructure_Error";
|
|
96
109
|
severity = "CRITICAL";
|
|
97
110
|
template = cleanLog.includes("15000ms") ? "HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 15000ms" : "HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 30000ms";
|
|
111
|
+
} else if (cleanLog.includes("429") || /rate limit|too many requests/i.test(cleanLog)) {
|
|
112
|
+
category = "Traffic_Management_Error";
|
|
113
|
+
severity = "MEDIUM";
|
|
114
|
+
template = "HTTP/1.1 429 Too Many Requests - Rate limit exceeded";
|
|
98
115
|
}
|
|
99
116
|
if (!template) {
|
|
100
117
|
template = this.extractLogTemplate(log);
|
|
@@ -137,7 +154,8 @@ var blazeCore;
|
|
|
137
154
|
try {
|
|
138
155
|
blazeCore = require2(nativeBindingPath);
|
|
139
156
|
} catch (e) {
|
|
140
|
-
console.error(
|
|
157
|
+
console.error(`\u274C Failed to load native C++ bindings from ${nativeBindingPath}`);
|
|
158
|
+
process.exit(1);
|
|
141
159
|
}
|
|
142
160
|
var mathUtils = {
|
|
143
161
|
mean: (arr) => arr.length === 0 ? 0 : arr.reduce((p, c) => p + c, 0) / arr.length,
|
|
@@ -153,46 +171,6 @@ var mathUtils = {
|
|
|
153
171
|
return sorted[Math.max(0, index)];
|
|
154
172
|
}
|
|
155
173
|
};
|
|
156
|
-
function getMockRegionalData() {
|
|
157
|
-
return [
|
|
158
|
-
{ zone: "us-east-1", location: "N. Virginia", latencyAvg: 24, p99: 68, errorRate: 0.02, status: "optimal" },
|
|
159
|
-
{ zone: "eu-central-1", location: "Frankfurt", latencyAvg: 42, p99: 115, errorRate: 0.14, status: "stable" },
|
|
160
|
-
{ zone: "ap-south-1", location: "Mumbai", latencyAvg: 88, p99: 210, errorRate: 0.85, status: "elevated" },
|
|
161
|
-
{ zone: "ap-northeast-1", location: "Tokyo", latencyAvg: 55, p99: 130, errorRate: 0.05, status: "stable" },
|
|
162
|
-
{ zone: "sa-east-1", location: "S\xE3o Paulo", latencyAvg: 112, p99: 285, errorRate: 1.2, status: "critical" }
|
|
163
|
-
];
|
|
164
|
-
}
|
|
165
|
-
function renderStatusBadge(status) {
|
|
166
|
-
switch (status) {
|
|
167
|
-
case "optimal":
|
|
168
|
-
return chalk.green("\u{1F7E2} OPTIMAL");
|
|
169
|
-
case "stable":
|
|
170
|
-
return chalk.green("\u{1F7E2} STABLE");
|
|
171
|
-
case "elevated":
|
|
172
|
-
return chalk.yellow("\u{1F7E1} ELEVATED");
|
|
173
|
-
case "critical":
|
|
174
|
-
return chalk.red("\u{1F534} CRITICAL");
|
|
175
|
-
default:
|
|
176
|
-
return chalk.gray("\u26AA UNKNOWN");
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
function renderGeographicHeatmap(regions) {
|
|
180
|
-
console.log(chalk.bold.cyan("\n============================================================"));
|
|
181
|
-
console.log(chalk.bold.cyan(" BLAZE: GEOGRAPHIC LATENCY HEATMAP & MATRIX "));
|
|
182
|
-
console.log(chalk.bold.cyan("============================================================\n"));
|
|
183
|
-
console.log(
|
|
184
|
-
`${chalk.bold("Zone".padEnd(16))} | ${chalk.bold("Location".padEnd(14))} | ${chalk.bold("Avg (ms)".padEnd(10))} | ${chalk.bold("P99 (ms)".padEnd(10))} | ${chalk.bold("Error Rate".padEnd(12))} | ${chalk.bold("Status")}`
|
|
185
|
-
);
|
|
186
|
-
console.log("-".repeat(78));
|
|
187
|
-
for (const r of regions) {
|
|
188
|
-
const errorColor = r.errorRate > 1 ? chalk.red : r.errorRate > 0.5 ? chalk.yellow : chalk.green;
|
|
189
|
-
const latencyColor = r.latencyAvg > 100 ? chalk.yellow : chalk.white;
|
|
190
|
-
console.log(
|
|
191
|
-
`${r.zone.padEnd(16)} | ${r.location.padEnd(14)} | ${latencyColor(String(r.latencyAvg).padEnd(10))} | ${String(r.p99).padEnd(10)} | ${errorColor(`${r.errorRate.toFixed(2)}%`).padEnd(20)} | ${renderStatusBadge(r.status)}`
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
console.log("\n");
|
|
195
|
-
}
|
|
196
174
|
function getLoadMultiplier(elapsedMs, rampUpMs, steadyMs, rampDownMs) {
|
|
197
175
|
const totalDurationMs = rampUpMs + steadyMs + rampDownMs;
|
|
198
176
|
if (elapsedMs < rampUpMs && rampUpMs > 0) {
|
|
@@ -210,64 +188,20 @@ function loadBaselineData(filePath) {
|
|
|
210
188
|
try {
|
|
211
189
|
const resolved = path.resolve(filePath);
|
|
212
190
|
if (fs.existsSync(resolved)) {
|
|
213
|
-
console.log(
|
|
191
|
+
console.log(`\u{1F4C1} Loaded baseline comparison telemetry from: ${resolved}`);
|
|
214
192
|
return JSON.parse(fs.readFileSync(resolved, "utf-8"));
|
|
215
193
|
}
|
|
216
194
|
} catch (e) {
|
|
217
|
-
console.error(
|
|
195
|
+
console.error(`\u274C Failed to parse baseline telemetry file: ${e}`);
|
|
218
196
|
}
|
|
219
197
|
return null;
|
|
220
198
|
}
|
|
221
|
-
function calculateSeoImpactMetrics(avgLatencyMs) {
|
|
222
|
-
const baseLineOptimalMs = 200;
|
|
223
|
-
if (avgLatencyMs <= baseLineOptimalMs) {
|
|
224
|
-
return { trafficLoss: 0, status: "Excellent", crawlPenalty: "None", color: "#10b981" };
|
|
225
|
-
}
|
|
226
|
-
const delayFactor = avgLatencyMs - baseLineOptimalMs;
|
|
227
|
-
const trafficLoss = Math.min(94, Math.floor(delayFactor / 1200 * 100));
|
|
228
|
-
let status = "Healthy";
|
|
229
|
-
let crawlPenalty = "Minimal impact on indexing rates.";
|
|
230
|
-
let color = "#10b981";
|
|
231
|
-
if (trafficLoss >= 50) {
|
|
232
|
-
status = "Critical Exposure";
|
|
233
|
-
crawlPenalty = "Severe penalty. Googlebot will heavily restrict crawl budgets due to timeout risks.";
|
|
234
|
-
color = "#ef4444";
|
|
235
|
-
} else if (trafficLoss >= 20) {
|
|
236
|
-
status = "Moderate Danger";
|
|
237
|
-
crawlPenalty = "Delayed indexation. Core Web Vital thresholds are officially breached.";
|
|
238
|
-
color = "#f97316";
|
|
239
|
-
} else if (trafficLoss > 5) {
|
|
240
|
-
status = "Minor Impact";
|
|
241
|
-
crawlPenalty = "Slightly elevated bounce trends could impact highly volatile rankings.";
|
|
242
|
-
color = "#eab308";
|
|
243
|
-
}
|
|
244
|
-
return { trafficLoss, status, crawlPenalty, color };
|
|
245
|
-
}
|
|
246
|
-
function computeHealthScoreValue(apdex, errorRate, p95Latency, maxAllowedLatency) {
|
|
247
|
-
const apdexComponent = apdex * 50;
|
|
248
|
-
const errorComponent = Math.max(0, 1 - errorRate) * 30;
|
|
249
|
-
const latencyRatio = p95Latency / maxAllowedLatency;
|
|
250
|
-
const latencyComponent = Math.max(0, 1 - Math.min(1, latencyRatio)) * 20;
|
|
251
|
-
return Math.min(100, Math.max(0, Math.round(apdexComponent + errorComponent + latencyComponent)));
|
|
252
|
-
}
|
|
253
|
-
function getFallbackClusterLogs() {
|
|
254
|
-
const logs = [];
|
|
255
|
-
const add = (msg, count) => {
|
|
256
|
-
for (let i = 0; i < count; i++) logs.push(`[2026-07-08T12:08:18.000Z] ${msg}`);
|
|
257
|
-
};
|
|
258
|
-
add("JsonWebTokenError: jwt expired at JMT.verify (\\app\\node_modules\\jsonwebtoken\\index.js:5)", 37);
|
|
259
|
-
add("Error: ECONNREFUSED 127.0.0.1:5432 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1)", 33);
|
|
260
|
-
add("TypeError: Cannot read properties of undefined (reading 'config_id') at Object.execute (\\app\\dist\\handler.js:42:19)", 31);
|
|
261
|
-
add("HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 15000ms", 25);
|
|
262
|
-
add("HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 30000ms", 19);
|
|
263
|
-
return logs;
|
|
264
|
-
}
|
|
265
199
|
async function generateGeminiRCA(history, finalSummary, errorLogs) {
|
|
266
200
|
const apiKey = process.env.GEMINI_API_KEY;
|
|
267
201
|
if (!apiKey) {
|
|
268
202
|
return `<span style="color: #ef4444;">\u26A0\uFE0F Gemini API Key missing. Export GEMINI_API_KEY to enable automated 2.5 Flash RCA analysis.</span>`;
|
|
269
203
|
}
|
|
270
|
-
console.log(
|
|
204
|
+
console.log("\u{1F9E0} Querying Gemini 2.5 Flash for Advanced Root Cause Analysis...");
|
|
271
205
|
const formattedHistory = history.map(
|
|
272
206
|
(h) => `Threads: ${h.threads} VUs | Throughput: ${h.throughput.toFixed(1)} req/s | Avg Latency: ${h.avgLatency.toFixed(1)}ms | Errors: ${(h.errorRate * 100).toFixed(2)}% | Apdex: ${h.apdex.toFixed(2)}`
|
|
273
207
|
).join("\n");
|
|
@@ -323,97 +257,127 @@ CRITICAL: Return ONLY plain paragraph text. Do not use markdown headers (###). I
|
|
|
323
257
|
}
|
|
324
258
|
return candidateText.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>").replace(/\n/g, "<br>");
|
|
325
259
|
} catch (error) {
|
|
326
|
-
console.error(
|
|
260
|
+
console.error("\u274C Gemini API processing breakdown failure:", error);
|
|
327
261
|
return `<span style="color: #f87171;">Failed to generate AI diagnosis framework: ${error.message || error}</span>`;
|
|
328
262
|
}
|
|
329
263
|
}
|
|
330
|
-
function
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
let statusCode = 200;
|
|
351
|
-
if (isError) {
|
|
352
|
-
const targetResponseCodes = [400, 401, 403, 404, 429, 500, 502, 503, 504];
|
|
353
|
-
statusCode = targetResponseCodes[Math.floor(Math.random() * targetResponseCodes.length)];
|
|
354
|
-
errorMessage = errorPool[Math.floor(Math.random() * errorPool.length)];
|
|
264
|
+
async function executeTestPipeline(config) {
|
|
265
|
+
if (!blazeCore || typeof blazeCore.runCorrelatedTransaction !== "function") {
|
|
266
|
+
console.error("\u274C Error: runCorrelatedTransaction function is missing from the compiled binary bindings.");
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
const transactionalScenario = [
|
|
270
|
+
{
|
|
271
|
+
name: "Fetch Target Anti-Forgery Nonce",
|
|
272
|
+
url: "https://httpbin.org/json",
|
|
273
|
+
method: "GET",
|
|
274
|
+
body: null
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
name: "Perform Contextual Post Action",
|
|
278
|
+
url: "https://httpbin.org/post?verification=${csrf_token}",
|
|
279
|
+
method: "POST",
|
|
280
|
+
body: JSON.stringify({
|
|
281
|
+
data: "performance_payload",
|
|
282
|
+
security_token: "${csrf_token}"
|
|
283
|
+
})
|
|
355
284
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
285
|
+
];
|
|
286
|
+
console.log(`Launching automated script transaction analysis for: ${config.targetScript}`);
|
|
287
|
+
const sanitizedSteps = transactionalScenario.map((step) => ({
|
|
288
|
+
...step,
|
|
289
|
+
body: typeof step.body === "string" ? step.body : step.body ? JSON.stringify(step.body) : ""
|
|
290
|
+
}));
|
|
291
|
+
const success = await blazeCore.runCorrelatedTransaction(sanitizedSteps);
|
|
292
|
+
if (success) {
|
|
293
|
+
console.log("Pipeline run complete. Parameter tracking successfully mitigated breaking changes.");
|
|
365
294
|
}
|
|
366
|
-
return data.sort((a, b) => a.timestampMs - b.timestampMs);
|
|
367
295
|
}
|
|
368
|
-
function
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
const
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
296
|
+
async function main() {
|
|
297
|
+
const args = process.argv.slice(2);
|
|
298
|
+
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
299
|
+
printUsage();
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const config = parseArguments(args);
|
|
303
|
+
if (config.isCorrelate) {
|
|
304
|
+
await executeTestPipeline(config);
|
|
305
|
+
}
|
|
306
|
+
if (config.isAgentic) {
|
|
307
|
+
await runIntelligentAgenticStressTest(config);
|
|
308
|
+
} else {
|
|
309
|
+
await runStandardStressTest(config);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function parseArguments(args) {
|
|
313
|
+
const targetScript = path.resolve(args[0] || ".");
|
|
314
|
+
const isAgentic = args.includes("--agentic");
|
|
315
|
+
const isCorrelate = args.includes("--correlate");
|
|
316
|
+
const isSeo = args.includes("--seo");
|
|
317
|
+
const clusterLogs = !args.includes("--no-cluster-logs");
|
|
318
|
+
let threads = 10;
|
|
319
|
+
let durationSec = 10;
|
|
320
|
+
let rampUpSec = 0;
|
|
321
|
+
let rampDownSec = 0;
|
|
322
|
+
let targetApdex = 0.85;
|
|
323
|
+
let targetErrorRate = 0.01;
|
|
324
|
+
let maxThreads = 300;
|
|
325
|
+
let maxAllowedLatencyMs = 800;
|
|
326
|
+
let outputHtml = "blaze-dashboard.html";
|
|
327
|
+
let baselinePath = null;
|
|
328
|
+
const threadsIdx = args.indexOf("--threads");
|
|
329
|
+
if (threadsIdx !== -1) threads = parseInt(args[threadsIdx + 1], 10);
|
|
330
|
+
const durationIdx = args.indexOf("--duration");
|
|
331
|
+
if (durationIdx !== -1) durationSec = parseInt(args[durationIdx + 1], 10);
|
|
332
|
+
const rampUpIdx = args.indexOf("--ramp-up");
|
|
333
|
+
if (rampUpIdx !== -1) rampUpSec = parseInt(args[rampUpIdx + 1], 10);
|
|
334
|
+
const rampDownIdx = args.indexOf("--ramp-down");
|
|
335
|
+
if (rampDownIdx !== -1) rampDownSec = parseInt(args[rampDownIdx + 1], 10);
|
|
336
|
+
const apdexIdx = args.indexOf("--target-apdex");
|
|
337
|
+
if (apdexIdx !== -1) targetApdex = parseFloat(args[apdexIdx + 1]);
|
|
338
|
+
const errorIdx = args.indexOf("--target-error");
|
|
339
|
+
if (errorIdx !== -1) targetErrorRate = parseFloat(args[errorIdx + 1]);
|
|
340
|
+
const maxThreadsIdx = args.indexOf("--max-threads");
|
|
341
|
+
if (maxThreadsIdx !== -1) maxThreads = parseInt(args[maxThreadsIdx + 1], 10);
|
|
342
|
+
const outputIdx = args.indexOf("--output");
|
|
343
|
+
if (outputIdx !== -1) outputHtml = args[outputIdx + 1];
|
|
344
|
+
const baselineIdx = args.indexOf("--baseline");
|
|
345
|
+
if (baselineIdx !== -1) baselinePath = args[baselineIdx + 1];
|
|
346
|
+
const positionalNums = args.slice(1).filter((arg) => !arg.startsWith("-")).map(Number).filter((n) => !isNaN(n));
|
|
347
|
+
if (positionalNums.length > 0 && threadsIdx === -1 && !isAgentic) threads = positionalNums[0];
|
|
348
|
+
if (positionalNums.length > 1 && durationIdx === -1 && !isAgentic) durationSec = positionalNums[1];
|
|
349
|
+
if (positionalNums.length > 2 && errorIdx === -1 && !isAgentic) targetErrorRate = positionalNums[2] / 100;
|
|
350
|
+
if (isAgentic) {
|
|
351
|
+
const agenticIdx = args.indexOf("--agentic");
|
|
352
|
+
const trailingArgs = args.slice(agenticIdx + 1).filter((arg) => !arg.startsWith("--"));
|
|
353
|
+
if (trailingArgs[0]) maxThreads = parseInt(trailingArgs[0], 10);
|
|
354
|
+
if (trailingArgs[1]) {
|
|
355
|
+
let rawLatency = parseFloat(trailingArgs[1]);
|
|
356
|
+
if (rawLatency < 50) {
|
|
357
|
+
maxAllowedLatencyMs = rawLatency * 1e3;
|
|
358
|
+
} else {
|
|
359
|
+
maxAllowedLatencyMs = rawLatency;
|
|
360
|
+
}
|
|
389
361
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
const errorRate = totalRequests === 0 ? 0 : errorCount / totalRequests;
|
|
393
|
-
const T = 50;
|
|
394
|
-
const satisfied = requests.filter((r) => r.durationMs <= T && r.statusCode < 400).length;
|
|
395
|
-
const tolerating = requests.filter((r) => r.durationMs > T && r.durationMs <= T * 4 && r.statusCode < 400).length;
|
|
396
|
-
const apdexScore = totalRequests === 0 ? 0 : (satisfied + tolerating / 2) / totalRequests;
|
|
397
|
-
const bandwidthMb = totalRequests * 1.2 / durationSec / 10;
|
|
362
|
+
if (trailingArgs[2]) targetErrorRate = parseFloat(trailingArgs[2]) / 100;
|
|
363
|
+
}
|
|
398
364
|
return {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
bandwidthMb,
|
|
416
|
-
codeCounts
|
|
365
|
+
targetScript,
|
|
366
|
+
isAgentic,
|
|
367
|
+
isCorrelate,
|
|
368
|
+
isSeo,
|
|
369
|
+
clusterLogs,
|
|
370
|
+
threads,
|
|
371
|
+
durationSec,
|
|
372
|
+
rampUpSec,
|
|
373
|
+
rampDownSec,
|
|
374
|
+
targetApdex,
|
|
375
|
+
targetErrorRate,
|
|
376
|
+
maxThreads,
|
|
377
|
+
stepSize: 15,
|
|
378
|
+
maxAllowedLatencyMs,
|
|
379
|
+
outputHtml,
|
|
380
|
+
baselinePath
|
|
417
381
|
};
|
|
418
382
|
}
|
|
419
383
|
async function runBlazeCoreEngine(config) {
|
|
@@ -437,62 +401,40 @@ async function runBlazeCoreEngine(config) {
|
|
|
437
401
|
}, 1e3);
|
|
438
402
|
});
|
|
439
403
|
}
|
|
440
|
-
function
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
console.log(`-----------------------------------------------------------------------------------------`);
|
|
445
|
-
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)} |`);
|
|
446
|
-
console.log(`-----------------------------------------------------------------------------------------`);
|
|
447
|
-
}
|
|
448
|
-
function generateFinalAgentReport(history, score) {
|
|
449
|
-
if (history.length === 0) return;
|
|
450
|
-
const peakThroughput = Math.max(...history.map((h) => h.throughput));
|
|
451
|
-
const cleanRuns = history.filter((h) => h.apdex >= 0.85 && h.errorRate <= 0.01);
|
|
452
|
-
const maxSafeThreads = cleanRuns.length > 0 ? cleanRuns[cleanRuns.length - 1].threads : history[0].threads;
|
|
453
|
-
console.log(chalk.bold.green("\n======================================================="));
|
|
454
|
-
console.log(chalk.bold.cyan("\u{1F9E0} INTELLIGENT AUTONOMOUS LOAD AGENT FINAL REPORT"));
|
|
455
|
-
console.log(chalk.bold.green("======================================================="));
|
|
456
|
-
console.log(`\u{1F7E2} Unified Blaze Health Score : ${score}/100`);
|
|
457
|
-
console.log(`\u{1F3C6} Recommended Max Safe Concurrency : ${maxSafeThreads} allocation threads`);
|
|
458
|
-
console.log(`\u{1F4A5} Infrastructure Failure Boundary : ${history[history.length - 1].threads} concurrency allocation`);
|
|
459
|
-
console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
|
|
460
|
-
console.log(chalk.bold.green("=======================================================\n"));
|
|
461
|
-
}
|
|
462
|
-
async function executeTestPipeline(config) {
|
|
463
|
-
if (!blazeCore || typeof blazeCore.runCorrelatedTransaction !== "function") {
|
|
464
|
-
console.error(chalk.red("\u274C Error: runCorrelatedTransaction function is missing from the compiled binary bindings."));
|
|
465
|
-
return;
|
|
404
|
+
function calculateSeoImpactMetrics(avgLatencyMs) {
|
|
405
|
+
const baseLineOptimalMs = 200;
|
|
406
|
+
if (avgLatencyMs <= baseLineOptimalMs) {
|
|
407
|
+
return { trafficLoss: 0, status: "Excellent", crawlPenalty: "None", color: "#10b981" };
|
|
466
408
|
}
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
console.log(chalk.blue(`Launching automated script transaction analysis for: ${config.targetScript}`));
|
|
485
|
-
const sanitizedSteps = transactionalScenario.map((step) => ({
|
|
486
|
-
...step,
|
|
487
|
-
body: typeof step.body === "string" ? step.body : step.body ? JSON.stringify(step.body) : ""
|
|
488
|
-
}));
|
|
489
|
-
const success = await blazeCore.runCorrelatedTransaction(sanitizedSteps);
|
|
490
|
-
if (success) {
|
|
491
|
-
console.log(chalk.green("Pipeline run complete. Parameter tracking successfully mitigated breaking changes."));
|
|
409
|
+
const delayFactor = avgLatencyMs - baseLineOptimalMs;
|
|
410
|
+
const trafficLoss = Math.min(94, Math.floor(delayFactor / 1200 * 100));
|
|
411
|
+
let status = "Healthy";
|
|
412
|
+
let crawlPenalty = "Minimal impact on indexing rates.";
|
|
413
|
+
let color = "#10b981";
|
|
414
|
+
if (trafficLoss >= 50) {
|
|
415
|
+
status = "Critical Exposure";
|
|
416
|
+
crawlPenalty = "Severe penalty. Googlebot will heavily restrict crawl budgets due to timeout risks.";
|
|
417
|
+
color = "#ef4444";
|
|
418
|
+
} else if (trafficLoss >= 20) {
|
|
419
|
+
status = "Moderate Danger";
|
|
420
|
+
crawlPenalty = "Delayed indexation. Core Web Vital thresholds are officially breached.";
|
|
421
|
+
color = "#f97316";
|
|
422
|
+
} else if (trafficLoss > 5) {
|
|
423
|
+
status = "Minor Impact";
|
|
424
|
+
crawlPenalty = "Slightly elevated bounce trends could impact highly volatile rankings.";
|
|
425
|
+
color = "#eab308";
|
|
492
426
|
}
|
|
427
|
+
return { trafficLoss, status, crawlPenalty, color };
|
|
428
|
+
}
|
|
429
|
+
function computeHealthScoreValue(apdex, errorRate, p95Latency, maxAllowedLatency) {
|
|
430
|
+
const apdexComponent = apdex * 50;
|
|
431
|
+
const errorComponent = Math.max(0, 1 - errorRate) * 30;
|
|
432
|
+
const latencyRatio = p95Latency / maxAllowedLatency;
|
|
433
|
+
const latencyComponent = Math.max(0, 1 - Math.min(1, latencyRatio)) * 20;
|
|
434
|
+
return Math.min(100, Math.max(0, Math.round(apdexComponent + errorComponent + latencyComponent)));
|
|
493
435
|
}
|
|
494
436
|
async function runIntelligentAgenticStressTest(config) {
|
|
495
|
-
console.log(
|
|
437
|
+
console.log("\u{1F680} Initializing Intelligent Autonomous Load Agent...");
|
|
496
438
|
const history = [];
|
|
497
439
|
let aggregateErrorLogs = [];
|
|
498
440
|
let lastRawRequests = [];
|
|
@@ -506,7 +448,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
506
448
|
let verdictReason = "The system successfully scaled and remained stable within parameters up to maximum configured capacity allocations.";
|
|
507
449
|
let saturationKneePoint = null;
|
|
508
450
|
while (currentThreads <= config.maxThreads && isStable) {
|
|
509
|
-
console.log(
|
|
451
|
+
console.log(`\u{1F916} [Agent Decision]: Testing execution tier at ${currentThreads} concurrent threads...`);
|
|
510
452
|
const { metrics, rawErrors, rawRequests } = await runBlazeCoreEngine({ ...config, threads: currentThreads });
|
|
511
453
|
if (config.clusterLogs) {
|
|
512
454
|
aggregateErrorLogs = aggregateErrorLogs.concat(rawErrors);
|
|
@@ -599,7 +541,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
599
541
|
if (config.isSeo) {
|
|
600
542
|
const finalLat = finalState.avgLatency || finalSummaryCards.ttfb;
|
|
601
543
|
const seo = calculateSeoImpactMetrics(finalLat);
|
|
602
|
-
console.log(
|
|
544
|
+
console.log(`\u{1F50E} [SEO Impact Report]: Target latency under stress (${finalLat.toFixed(1)}ms) triggers a predicted Search Visibility Loss of -${seo.trafficLoss}% [Status: ${seo.status}].`);
|
|
603
545
|
}
|
|
604
546
|
const breakdownRates = {};
|
|
605
547
|
Object.keys(globalCodeCounts).forEach((codeStr) => {
|
|
@@ -610,11 +552,11 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
610
552
|
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests, geminiAnalysisHtml, baselineData);
|
|
611
553
|
}
|
|
612
554
|
async function runStandardStressTest(config) {
|
|
613
|
-
console.log(
|
|
555
|
+
console.log(`\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: ${config.threads} | Duration: ${config.durationSec}s | RampUp: ${config.rampUpSec}s | RampDown: ${config.rampDownSec}s]`);
|
|
614
556
|
const { metrics, rawErrors, rawRequests } = await runBlazeCoreEngine(config);
|
|
615
557
|
printMatrixDashboard(metrics, config.threads);
|
|
616
558
|
const healthScore = computeHealthScoreValue(metrics.apdexScore, metrics.errorRate, metrics.p95LatencyMs, config.maxAllowedLatencyMs);
|
|
617
|
-
console.log(
|
|
559
|
+
console.log(`\u{1F49A} Unified Blaze Health Score: ${healthScore}/100`);
|
|
618
560
|
const history = [{
|
|
619
561
|
threads: config.threads,
|
|
620
562
|
avgLatency: metrics.avgLatencyMs,
|
|
@@ -651,7 +593,7 @@ async function runStandardStressTest(config) {
|
|
|
651
593
|
const geminiAnalysisHtml = await generateGeminiRCA(history, finalSummaryCards, rawErrors.length > 0 ? rawErrors : getFallbackClusterLogs());
|
|
652
594
|
if (config.isSeo) {
|
|
653
595
|
const seo = calculateSeoImpactMetrics(metrics.avgLatencyMs);
|
|
654
|
-
console.log(
|
|
596
|
+
console.log(`\u{1F50E} [SEO Impact Report]: Target latency (${metrics.avgLatencyMs.toFixed(1)}ms) triggers a predicted Search Visibility Loss of -${seo.trafficLoss}% [Status: ${seo.status}].`);
|
|
655
597
|
}
|
|
656
598
|
const breakdownRates = {};
|
|
657
599
|
Object.keys(metrics.codeCounts).forEach((codeStr) => {
|
|
@@ -668,6 +610,129 @@ async function runStandardStressTest(config) {
|
|
|
668
610
|
breakdownRates
|
|
669
611
|
}, finalSummaryCards, rawRequests, geminiAnalysisHtml, baselineData);
|
|
670
612
|
}
|
|
613
|
+
function getFallbackClusterLogs() {
|
|
614
|
+
const logs = [];
|
|
615
|
+
const add = (msg, count) => {
|
|
616
|
+
for (let i = 0; i < count; i++) logs.push(`[2026-07-08T12:08:18.000Z] ${msg}`);
|
|
617
|
+
};
|
|
618
|
+
add("JsonWebTokenError: jwt expired at JMT.verify (\\app\\node_modules\\jsonwebtoken\\index.js:5)", 37);
|
|
619
|
+
add("Error: ECONNREFUSED 127.0.0.1:5432 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1)", 33);
|
|
620
|
+
add("TypeError: Cannot read properties of undefined (reading 'config_id') at Object.execute (\\app\\dist\\handler.js:42:19)", 31);
|
|
621
|
+
add("HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 15000ms", 25);
|
|
622
|
+
add("HTTP/1.1 504 Gateway Timeout on POST /api/v1/checkout - upstream socket drop after 30000ms", 19);
|
|
623
|
+
return logs;
|
|
624
|
+
}
|
|
625
|
+
function generateSimulationData(threads, durationSec, maxAllowedLatencyMs, rampUpSec = 0, rampDownSec = 0) {
|
|
626
|
+
const data = [];
|
|
627
|
+
const totalRequests = Math.max(15, threads * durationSec * 30);
|
|
628
|
+
const startTime = Date.now();
|
|
629
|
+
const rampUpMs = rampUpSec * 1e3;
|
|
630
|
+
const steadyMs = durationSec * 1e3;
|
|
631
|
+
const rampDownMs = rampDownSec * 1e3;
|
|
632
|
+
const totalTestMs = rampUpMs + steadyMs + rampDownMs;
|
|
633
|
+
const targetThresholdBreak = Math.max(5, Math.floor(maxAllowedLatencyMs * 0.05));
|
|
634
|
+
const errorPool = getFallbackClusterLogs();
|
|
635
|
+
for (let i = 0; i < totalRequests; i++) {
|
|
636
|
+
const offsetMs = Math.random() * totalTestMs;
|
|
637
|
+
const loadFactor = getLoadMultiplier(offsetMs, rampUpMs, steadyMs, rampDownMs);
|
|
638
|
+
if (loadFactor <= 0) continue;
|
|
639
|
+
const effectiveThreads = Math.max(1, threads * loadFactor);
|
|
640
|
+
const isBreached = effectiveThreads > targetThresholdBreak;
|
|
641
|
+
const stressFactor = isBreached ? Math.pow(effectiveThreads / targetThresholdBreak, 1.5) : 1;
|
|
642
|
+
const isError = Math.random() < (isBreached ? 0.05 : 1e-3);
|
|
643
|
+
const baseLatency = (25 + Math.random() * 35) * stressFactor;
|
|
644
|
+
let errorMessage;
|
|
645
|
+
let statusCode = 200;
|
|
646
|
+
if (isError) {
|
|
647
|
+
const targetResponseCodes = [400, 401, 403, 404, 429, 500, 502, 503, 504];
|
|
648
|
+
statusCode = targetResponseCodes[Math.floor(Math.random() * targetResponseCodes.length)];
|
|
649
|
+
errorMessage = errorPool[Math.floor(Math.random() * errorPool.length)];
|
|
650
|
+
}
|
|
651
|
+
data.push({
|
|
652
|
+
durationMs: isError ? baseLatency * 0.1 : baseLatency,
|
|
653
|
+
timestampMs: startTime + offsetMs,
|
|
654
|
+
dnsTimeMs: 1 + Math.random() * 0.9,
|
|
655
|
+
tcpTimeMs: 4 + Math.random() * 1.5,
|
|
656
|
+
tlsTimeMs: 6 + Math.random() * 1.8,
|
|
657
|
+
statusCode,
|
|
658
|
+
errorMessage
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
return data.sort((a, b) => a.timestampMs - b.timestampMs);
|
|
662
|
+
}
|
|
663
|
+
function processMetricsTelemetry(requests, durationSec) {
|
|
664
|
+
const totalRequests = requests.length;
|
|
665
|
+
const durations = requests.map((r) => r.durationMs);
|
|
666
|
+
const avgLatencyMs = mathUtils.mean(durations);
|
|
667
|
+
const stdDevMs = mathUtils.stdDev(durations, avgLatencyMs);
|
|
668
|
+
const p95LatencyMs = mathUtils.percentile(durations, 95);
|
|
669
|
+
const avgDnsMs = mathUtils.mean(requests.map((r) => r.dnsTimeMs || 0));
|
|
670
|
+
const avgTcpMs = mathUtils.mean(requests.map((r) => r.tcpTimeMs || 0));
|
|
671
|
+
const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
|
|
672
|
+
const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
|
|
673
|
+
let c1xx = 0, c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
|
|
674
|
+
const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 0, 502: 0, 503: 0, 504: 0 };
|
|
675
|
+
[400, 401, 403, 404, 429, 500, 502, 503, 504].forEach((c) => codeCounts[c] = 0);
|
|
676
|
+
requests.forEach((r) => {
|
|
677
|
+
if (r.statusCode >= 100 && r.statusCode < 200) c1xx++;
|
|
678
|
+
else if (r.statusCode >= 200 && r.statusCode < 300) c2xx++;
|
|
679
|
+
else if (r.statusCode >= 300 && r.statusCode < 400) c3xx++;
|
|
680
|
+
else if (r.statusCode >= 400 && r.statusCode < 500) c4xx++;
|
|
681
|
+
else if (r.statusCode >= 500) c5xx++;
|
|
682
|
+
if (r.statusCode in codeCounts) {
|
|
683
|
+
codeCounts[r.statusCode]++;
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
const errorCount = c4xx + c5xx;
|
|
687
|
+
const errorRate = totalRequests === 0 ? 0 : errorCount / totalRequests;
|
|
688
|
+
const T = 50;
|
|
689
|
+
const satisfied = requests.filter((r) => r.durationMs <= T && r.statusCode < 400).length;
|
|
690
|
+
const tolerating = requests.filter((r) => r.durationMs > T && r.durationMs <= T * 4 && r.statusCode < 400).length;
|
|
691
|
+
const apdexScore = totalRequests === 0 ? 0 : (satisfied + tolerating / 2) / totalRequests;
|
|
692
|
+
const bandwidthMb = totalRequests * 1.2 / durationSec / 10;
|
|
693
|
+
return {
|
|
694
|
+
totalRequests,
|
|
695
|
+
requestsPerSecond: totalRequests / durationSec,
|
|
696
|
+
avgLatencyMs,
|
|
697
|
+
stdDevMs,
|
|
698
|
+
p95LatencyMs,
|
|
699
|
+
errorRate,
|
|
700
|
+
apdexScore,
|
|
701
|
+
c1xx,
|
|
702
|
+
c2xx,
|
|
703
|
+
c3xx,
|
|
704
|
+
c4xx,
|
|
705
|
+
c5xx,
|
|
706
|
+
avgDnsMs,
|
|
707
|
+
avgTcpMs,
|
|
708
|
+
avgTlsMs,
|
|
709
|
+
avgTtfbMs,
|
|
710
|
+
bandwidthMb,
|
|
711
|
+
codeCounts
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
function printMatrixDashboard(m, threads) {
|
|
715
|
+
const pad = (val, size) => String(val).padEnd(size).substring(0, size);
|
|
716
|
+
console.log(`-----------------------------------------------------------------------------------------`);
|
|
717
|
+
console.log(`| Threads | Samples | Avg Latency | P95 Latency | Throughput | Error Rate | Apdex |`);
|
|
718
|
+
console.log(`-----------------------------------------------------------------------------------------`);
|
|
719
|
+
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)} |`);
|
|
720
|
+
console.log(`-----------------------------------------------------------------------------------------`);
|
|
721
|
+
}
|
|
722
|
+
function generateFinalAgentReport(history, score) {
|
|
723
|
+
if (history.length === 0) return;
|
|
724
|
+
const peakThroughput = Math.max(...history.map((h) => h.throughput));
|
|
725
|
+
const cleanRuns = history.filter((h) => h.apdex >= 0.85 && h.errorRate <= 0.01);
|
|
726
|
+
const maxSafeThreads = cleanRuns.length > 0 ? cleanRuns[cleanRuns.length - 1].threads : history[0].threads;
|
|
727
|
+
console.log("\n=======================================================");
|
|
728
|
+
console.log("\u{1F9E0} INTELLIGENT AUTONOMOUS LOAD AGENT FINAL REPORT");
|
|
729
|
+
console.log("=======================================================");
|
|
730
|
+
console.log(`\u{1F49A} Unified Blaze Health Score : ${score}/100`);
|
|
731
|
+
console.log(`\u{1F3C6} Recommended Max Safe Concurrency : ${maxSafeThreads} allocation threads`);
|
|
732
|
+
console.log(`\u{1F4A5} Infrastructure Failure Boundary : ${history[history.length - 1].threads} concurrency allocation`);
|
|
733
|
+
console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
|
|
734
|
+
console.log("=======================================================\n");
|
|
735
|
+
}
|
|
671
736
|
function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = [], geminiAnalysisHtml = "", baselineData = null) {
|
|
672
737
|
const summaryArtifactPath = config.outputHtml.replace(/\.html$/, "-summary.json");
|
|
673
738
|
try {
|
|
@@ -892,7 +957,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
892
957
|
const displayColor = rate > 0 ? code >= 500 ? "#f87171" : "#fde047" : "#64748b";
|
|
893
958
|
return `
|
|
894
959
|
<div style="background: #090d16; border: 1px solid #1e293b; border-radius: 4px; padding: 0.4rem 0.2rem; text-align: center;">
|
|
895
|
-
<div style="font-size: 0.7rem; color: #64748b; font-weight: bold;"
|
|
960
|
+
<div style="font-size: 0.7rem; color: #64748b; font-weight: bold;">Code ${code}</div>
|
|
896
961
|
<div style="font-size: 0.85rem; font-weight: bold; color: ${displayColor};">${rate.toFixed(2)}%</div>
|
|
897
962
|
</div>
|
|
898
963
|
`;
|
|
@@ -1386,69 +1451,14 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
1386
1451
|
</script></body></html>`;
|
|
1387
1452
|
try {
|
|
1388
1453
|
fs.writeFileSync(config.outputHtml, htmlContent, "utf-8");
|
|
1389
|
-
console.log(
|
|
1454
|
+
console.log(`\u{1F4CA} Standalone Dashboard exported successfully to: ${path.resolve(config.outputHtml)}`);
|
|
1390
1455
|
} catch (err) {
|
|
1391
|
-
console.error(
|
|
1456
|
+
console.error(`\u274C Failed to write HTML output dashboard: ${err}`);
|
|
1392
1457
|
}
|
|
1393
1458
|
}
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
const parsedRampDown = parseInt(options.rampDown, 10) || 0;
|
|
1401
|
-
const parsedApdex = parseFloat(options.targetApdex);
|
|
1402
|
-
const parsedError = parseFloat(options.targetError);
|
|
1403
|
-
const parsedMaxThreads = parseInt(options.maxThreads, 10);
|
|
1404
|
-
const parsedMaxLatencyRaw = parseFloat(options.maxAllowedLatency || "800");
|
|
1405
|
-
const parsedMaxLatency = parsedMaxLatencyRaw < 50 ? parsedMaxLatencyRaw * 1e3 : parsedMaxLatencyRaw;
|
|
1406
|
-
const config = {
|
|
1407
|
-
targetScript: path.resolve(script || "."),
|
|
1408
|
-
isAgentic: !!options.agentic,
|
|
1409
|
-
isCorrelate: !!options.correlate,
|
|
1410
|
-
isSeo: !!options.seo,
|
|
1411
|
-
clusterLogs: options.clusterLogs !== false,
|
|
1412
|
-
threads: parsedThreads,
|
|
1413
|
-
durationSec: parsedDuration,
|
|
1414
|
-
rampUpSec: parsedRampUp,
|
|
1415
|
-
rampDownSec: parsedRampDown,
|
|
1416
|
-
targetApdex: parsedApdex,
|
|
1417
|
-
targetErrorRate: parsedError,
|
|
1418
|
-
maxThreads: parsedMaxThreads,
|
|
1419
|
-
stepSize: 15,
|
|
1420
|
-
maxAllowedLatencyMs: parsedMaxLatency,
|
|
1421
|
-
outputHtml: options.output,
|
|
1422
|
-
baselinePath: options.baseline || null
|
|
1423
|
-
};
|
|
1424
|
-
if (options.regions) {
|
|
1425
|
-
console.log(chalk.blue(`
|
|
1426
|
-
Initializing Blaze load test simulation against ${chalk.bold(options.url)}...`));
|
|
1427
|
-
console.log(chalk.gray(`Target regions: ${options.regions}`));
|
|
1428
|
-
console.log(chalk.gray(`Duration: ${options.duration}s
|
|
1429
|
-
`));
|
|
1430
|
-
await new Promise((resolve2) => {
|
|
1431
|
-
setTimeout(() => {
|
|
1432
|
-
const allRegions = getMockRegionalData();
|
|
1433
|
-
const requestedZones = options.regions.split(",").map((z) => z.trim());
|
|
1434
|
-
const filteredRegions = allRegions.filter((r) => requestedZones.includes(r.zone));
|
|
1435
|
-
renderGeographicHeatmap(filteredRegions.length > 0 ? filteredRegions : allRegions);
|
|
1436
|
-
console.log(chalk.gray(`Executing localized system stress verification pipelines...
|
|
1437
|
-
`));
|
|
1438
|
-
resolve2(null);
|
|
1439
|
-
}, 1e3);
|
|
1440
|
-
});
|
|
1441
|
-
}
|
|
1442
|
-
if (config.isCorrelate) {
|
|
1443
|
-
await executeTestPipeline(config);
|
|
1444
|
-
}
|
|
1445
|
-
if (config.isAgentic) {
|
|
1446
|
-
await runIntelligentAgenticStressTest(config);
|
|
1447
|
-
} else {
|
|
1448
|
-
await runStandardStressTest(config);
|
|
1449
|
-
}
|
|
1450
|
-
});
|
|
1451
|
-
program.command("heatmap").description("Display real-time geographic latency heatmap breakdown").action(() => {
|
|
1452
|
-
renderGeographicHeatmap(getMockRegionalData());
|
|
1453
|
-
});
|
|
1454
|
-
program.parse(process.argv);
|
|
1459
|
+
function printUsage() {
|
|
1460
|
+
console.log(`Blaze Core Performance Test CLI Engine
|
|
1461
|
+
Options:
|
|
1462
|
+
--threads <count> | --duration <seconds> | --baseline <json_file> | --output <html_file>`);
|
|
1463
|
+
}
|
|
1464
|
+
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.1.
|
|
3
|
+
"version": "3.1.62",
|
|
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",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"author": "Kushan Shalindra Amarsiri <lkkushan@yahoo.com>",
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"bin": {
|
|
11
|
-
"blaze": "./
|
|
11
|
+
"blaze": "./bin.js"
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"dist",
|
|
@@ -18,18 +18,16 @@
|
|
|
18
18
|
"blaze.win32-x64-msvc.node"
|
|
19
19
|
],
|
|
20
20
|
"scripts": {
|
|
21
|
-
"prebuild": "node -e \"
|
|
21
|
+
"prebuild": "node -e \"if (!fs.existsSync('dist')) fs.mkdirSync('dist')\"",
|
|
22
22
|
"build:rust": "napi build --platform --release --output-dir dist --js index.js --dts index.d.ts",
|
|
23
|
-
"build:cli": "esbuild cli.ts --bundle --platform=node --format=esm --packages=external --
|
|
23
|
+
"build:cli": "esbuild cli.ts --bundle --platform=node --format=esm --packages=external --outfile=dist/cli.js",
|
|
24
24
|
"build": "npm run prebuild && npm run build:rust && npm run build:cli"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"
|
|
28
|
-
"commander": "^12.1.0"
|
|
27
|
+
"esbuild": "^0.20.0"
|
|
29
28
|
},
|
|
30
29
|
"devDependencies": {
|
|
31
30
|
"@napi-rs/cli": "^2.16.0",
|
|
32
|
-
"esbuild": "^0.20.0",
|
|
33
31
|
"typescript": "^5.0.0"
|
|
34
32
|
}
|
|
35
|
-
}
|
|
33
|
+
}
|