blaze-performance-tester 3.1.17 → 3.1.19
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 +100 -70
- package/dist/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -139,6 +139,7 @@ function parseArguments(args) {
|
|
|
139
139
|
const targetScript = path.resolve(args[0] || ".");
|
|
140
140
|
const isAgentic = args.includes("--agentic");
|
|
141
141
|
const isCorrelate = args.includes("--correlate");
|
|
142
|
+
const isSeo = args.includes("--seo");
|
|
142
143
|
const clusterLogs = !args.includes("--no-cluster-logs");
|
|
143
144
|
let threads = 10;
|
|
144
145
|
let durationSec = 10;
|
|
@@ -181,6 +182,7 @@ function parseArguments(args) {
|
|
|
181
182
|
targetScript,
|
|
182
183
|
isAgentic,
|
|
183
184
|
isCorrelate,
|
|
185
|
+
isSeo,
|
|
184
186
|
clusterLogs,
|
|
185
187
|
threads,
|
|
186
188
|
durationSec,
|
|
@@ -213,6 +215,31 @@ async function runBlazeCoreEngine(config) {
|
|
|
213
215
|
}, 1e3);
|
|
214
216
|
});
|
|
215
217
|
}
|
|
218
|
+
function calculateSeoImpactMetrics(avgLatencyMs) {
|
|
219
|
+
const baseLineOptimalMs = 200;
|
|
220
|
+
if (avgLatencyMs <= baseLineOptimalMs) {
|
|
221
|
+
return { trafficLoss: 0, status: "Excellent", crawlPenalty: "None", color: "#10b981" };
|
|
222
|
+
}
|
|
223
|
+
const delayFactor = avgLatencyMs - baseLineOptimalMs;
|
|
224
|
+
const trafficLoss = Math.min(94, Math.floor(delayFactor / 1200 * 100));
|
|
225
|
+
let status = "Healthy";
|
|
226
|
+
let crawlPenalty = "Minimal impact on indexing rates.";
|
|
227
|
+
let color = "#10b981";
|
|
228
|
+
if (trafficLoss >= 50) {
|
|
229
|
+
status = "Critical Exposure";
|
|
230
|
+
crawlPenalty = "Severe penalty. Googlebot will heavily restrict crawl budgets due to timeout risks.";
|
|
231
|
+
color = "#ef4444";
|
|
232
|
+
} else if (trafficLoss >= 20) {
|
|
233
|
+
status = "Moderate Danger";
|
|
234
|
+
crawlPenalty = "Delayed indexation. Core Web Vital thresholds are officially breached.";
|
|
235
|
+
color = "#f97316";
|
|
236
|
+
} else if (trafficLoss > 5) {
|
|
237
|
+
status = "Minor Impact";
|
|
238
|
+
crawlPenalty = "Slightly elevated bounce trends could impact highly volatile rankings.";
|
|
239
|
+
color = "#eab308";
|
|
240
|
+
}
|
|
241
|
+
return { trafficLoss, status, crawlPenalty, color };
|
|
242
|
+
}
|
|
216
243
|
async function runIntelligentAgenticStressTest(config) {
|
|
217
244
|
console.log("\u{1F680} Initializing Intelligent Autonomous Load Agent...");
|
|
218
245
|
const history = [];
|
|
@@ -293,8 +320,6 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
293
320
|
const analyzer = new LogAnalyzer();
|
|
294
321
|
semanticReport = analyzer.process(aggregateErrorLogs);
|
|
295
322
|
}
|
|
296
|
-
const totalTestSeconds = history.length * config.durationSec;
|
|
297
|
-
const vuRampUpVelocity = history.length > 1 && totalTestSeconds > 0 ? (history[history.length - 1].threads - history[0].threads) / totalTestSeconds : config.threads / config.durationSec;
|
|
298
323
|
const finalSummaryCards = {
|
|
299
324
|
apdex: history[history.length - 1]?.apdex || 0,
|
|
300
325
|
throughput: history[history.length - 1]?.throughput || 0,
|
|
@@ -304,10 +329,14 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
304
329
|
tcp: mathUtils.mean(globalMetricsAccumulator.tcp),
|
|
305
330
|
tls: mathUtils.mean(globalMetricsAccumulator.tls),
|
|
306
331
|
stdDev: mathUtils.stdDev(globalMetricsAccumulator.latencies, mathUtils.mean(globalMetricsAccumulator.latencies)),
|
|
307
|
-
saturationKneePoint: saturationKneePoint || history[history.length - 1]?.threads || 50
|
|
308
|
-
vuRampUpVelocity
|
|
332
|
+
saturationKneePoint: saturationKneePoint || history[history.length - 1]?.threads || 50
|
|
309
333
|
};
|
|
310
334
|
generateFinalAgentReport(history);
|
|
335
|
+
if (config.isSeo) {
|
|
336
|
+
const finalLat = history[history.length - 1]?.avgLatency || finalSummaryCards.ttfb;
|
|
337
|
+
const seo = calculateSeoImpactMetrics(finalLat);
|
|
338
|
+
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}].`);
|
|
339
|
+
}
|
|
311
340
|
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx }, finalSummaryCards, lastRawRequests);
|
|
312
341
|
}
|
|
313
342
|
async function runStandardStressTest(config) {
|
|
@@ -340,11 +369,14 @@ async function runStandardStressTest(config) {
|
|
|
340
369
|
tcp: metrics.avgTcpMs,
|
|
341
370
|
tls: metrics.avgTlsMs,
|
|
342
371
|
stdDev: metrics.stdDevMs,
|
|
343
|
-
saturationKneePoint: config.threads
|
|
344
|
-
vuRampUpVelocity: config.threads / config.durationSec
|
|
372
|
+
saturationKneePoint: config.threads
|
|
345
373
|
};
|
|
346
374
|
const isPassed = metrics.apdexScore >= config.targetApdex && metrics.errorRate <= config.targetErrorRate;
|
|
347
375
|
const verdictReason = isPassed ? "Static single-wave baseline checks concluded successfully without triggering health boundaries." : "Static verification loop completed with values exceeding defined quality thresholds.";
|
|
376
|
+
if (config.isSeo) {
|
|
377
|
+
const seo = calculateSeoImpactMetrics(metrics.avgLatencyMs);
|
|
378
|
+
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}].`);
|
|
379
|
+
}
|
|
348
380
|
exportHtmlDashboard(history, config, verdictReason, semanticReport, {
|
|
349
381
|
total1xx: metrics.c1xx,
|
|
350
382
|
total2xx: metrics.c2xx,
|
|
@@ -484,14 +516,23 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
484
516
|
logClustersHtml = `
|
|
485
517
|
<div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
|
|
486
518
|
<h3 style="border-bottom: none; padding-bottom: 0rem; margin-bottom: 0.25rem; display: flex; align-items: center; gap: 0.5rem; color: #ffffff; font-size: 1.2rem;">
|
|
487
|
-
\u{1F9E0}
|
|
519
|
+
\u{1F9E0} Semantic Log Clustering & Error Classification
|
|
488
520
|
</h3>
|
|
489
521
|
<div style="color: #94a3b8; font-size: 0.9rem; margin-bottom: 1.5rem;">
|
|
490
|
-
Captured <strong style="color: #f8fafc;">${totalLogCount}</strong> raw failures grouped into <strong style="color: #f8fafc;">${uniquePatternsCount}</strong> unique structural patterns.
|
|
522
|
+
Captured <strong style="color: #f8fafc;">${totalLogCount}</strong> raw failures grouped into <strong style="color: #f8fafc;">${uniquePatternsCount}</strong> unique structural patterns.
|
|
491
523
|
</div>
|
|
492
524
|
|
|
493
|
-
<
|
|
494
|
-
|
|
525
|
+
<table style="width: 100%; border-collapse: collapse;">
|
|
526
|
+
<thead>
|
|
527
|
+
<tr style="border-bottom: 1px solid #1e293b;">
|
|
528
|
+
<th style="width: 8%; padding: 0.75rem; text-align: left; color: #64748b; font-size: 0.85rem; font-weight: bold; text-transform: none;">Count</th>
|
|
529
|
+
<th style="width: 22%; padding: 0.75rem; text-align: left; color: #64748b; font-size: 0.85rem; font-weight: bold; text-transform: none;">Classification Category</th>
|
|
530
|
+
<th style="width: 10%; padding: 0.75rem; text-align: left; color: #64748b; font-size: 0.85rem; font-weight: bold; text-transform: none;">Severity</th>
|
|
531
|
+
<th style="width: 60%; padding: 0.75rem; text-align: left; color: #64748b; font-size: 0.85rem; font-weight: bold; text-transform: none;">Structural Abstract Blueprint / Dynamic Log Fingerprint</th>
|
|
532
|
+
</tr>
|
|
533
|
+
</thead>
|
|
534
|
+
<tbody>
|
|
535
|
+
${semanticReport.clusters.map((c) => {
|
|
495
536
|
let catColor = "#fb923c";
|
|
496
537
|
if (c.category === "Authentication_Error") catColor = "#c084fc";
|
|
497
538
|
if (c.category === "Product_Error") catColor = "#f87171";
|
|
@@ -499,52 +540,54 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
499
540
|
let sevBg = c.severity === "CRITICAL" ? "#dc2626" : "#ea580c";
|
|
500
541
|
const rawTemplate = c.template || "";
|
|
501
542
|
const cleanedTemplate = rawTemplate.replace(/\[\d{4}-\d{2}-\d{2}.*?\]\s*/, "");
|
|
502
|
-
const clarityBonus = c.severity === "CRITICAL" ? 15 : 8;
|
|
503
|
-
const freqScore = Math.min(25, c.count * 0.5);
|
|
504
|
-
const confidenceScore = Math.min(99, Math.round(65 + freqScore + clarityBonus));
|
|
505
|
-
let confColor = "#10b981";
|
|
506
|
-
if (confidenceScore < 80) confColor = "#f59e0b";
|
|
507
|
-
if (confidenceScore < 70) confColor = "#ef4444";
|
|
508
|
-
let fixTitle = "Infrastructure Pool & Tuning Fix";
|
|
509
|
-
let fixCode = "const pool = new Pool({ max: 50, idleTimeoutMillis: 30000 });";
|
|
510
|
-
let explanation = "High concurrency is causing socket/connection starvation. Increase connection limits or enable pooling keep-alives.";
|
|
511
|
-
if (c.category === "Authentication_Error") {
|
|
512
|
-
fixTitle = "Auth Token / JWT Strategy";
|
|
513
|
-
fixCode = "// Implement token caching and silent rotation\napp.use(authMiddleware({ cacheTtl: 300, allowGracePeriod: 60 }));";
|
|
514
|
-
explanation = "Frequent token verification failures under load. Extend signature verification cache or decouple auth validation check.";
|
|
515
|
-
} else if (c.category === "Product_Error") {
|
|
516
|
-
fixTitle = "Application Null-Safety / Guard Fix";
|
|
517
|
-
fixCode = "const configId = payload?.config_id ?? defaultConfigurationId;\nif (!configId) throw new ValidationError('Missing config_id');";
|
|
518
|
-
explanation = "Runtime reference error for undefined payload field under race condition spikes. Add optional chaining and input contracts.";
|
|
519
|
-
}
|
|
520
|
-
const snippetId = `snippet-${idx}`;
|
|
521
543
|
return `
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
<
|
|
525
|
-
|
|
526
|
-
<span style="
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
<div style="color: #64748b; font-size: 0.75rem; text-transform: uppercase; font-weight: bold; margin-bottom: 0.25rem;">Detected Log Fingerprint</div>
|
|
535
|
-
<code style="color: #cbd5e1; font-family: monospace; font-size: 0.85rem; word-break: break-all;">${cleanedTemplate}</code>
|
|
536
|
-
</div>
|
|
537
|
-
<div style="margin-bottom: 1.25rem;">
|
|
538
|
-
<div style="color: #38bdf8; font-size: 0.9rem; font-weight: bold; margin-bottom: 0.25rem;">\u{1F4A1} Playbook Strategy: ${fixTitle}</div>
|
|
539
|
-
<div style="color: #94a3b8; font-size: 0.85rem; line-height: 1.4; margin-bottom: 0.75rem;">${explanation}</div>
|
|
540
|
-
<div style="position: relative; background: #0b111e; border: 1px solid #1e293b; border-radius: 4px; padding: 0.75rem;">
|
|
541
|
-
<button onclick="copyToClipboard('${snippetId}')" style="position: absolute; top: 0.5rem; right: 0.5rem; background: #1e293b; color: #38bdf8; border: none; padding: 0.2rem 0.5rem; border-radius: 3px; font-size: 0.7rem; cursor: pointer;">Copy Fix</button>
|
|
542
|
-
<pre id="${snippetId}" style="margin: 0; color: #4ade80; font-family: monospace; font-size: 0.85rem; white-space: pre-wrap;">${fixCode}</pre>
|
|
544
|
+
<tr style="border-bottom: 1px solid #1e293b; vertical-align: top;">
|
|
545
|
+
<td style="padding: 1.25rem 0.75rem; font-size: 1.2rem; font-weight: bold; color: #f8fafc;">${c.count}</td>
|
|
546
|
+
<td style="padding: 1.25rem 0.75rem; color: ${catColor}; font-weight: 600; font-size: 0.95rem;">${c.category}</td>
|
|
547
|
+
<td style="padding: 1.25rem 0.75rem;">
|
|
548
|
+
<span style="background: ${sevBg}; color: #ffffff; padding: 0.2rem 0.5rem; border-radius: 4px; font-size: 0.7rem; font-weight: bold; letter-spacing: 0.05em;">${c.severity}</span>
|
|
549
|
+
</td>
|
|
550
|
+
<td style="padding: 1.25rem 0.75rem;">
|
|
551
|
+
<div style="background: #090d16; border-radius: 4px; padding: 0.6rem 0.8rem; border-left: 3px solid #1e293b; margin-bottom: 0.5rem;">
|
|
552
|
+
<code style="color: #cbd5e1; font-family: monospace; font-size: 0.9rem; white-space: pre-wrap; word-break: break-all;">${cleanedTemplate}</code>
|
|
553
|
+
</div>
|
|
554
|
+
<div style="color: #64748b; font-size: 0.8rem; font-family: monospace; padding-left: 0.2rem; line-height: 1.4;">
|
|
555
|
+
<span style="color: #475569;">Real Example Trace:</span> ${rawTemplate}
|
|
543
556
|
</div>
|
|
544
|
-
</
|
|
545
|
-
</
|
|
546
|
-
</details>`;
|
|
557
|
+
</td>
|
|
558
|
+
</tr>`;
|
|
547
559
|
}).join("")}
|
|
560
|
+
</tbody>
|
|
561
|
+
</table>
|
|
562
|
+
</div>`;
|
|
563
|
+
}
|
|
564
|
+
let seoImpactSectionHtml = "";
|
|
565
|
+
if (config.isSeo) {
|
|
566
|
+
const finalLatency = history[history.length - 1]?.avgLatency || cards.ttfb;
|
|
567
|
+
const seoMetrics = calculateSeoImpactMetrics(finalLatency);
|
|
568
|
+
seoImpactSectionHtml = `
|
|
569
|
+
<div class="card" style="margin-top: 2rem; background: #111a2e; border: 1px solid #1e3a8a;">
|
|
570
|
+
<h3 style="color: #f43f5e; display: flex; align-items: center; gap: 0.6rem; font-size: 1.2rem; border-bottom: 1px solid #1e293b; padding-bottom: 0.5rem;">
|
|
571
|
+
\u{1F50E} SEO Rank Impact & Visibility Loss Predictor
|
|
572
|
+
</h3>
|
|
573
|
+
<p style="color: #94a3b8; font-size: 0.9rem; margin-bottom: 1.5rem;">
|
|
574
|
+
Translates response time infrastructure load stress into Core Web Vitals ranking drops and organic search volume degradation metrics.
|
|
575
|
+
</p>
|
|
576
|
+
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem;">
|
|
577
|
+
<div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b; text-align: center;">
|
|
578
|
+
<div class="card-title" style="color: #94a3b8;">Est. Organic Traffic Loss</div>
|
|
579
|
+
<div style="font-size: 2rem; font-weight: bold; color: ${seoMetrics.color};">-${seoMetrics.trafficLoss}%</div>
|
|
580
|
+
<div style="font-size: 0.8rem; color: #64748b; margin-top: 0.25rem;">compared to 200ms sweet-spot</div>
|
|
581
|
+
</div>
|
|
582
|
+
<div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
583
|
+
<div class="card-title">Search Visibility Status</div>
|
|
584
|
+
<div style="font-size: 1.25rem; font-weight: bold; color: ${seoMetrics.color}; margin-top: 0.4rem;">${seoMetrics.status}</div>
|
|
585
|
+
<div style="font-size: 0.8rem; color: #94a3b8; margin-top: 0.25rem;">Target Latency: ${finalLatency.toFixed(1)}ms</div>
|
|
586
|
+
</div>
|
|
587
|
+
<div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
588
|
+
<div class="card-title">Googlebot Crawl Budget Impact</div>
|
|
589
|
+
<div style="font-size: 0.85rem; color: #e2e8f0; line-height: 1.5; margin-top: 0.4rem;">${seoMetrics.crawlPenalty}</div>
|
|
590
|
+
</div>
|
|
548
591
|
</div>
|
|
549
592
|
</div>`;
|
|
550
593
|
}
|
|
@@ -577,7 +620,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
577
620
|
<h3 style="color: #38bdf8; display: flex; align-items: center; gap: 0.5rem; font-size: 1.2rem;">
|
|
578
621
|
\u2601\uFE0F Infrastructure Right-Sizing & Cloud Cost Projections
|
|
579
622
|
</h3>
|
|
580
|
-
<div style="
|
|
623
|
+
<div style="grid-template-columns: repeat(3, 1fr); display: grid; gap: 1rem; margin-top: 1rem;">
|
|
581
624
|
<div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
582
625
|
<div class="card-title">Est. Monthly Cloud Cost</div>
|
|
583
626
|
<div class="card-value green">$${estimatedMonthlyCost} <span class="unit">/mo</span></div>
|
|
@@ -603,7 +646,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
603
646
|
h1 { color: #38bdf8; margin: 0; font-size: 2rem; }
|
|
604
647
|
.meta { color: #94a3b8; font-size: 0.9rem; margin-top: 0.5rem; }
|
|
605
648
|
|
|
606
|
-
.cards-wrapper { display: grid; grid-template-columns: repeat(
|
|
649
|
+
.cards-wrapper { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 1.5rem; }
|
|
607
650
|
.metric-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 6px; padding: 1.25rem; position: relative; }
|
|
608
651
|
.card-title { font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.5rem; }
|
|
609
652
|
.card-value { font-size: 1.6rem; font-weight: 700; color: #ffffff; }
|
|
@@ -611,7 +654,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
611
654
|
.card-value.green { color: #10b981; }
|
|
612
655
|
.card-value.orange { color: #f97316; }
|
|
613
656
|
.card-value.purple { color: #a855f7; }
|
|
614
|
-
.card-value.cyan { color: #38bdf8; }
|
|
615
657
|
.card-subtext { font-size: 0.8rem; color: #10b981; font-weight: 500; margin-left: 0.4rem; display: inline-block; }
|
|
616
658
|
|
|
617
659
|
.top-layout-grid { display: grid; grid-template-columns: 1fr 400px; gap: 1.5rem; margin-bottom: 2rem; }
|
|
@@ -670,10 +712,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
670
712
|
<div class="card-title">Avg Time To First Byte</div>
|
|
671
713
|
<div class="card-value">${cards.ttfb.toFixed(1)}<span class="unit">ms</span></div>
|
|
672
714
|
</div>
|
|
673
|
-
<div class="metric-card">
|
|
674
|
-
<div class="card-title">VU Ramp-up Velocity</div>
|
|
675
|
-
<div class="card-value cyan">${cards.vuRampUpVelocity.toFixed(1)}<span class="unit">VUs/s</span></div>
|
|
676
|
-
</div>
|
|
677
715
|
<div class="metric-card">
|
|
678
716
|
<div class="card-title">DNS Lookup</div>
|
|
679
717
|
<div class="card-value">${cards.dns.toFixed(2)}<span class="unit">ms</span></div>
|
|
@@ -782,21 +820,13 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
782
820
|
</tbody>
|
|
783
821
|
</table>
|
|
784
822
|
</div>
|
|
823
|
+
${seoImpactSectionHtml}
|
|
785
824
|
${liveAdjusterHtml}
|
|
786
825
|
${rightSizingHtml}
|
|
787
826
|
${logClustersHtml}
|
|
788
827
|
</div>
|
|
789
828
|
|
|
790
829
|
<script>
|
|
791
|
-
function copyToClipboard(containerId) {
|
|
792
|
-
const text = document.getElementById(containerId).innerText;
|
|
793
|
-
navigator.clipboard.writeText(text).then(() => {
|
|
794
|
-
alert('Copied remediation snippet to clipboard!');
|
|
795
|
-
}).catch(err => {
|
|
796
|
-
console.error('Failed to copy text: ', err);
|
|
797
|
-
});
|
|
798
|
-
}
|
|
799
|
-
|
|
800
830
|
const labels = ${JSON.stringify(labels)};
|
|
801
831
|
const baseThroughput = ${cards.throughput};
|
|
802
832
|
const baseLatency = ${cards.ttfb};
|
|
@@ -947,6 +977,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
947
977
|
function printUsage() {
|
|
948
978
|
console.log(`Blaze Core Performance Test CLI Engine
|
|
949
979
|
Options:
|
|
950
|
-
--threads <count> | --duration <seconds> | --agentic | --cluster-logs | --correlate`);
|
|
980
|
+
--threads <count> | --duration <seconds> | --agentic | --cluster-logs | --correlate | --seo`);
|
|
951
981
|
}
|
|
952
982
|
main().catch(console.error);
|
|
Binary file
|