blaze-performance-tester 3.1.34 → 3.1.36
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 +65 -33
- package/dist/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -87,6 +87,54 @@ var mathUtils = {
|
|
|
87
87
|
return sorted[Math.max(0, index)];
|
|
88
88
|
}
|
|
89
89
|
};
|
|
90
|
+
async function generateGeminiRCA(history, finalSummary, errorLogs) {
|
|
91
|
+
const apiKey = process.env.GEMINI_API_KEY;
|
|
92
|
+
if (!apiKey) {
|
|
93
|
+
return `<span style="color: #ef4444;">\u26A0\uFE0F Gemini API Key missing. Export GEMINI_API_KEY to enable automated 2.5 Flash RCA analysis.</span>`;
|
|
94
|
+
}
|
|
95
|
+
console.log("\u{1F9E0} Querying Gemini 2.5 Flash for Advanced Root Cause Analysis...");
|
|
96
|
+
const formattedHistory = history.map(
|
|
97
|
+
(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)}`
|
|
98
|
+
).join("\n");
|
|
99
|
+
const uniqueLogs = Array.from(new Set(errorLogs)).slice(0, 10).join("\n");
|
|
100
|
+
const prompt = `
|
|
101
|
+
You are an expert Performance & Systems Reliability Engineer. Analyze the following load test execution telemetry and logs:
|
|
102
|
+
|
|
103
|
+
[LOAD SUMMARY METERICS]
|
|
104
|
+
- Unified Blaze Health Score: ${finalSummary.healthScore}/100
|
|
105
|
+
- Saturation Knee Point: ${finalSummary.saturationKneePoint} VUs
|
|
106
|
+
- Peak Stability Variance (Std Dev): ${finalSummary.stdDev.toFixed(2)}ms
|
|
107
|
+
- Network Bandwidth: ${finalSummary.bandwidth.toFixed(2)} MB/s
|
|
108
|
+
|
|
109
|
+
[EXECUTION STEP HISTORY]
|
|
110
|
+
${formattedHistory}
|
|
111
|
+
|
|
112
|
+
[UNIQUE LOG SAMPLES EXPLORATION]
|
|
113
|
+
${uniqueLogs || "No unique structural exceptions encountered."}
|
|
114
|
+
|
|
115
|
+
Provide a punchy, highly technical 3-paragraph Root Cause Analysis (RCA) report.
|
|
116
|
+
Paragraph 1: Diagnose the exact bottleneck point (CPU saturation, socket pool exhaustion, database lock contention, etc.) indicated by how latency changes with concurrency.
|
|
117
|
+
Paragraph 2: Correlate unique error patterns directly to performance drops.
|
|
118
|
+
Paragraph 3: Give concrete, actionable infrastructure or architectural sizing recommendations. Do not use markdown headers inside your response, use standard HTML bold text if needed, and wrap lines cleanly.
|
|
119
|
+
`;
|
|
120
|
+
try {
|
|
121
|
+
const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=${apiKey}`, {
|
|
122
|
+
method: "POST",
|
|
123
|
+
headers: { "Content-Type": "application/json" },
|
|
124
|
+
body: JSON.stringify({
|
|
125
|
+
contents: [{ parts: [{ text: prompt }] }],
|
|
126
|
+
generationConfig: { temperature: 0.2, maxOutputTokens: 800 }
|
|
127
|
+
})
|
|
128
|
+
});
|
|
129
|
+
const data = await response.json();
|
|
130
|
+
const candidateText = data?.candidates?.[0]?.content?.parts?.[0]?.text;
|
|
131
|
+
if (!candidateText) throw new Error("Malformed API structural response layout");
|
|
132
|
+
return candidateText.replace(/\n/g, "<br>");
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.error("\u274C Gemini API processing breakdown failure:", error);
|
|
135
|
+
return `<span style="color: #f87171;">Failed to generate AI diagnosis framework: ${error.message}</span>`;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
90
138
|
async function executeTestPipeline(config) {
|
|
91
139
|
if (!blazeCore || typeof blazeCore.runCorrelatedTransaction !== "function") {
|
|
92
140
|
console.error("\u274C Error: runCorrelatedTransaction function is missing from the compiled binary bindings.");
|
|
@@ -349,6 +397,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
349
397
|
healthScore
|
|
350
398
|
};
|
|
351
399
|
generateFinalAgentReport(history, healthScore);
|
|
400
|
+
const geminiAnalysisHtml = await generateGeminiRCA(history, finalSummaryCards, aggregateErrorLogs);
|
|
352
401
|
if (config.isSeo) {
|
|
353
402
|
const finalLat = finalState.avgLatency || finalSummaryCards.ttfb;
|
|
354
403
|
const seo = calculateSeoImpactMetrics(finalLat);
|
|
@@ -358,7 +407,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
358
407
|
Object.keys(globalCodeCounts).forEach((code) => {
|
|
359
408
|
breakdownRates[code] = totalRequestsAccumulator === 0 ? 0 : globalCodeCounts[code] / totalRequestsAccumulator * 100;
|
|
360
409
|
});
|
|
361
|
-
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests);
|
|
410
|
+
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests, geminiAnalysisHtml);
|
|
362
411
|
}
|
|
363
412
|
async function runStandardStressTest(config) {
|
|
364
413
|
console.log(`\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: ${config.threads} | Duration: ${config.durationSec}s]`);
|
|
@@ -397,6 +446,7 @@ async function runStandardStressTest(config) {
|
|
|
397
446
|
};
|
|
398
447
|
const isPassed = metrics.apdexScore >= config.targetApdex && metrics.errorRate <= config.targetErrorRate;
|
|
399
448
|
const verdictReason = isPassed ? "Static single-wave baseline checks concluded successfully without triggering health boundaries." : "Static verification loop completed with values exceeding defined quality thresholds.";
|
|
449
|
+
const geminiAnalysisHtml = await generateGeminiRCA(history, finalSummaryCards, rawErrors.length > 0 ? rawErrors : getFallbackClusterLogs());
|
|
400
450
|
if (config.isSeo) {
|
|
401
451
|
const seo = calculateSeoImpactMetrics(metrics.avgLatencyMs);
|
|
402
452
|
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}].`);
|
|
@@ -412,7 +462,7 @@ async function runStandardStressTest(config) {
|
|
|
412
462
|
total4xx: metrics.c4xx,
|
|
413
463
|
total5xx: metrics.c5xx,
|
|
414
464
|
breakdownRates
|
|
415
|
-
}, finalSummaryCards, rawRequests);
|
|
465
|
+
}, finalSummaryCards, rawRequests, geminiAnalysisHtml);
|
|
416
466
|
}
|
|
417
467
|
function getFallbackClusterLogs() {
|
|
418
468
|
const logs = [];
|
|
@@ -467,7 +517,7 @@ function processMetricsTelemetry(requests, durationSec) {
|
|
|
467
517
|
const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
|
|
468
518
|
const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
|
|
469
519
|
let c1xx = 0, c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
|
|
470
|
-
const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 502, 503: 0, 504: 0 };
|
|
520
|
+
const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 0, 502: 0, 503: 0, 504: 0 };
|
|
471
521
|
requests.forEach((r) => {
|
|
472
522
|
if (r.statusCode >= 100 && r.statusCode < 200) c1xx++;
|
|
473
523
|
else if (r.statusCode >= 200 && r.statusCode < 300) c2xx++;
|
|
@@ -528,7 +578,7 @@ function generateFinalAgentReport(history, score) {
|
|
|
528
578
|
console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
|
|
529
579
|
console.log("=======================================================\n");
|
|
530
580
|
}
|
|
531
|
-
function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = []) {
|
|
581
|
+
function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = [], geminiAnalysisHtml = "") {
|
|
532
582
|
const labels = history.map((h, i) => `${i + 1}s`);
|
|
533
583
|
const successRequestsData = history.map((h) => h.successRequests);
|
|
534
584
|
const failedWorkloadsData = history.map((h) => h.failedRequests);
|
|
@@ -545,33 +595,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
545
595
|
x: Number(((r.timestampMs - firstTimestamp) / 1e3).toFixed(2)),
|
|
546
596
|
y: Number(((r.dnsTimeMs || 0) + (r.tcpTimeMs || 0) + (r.tlsTimeMs || 0) + r.durationMs * 0.3).toFixed(1))
|
|
547
597
|
}));
|
|
548
|
-
let narrativeStoryText = "";
|
|
549
|
-
const terminalWave = history[history.length - 1];
|
|
550
|
-
const isSystemDegraded = cards.healthScore < 85 || terminalWave && terminalWave.errorRate > 0.01;
|
|
551
|
-
if (isSystemDegraded) {
|
|
552
|
-
let analyticalLogContext = "";
|
|
553
|
-
if (semanticReport && semanticReport.clusters && semanticReport.clusters.length > 0) {
|
|
554
|
-
const primaryPattern = semanticReport.clusters[0];
|
|
555
|
-
const blueprintSample = (primaryPattern.template || "").replace(/\[\d{4}-\d{2}-\d{2}.*?\]\s*/, "").substring(0, 130);
|
|
556
|
-
analyticalLogContext = ` The system failure state was dominated by a flood of <strong>${primaryPattern.category || "unclassified exceptions"}</strong> (${primaryPattern.count} trace entries), capturing dynamic footprints like: <code>${blueprintSample}...</code>.`;
|
|
557
|
-
}
|
|
558
|
-
narrativeStoryText = `<strong>Incident Narrative:</strong> During the load stress verification timeline, system resource contention triggered sharp degradation as simulated concurrency mounted up to <strong>${terminalWave?.threads || cards.saturationKneePoint} Virtual Users</strong>. At peak saturation, infrastructure throughput flattened out at <strong>${cards.throughput.toFixed(0)} req/sec</strong> while tracking metrics registered a P95 latency surge up to <strong>${terminalWave?.p95Latency.toFixed(1)}ms</strong>. ${verdictReason}${analyticalLogContext} The performance collapse dragged the composite health rating down to <strong>${cards.healthScore}/100</strong>, indicating target capacity boundaries have officially broken down under the active profile constraints.`;
|
|
559
|
-
} else {
|
|
560
|
-
narrativeStoryText = `<strong>Operational Summary:</strong> The pipeline concluded successfully without showing structural strain or performance compromises. Across the concurrency tiers peaking at <strong>${terminalWave?.threads || config.threads} active execution threads</strong>, infrastructure velocity sustained a robust <strong>${cards.throughput.toFixed(0)} req/sec</strong> with an exceptional Apdex tier of <strong>${cards.apdex.toFixed(2)}</strong>. Scanned event frameworks and metric trends yielded zero repeating error footprints, confirming system resilience matches the expected parameters perfectly with a health score of <strong>${cards.healthScore}/100</strong>.`;
|
|
561
|
-
}
|
|
562
|
-
const incidentNarrativeBoxHtml = `
|
|
563
|
-
<div class="card" style="margin-bottom: 2rem; background: linear-gradient(135deg, #1e1b4b 0%, #0f172a 100%); border: 1px solid #4338ca; border-radius: 8px; padding: 1.5rem; box-shadow: 0 4px 25px rgba(0, 0, 0, 0.55);">
|
|
564
|
-
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.85rem;">
|
|
565
|
-
<div style="display: flex; align-items: center; gap: 0.6rem; font-weight: 700; color: #818cf8; font-size: 1.1rem; text-transform: none; letter-spacing: normal;">
|
|
566
|
-
\u{1F9E0} Generative Incident Narrative (AI Plain-English Summary)
|
|
567
|
-
</div>
|
|
568
|
-
<span style="background: #4338ca; color: #e0e7ff; font-size: 0.7rem; font-weight: 800; padding: 0.25rem 0.6rem; border-radius: 4px; text-transform: uppercase; letter-spacing: 0.05em;">Telemetry Insight</span>
|
|
569
|
-
</div>
|
|
570
|
-
<p style="margin: 0; color: #cbd5e1; font-size: 0.95rem; line-height: 1.65; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
|
|
571
|
-
${narrativeStoryText}
|
|
572
|
-
</p>
|
|
573
|
-
</div>
|
|
574
|
-
`;
|
|
575
598
|
let logClustersHtml = "";
|
|
576
599
|
if (semanticReport) {
|
|
577
600
|
const totalLogCount = semanticReport.clusters.reduce((sum, c) => sum + c.count, 0);
|
|
@@ -770,7 +793,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
770
793
|
.badge-fail { background: #dc2626; color: #fef2f2; }
|
|
771
794
|
</style></head><body>
|
|
772
795
|
<div class="container">
|
|
773
|
-
${incidentNarrativeBoxHtml}
|
|
774
796
|
<div class="header">
|
|
775
797
|
<h1>\u{1F525} Blaze Core Performance Analysis</h1>
|
|
776
798
|
<div class="meta">Target Script: <code>${config.targetScript}</code></div>
|
|
@@ -869,6 +891,16 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
869
891
|
</div>
|
|
870
892
|
</div>
|
|
871
893
|
|
|
894
|
+
<!-- Live Gemini 2.5 Flash Autonomous RCA Module -->
|
|
895
|
+
<div class="card" style="margin-bottom: 2rem; background: #0c172b; border: 1px solid #7c3aed;">
|
|
896
|
+
<h3 style="color: #a78bfa; display: flex; align-items: center; gap: 0.6rem; font-size: 1.2rem; border-bottom: 1px solid #1e293b; padding-bottom: 0.5rem;">
|
|
897
|
+
\u26A1 Gemini 2.5 Flash Autonomous Root Cause Analysis (RCA)
|
|
898
|
+
</h3>
|
|
899
|
+
<div style="font-size: 0.95rem; line-height: 1.6; color: #cbd5e1; padding: 0.5rem 0;">
|
|
900
|
+
${geminiAnalysisHtml}
|
|
901
|
+
</div>
|
|
902
|
+
</div>
|
|
903
|
+
|
|
872
904
|
<div class="charts-grid">
|
|
873
905
|
<div class="graph-card">
|
|
874
906
|
<div class="graph-title">\u{1F4CA} Throughput Velocity & Workload Volume</div>
|
|
@@ -1094,7 +1126,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
1094
1126
|
responsive: true,
|
|
1095
1127
|
maintainAspectRatio: false,
|
|
1096
1128
|
plugins: {
|
|
1097
|
-
legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } },
|
|
1129
|
+
legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } },
|
|
1098
1130
|
cutout: '65%'
|
|
1099
1131
|
}
|
|
1100
1132
|
}
|
|
Binary file
|