blaze-performance-tester 3.1.4 → 3.1.5
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 +72 -390
- package/dist/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -70,7 +70,7 @@ var blazeCore;
|
|
|
70
70
|
try {
|
|
71
71
|
blazeCore = require2(nativeBindingPath);
|
|
72
72
|
} catch (e) {
|
|
73
|
-
console.error(
|
|
73
|
+
console.error("\u274C Failed to load native C++ bindings from " + nativeBindingPath);
|
|
74
74
|
process.exit(1);
|
|
75
75
|
}
|
|
76
76
|
var mathUtils = {
|
|
@@ -109,7 +109,7 @@ async function executeTestPipeline(config) {
|
|
|
109
109
|
})
|
|
110
110
|
}
|
|
111
111
|
];
|
|
112
|
-
console.log(
|
|
112
|
+
console.log("Launching automated script transaction analysis for: " + config.targetScript);
|
|
113
113
|
const sanitizedSteps = transactionalScenario.map((step) => ({
|
|
114
114
|
...step,
|
|
115
115
|
body: typeof step.body === "string" ? step.body : step.body ? JSON.stringify(step.body) : ""
|
|
@@ -209,7 +209,7 @@ async function runBlazeCoreEngine(config) {
|
|
|
209
209
|
const steadyStateRequests = rawRequests.slice(warmUpCutoff);
|
|
210
210
|
const metrics = processMetricsTelemetry(steadyStateRequests.length > 0 ? steadyStateRequests : rawRequests, config.durationSec);
|
|
211
211
|
const rawErrors = rawRequests.filter((r) => r.errorMessage).map((r) => r.errorMessage);
|
|
212
|
-
resolve2({ metrics, rawErrors });
|
|
212
|
+
resolve2({ metrics, rawErrors, rawRequests: steadyStateRequests.length > 0 ? steadyStateRequests : rawRequests });
|
|
213
213
|
}, 1e3);
|
|
214
214
|
});
|
|
215
215
|
}
|
|
@@ -217,7 +217,8 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
217
217
|
console.log("\u{1F680} Initializing Intelligent Autonomous Load Agent...");
|
|
218
218
|
const history = [];
|
|
219
219
|
let aggregateErrorLogs = [];
|
|
220
|
-
let
|
|
220
|
+
let lastRawRequests = [];
|
|
221
|
+
let total1xx = 0, total2xx = 0, total3xx = 0, total4xx = 0, total5xx = 0;
|
|
221
222
|
let globalMetricsAccumulator = { dns: [], tcp: [], tls: [], ttfb: [], latencies: [], bandwidths: [] };
|
|
222
223
|
let currentThreads = Math.min(config.maxThreads, Math.max(5, Math.floor(config.maxThreads * 0.2)));
|
|
223
224
|
let baseStep = config.stepSize;
|
|
@@ -225,11 +226,13 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
225
226
|
let verdictReason = "The system successfully scaled and remained stable within parameters up to maximum configured capacity allocations.";
|
|
226
227
|
let saturationKneePoint = null;
|
|
227
228
|
while (currentThreads <= config.maxThreads && isStable) {
|
|
228
|
-
console.log(
|
|
229
|
-
const { metrics, rawErrors } = await runBlazeCoreEngine({ ...config, threads: currentThreads });
|
|
229
|
+
console.log("\u{1F916} [Agent Decision]: Testing execution tier at " + currentThreads + " concurrent threads...");
|
|
230
|
+
const { metrics, rawErrors, rawRequests } = await runBlazeCoreEngine({ ...config, threads: currentThreads });
|
|
230
231
|
if (config.clusterLogs) {
|
|
231
232
|
aggregateErrorLogs = aggregateErrorLogs.concat(rawErrors);
|
|
232
233
|
}
|
|
234
|
+
lastRawRequests = rawRequests;
|
|
235
|
+
total1xx += metrics.c1xx;
|
|
233
236
|
total2xx += metrics.c2xx;
|
|
234
237
|
total3xx += metrics.c3xx;
|
|
235
238
|
total4xx += metrics.c4xx;
|
|
@@ -258,7 +261,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
258
261
|
const dLatency_dThreads = (current.avgLatency - previous.avgLatency) / (current.threads - previous.threads);
|
|
259
262
|
if (current.throughput <= previous.throughput * 1.02 && dLatency_dThreads > 4.5) {
|
|
260
263
|
saturationKneePoint = currentThreads;
|
|
261
|
-
verdictReason =
|
|
264
|
+
verdictReason = "Saturation knee-point identified at " + currentThreads + " VUs where throughput flattened while latency spiked rapidly.";
|
|
262
265
|
isStable = false;
|
|
263
266
|
break;
|
|
264
267
|
}
|
|
@@ -290,6 +293,8 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
290
293
|
const analyzer = new LogAnalyzer();
|
|
291
294
|
semanticReport = analyzer.process(aggregateErrorLogs);
|
|
292
295
|
}
|
|
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;
|
|
293
298
|
const finalSummaryCards = {
|
|
294
299
|
apdex: history[history.length - 1]?.apdex || 0,
|
|
295
300
|
throughput: history[history.length - 1]?.throughput || 0,
|
|
@@ -299,14 +304,15 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
299
304
|
tcp: mathUtils.mean(globalMetricsAccumulator.tcp),
|
|
300
305
|
tls: mathUtils.mean(globalMetricsAccumulator.tls),
|
|
301
306
|
stdDev: mathUtils.stdDev(globalMetricsAccumulator.latencies, mathUtils.mean(globalMetricsAccumulator.latencies)),
|
|
302
|
-
saturationKneePoint: saturationKneePoint || history[history.length - 1]?.threads || 50
|
|
307
|
+
saturationKneePoint: saturationKneePoint || history[history.length - 1]?.threads || 50,
|
|
308
|
+
vuRampUpVelocity
|
|
303
309
|
};
|
|
304
310
|
generateFinalAgentReport(history);
|
|
305
|
-
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total2xx, total3xx, total4xx, total5xx }, finalSummaryCards);
|
|
311
|
+
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx }, finalSummaryCards, lastRawRequests);
|
|
306
312
|
}
|
|
307
313
|
async function runStandardStressTest(config) {
|
|
308
|
-
console.log(
|
|
309
|
-
const { metrics, rawErrors } = await runBlazeCoreEngine(config);
|
|
314
|
+
console.log("\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: " + config.threads + " | Duration: " + config.durationSec + "s]");
|
|
315
|
+
const { metrics, rawErrors, rawRequests } = await runBlazeCoreEngine(config);
|
|
310
316
|
printMatrixDashboard(metrics, config.threads);
|
|
311
317
|
const history = [{
|
|
312
318
|
threads: config.threads,
|
|
@@ -334,21 +340,23 @@ async function runStandardStressTest(config) {
|
|
|
334
340
|
tcp: metrics.avgTcpMs,
|
|
335
341
|
tls: metrics.avgTlsMs,
|
|
336
342
|
stdDev: metrics.stdDevMs,
|
|
337
|
-
saturationKneePoint: config.threads
|
|
343
|
+
saturationKneePoint: config.threads,
|
|
344
|
+
vuRampUpVelocity: config.threads / config.durationSec
|
|
338
345
|
};
|
|
339
346
|
const isPassed = metrics.apdexScore >= config.targetApdex && metrics.errorRate <= config.targetErrorRate;
|
|
340
347
|
const verdictReason = isPassed ? "Static single-wave baseline checks concluded successfully without triggering health boundaries." : "Static verification loop completed with values exceeding defined quality thresholds.";
|
|
341
348
|
exportHtmlDashboard(history, config, verdictReason, semanticReport, {
|
|
349
|
+
total1xx: metrics.c1xx,
|
|
342
350
|
total2xx: metrics.c2xx,
|
|
343
351
|
total3xx: metrics.c3xx,
|
|
344
352
|
total4xx: metrics.c4xx,
|
|
345
353
|
total5xx: metrics.c5xx
|
|
346
|
-
}, finalSummaryCards);
|
|
354
|
+
}, finalSummaryCards, rawRequests);
|
|
347
355
|
}
|
|
348
356
|
function getFallbackClusterLogs() {
|
|
349
357
|
const logs = [];
|
|
350
358
|
const add = (msg, count) => {
|
|
351
|
-
for (let i = 0; i < count; i++) logs.push(
|
|
359
|
+
for (let i = 0; i < count; i++) logs.push("[2026-07-08T12:08:18.000Z] " + msg);
|
|
352
360
|
};
|
|
353
361
|
add("JsonWebTokenError: jwt expired at JMT.verify (\\app\\node_modules\\jsonwebtoken\\index.js:5)", 37);
|
|
354
362
|
add("Error: ECONNREFUSED 127.0.0.1:5432 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1)", 33);
|
|
@@ -396,9 +404,10 @@ function processMetricsTelemetry(requests, durationSec) {
|
|
|
396
404
|
const avgTcpMs = mathUtils.mean(requests.map((r) => r.tcpTimeMs || 0));
|
|
397
405
|
const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
|
|
398
406
|
const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
|
|
399
|
-
let c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
|
|
407
|
+
let c1xx = 0, c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
|
|
400
408
|
requests.forEach((r) => {
|
|
401
|
-
if (r.statusCode >=
|
|
409
|
+
if (r.statusCode >= 100 && r.statusCode < 200) c1xx++;
|
|
410
|
+
else if (r.statusCode >= 200 && r.statusCode < 300) c2xx++;
|
|
402
411
|
else if (r.statusCode >= 300 && r.statusCode < 400) c3xx++;
|
|
403
412
|
else if (r.statusCode >= 400 && r.statusCode < 500) c4xx++;
|
|
404
413
|
else if (r.statusCode >= 500) c5xx++;
|
|
@@ -418,6 +427,7 @@ function processMetricsTelemetry(requests, durationSec) {
|
|
|
418
427
|
p95LatencyMs,
|
|
419
428
|
errorRate,
|
|
420
429
|
apdexScore,
|
|
430
|
+
c1xx,
|
|
421
431
|
c2xx,
|
|
422
432
|
c3xx,
|
|
423
433
|
c4xx,
|
|
@@ -431,11 +441,11 @@ function processMetricsTelemetry(requests, durationSec) {
|
|
|
431
441
|
}
|
|
432
442
|
function printMatrixDashboard(m, threads) {
|
|
433
443
|
const pad = (val, size) => String(val).padEnd(size).substring(0, size);
|
|
434
|
-
console.log(
|
|
435
|
-
console.log(
|
|
436
|
-
console.log(
|
|
437
|
-
console.log(
|
|
438
|
-
console.log(
|
|
444
|
+
console.log("-----------------------------------------------------------------------------------------");
|
|
445
|
+
console.log("| Threads | Samples | Avg Latency | P95 Latency | Throughput | Error Rate | Apdex |");
|
|
446
|
+
console.log("-----------------------------------------------------------------------------------------");
|
|
447
|
+
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) + " |");
|
|
448
|
+
console.log("-----------------------------------------------------------------------------------------");
|
|
439
449
|
}
|
|
440
450
|
function generateFinalAgentReport(history) {
|
|
441
451
|
if (history.length === 0) return;
|
|
@@ -445,396 +455,68 @@ function generateFinalAgentReport(history) {
|
|
|
445
455
|
console.log("\n=======================================================");
|
|
446
456
|
console.log("\u{1F9E0} INTELLIGENT AUTONOMOUS LOAD AGENT FINAL REPORT");
|
|
447
457
|
console.log("=======================================================");
|
|
448
|
-
console.log(
|
|
449
|
-
console.log(
|
|
450
|
-
console.log(
|
|
458
|
+
console.log("\u{1F3C6} Recommended Max Safe Concurrency : " + maxSafeThreads + " allocation threads");
|
|
459
|
+
console.log("\u{1F4A5} Infrastructure Failure Boundary : " + history[history.length - 1].threads + " concurrency allocation");
|
|
460
|
+
console.log("\u26A1 Peak Achieved Cluster Velocity : " + peakThroughput.toFixed(0) + " req/sec");
|
|
451
461
|
console.log("=======================================================\n");
|
|
452
462
|
}
|
|
453
|
-
function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards) {
|
|
454
|
-
const labels = history.map((h, i) =>
|
|
463
|
+
function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = []) {
|
|
464
|
+
const labels = history.map((h, i) => i + 1 + "s");
|
|
455
465
|
const successRequestsData = history.map((h) => h.successRequests);
|
|
456
466
|
const failedWorkloadsData = history.map((h) => h.failedRequests);
|
|
457
467
|
const activeThreadsData = history.map((h) => h.threads);
|
|
458
468
|
const ttfTrendData = history.map((h) => h.avgLatency * 1.1);
|
|
459
469
|
const waveListItems = history.map((h) => {
|
|
460
|
-
return
|
|
470
|
+
return '<div class="wave-item">Wave (' + h.threads + " VUs): P95 " + h.p95Latency.toFixed(1) + "ms, Errors " + (h.errorRate * 100).toFixed(1) + "%</div>";
|
|
461
471
|
}).join("");
|
|
462
472
|
const estimatedMonthlyCost = (cards.throughput * 0.045 * 24 * 30).toFixed(2);
|
|
463
473
|
const recommendedCpuCores = Math.max(2, Math.ceil(cards.saturationKneePoint / 75));
|
|
464
474
|
const recommendedRamGb = recommendedCpuCores * 2;
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
<div style="color: #94a3b8; font-size: 0.9rem; margin-bottom: 1.5rem;">
|
|
475
|
-
Captured <strong style="color: #f8fafc;">${totalLogCount}</strong> raw failures grouped into <strong style="color: #f8fafc;">${uniquePatternsCount}</strong> unique structural patterns.
|
|
476
|
-
</div>
|
|
477
|
-
|
|
478
|
-
<table style="width: 100%; border-collapse: collapse;">
|
|
479
|
-
<thead>
|
|
480
|
-
<tr style="border-bottom: 1px solid #1e293b;">
|
|
481
|
-
<th style="width: 8%; padding: 0.75rem; text-align: left; color: #64748b; font-size: 0.85rem; font-weight: bold; text-transform: none;">Count</th>
|
|
482
|
-
<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>
|
|
483
|
-
<th style="width: 10%; padding: 0.75rem; text-align: left; color: #64748b; font-size: 0.85rem; font-weight: bold; text-transform: none;">Severity</th>
|
|
484
|
-
<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>
|
|
485
|
-
</tr>
|
|
486
|
-
</thead>
|
|
487
|
-
<tbody>
|
|
488
|
-
${semanticReport.clusters.map((c) => {
|
|
489
|
-
let catColor = "#fb923c";
|
|
490
|
-
if (c.category === "Authentication_Error") catColor = "#c084fc";
|
|
491
|
-
if (c.category === "Product_Error") catColor = "#f87171";
|
|
492
|
-
if (c.category === "Environment_Infrastructure_Error") catColor = "#fb923c";
|
|
493
|
-
let sevBg = c.severity === "CRITICAL" ? "#dc2626" : "#ea580c";
|
|
494
|
-
const rawTemplate = c.template || "";
|
|
495
|
-
const cleanedTemplate = rawTemplate.replace(/\[\d{4}-\d{2}-\d{2}.*?\]\s*/, "");
|
|
496
|
-
return `
|
|
497
|
-
<tr style="border-bottom: 1px solid #1e293b; vertical-align: top;">
|
|
498
|
-
<td style="padding: 1.25rem 0.75rem; font-size: 1.2rem; font-weight: bold; color: #f8fafc;">${c.count}</td>
|
|
499
|
-
<td style="padding: 1.25rem 0.75rem; color: ${catColor}; font-weight: 600; font-size: 0.95rem;">${c.category}</td>
|
|
500
|
-
<td style="padding: 1.25rem 0.75rem;">
|
|
501
|
-
<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>
|
|
502
|
-
</td>
|
|
503
|
-
<td style="padding: 1.25rem 0.75rem;">
|
|
504
|
-
<div style="background: #090d16; border-radius: 4px; padding: 0.6rem 0.8rem; border-left: 3px solid #1e293b; margin-bottom: 0.5rem;">
|
|
505
|
-
<code style="color: #cbd5e1; font-family: monospace; font-size: 0.9rem; white-space: pre-wrap; word-break: break-all;">${cleanedTemplate}</code>
|
|
506
|
-
</div>
|
|
507
|
-
<div style="color: #64748b; font-size: 0.8rem; font-family: monospace; padding-left: 0.2rem; line-height: 1.4;">
|
|
508
|
-
<span style="color: #475569;">Real Example Trace:</span> ${rawTemplate}
|
|
509
|
-
</div>
|
|
510
|
-
</td>
|
|
511
|
-
</tr>`;
|
|
512
|
-
}).join("")}
|
|
513
|
-
</tbody>
|
|
514
|
-
</table>
|
|
515
|
-
</div>`;
|
|
516
|
-
}
|
|
517
|
-
const liveAdjusterHtml = `
|
|
518
|
-
<div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
|
|
519
|
-
<h3 style="color: #38bdf8; display: flex; align-items: center; gap: 0.5rem; font-size: 1.2rem; margin-bottom: 1rem;">
|
|
520
|
-
\u{1F39B}\uFE0F Live Concurrency Adjuster (Mid-Test Simulation)
|
|
475
|
+
const firstTimestamp = rawRequests[0]?.timestampMs || Date.now();
|
|
476
|
+
const scatterPoints = rawRequests.slice(0, 180).map((r) => ({
|
|
477
|
+
x: Number(((r.timestampMs - firstTimestamp) / 1e3).toFixed(2)),
|
|
478
|
+
y: Number(((r.dnsTimeMs || 0) + (r.tcpTimeMs || 0) + (r.tlsTimeMs || 0) + r.durationMs * 0.3).toFixed(1))
|
|
479
|
+
}));
|
|
480
|
+
const naturalLanguageAssistantHtml = `
|
|
481
|
+
<div class="card" style="margin-top: 2rem; background: linear-gradient(135deg, #1e1b4b 0%, #111827 100%); border: 1px solid #4338ca;">
|
|
482
|
+
<h3 style="color: #818cf8; display: flex; align-items: center; gap: 0.6rem; font-size: 1.25rem; margin-bottom: 0.5rem; border-bottom: none; padding-bottom: 0;">
|
|
483
|
+
\u{1F52E} Ask the Test \u2014 Embedded Natural Language Assistant
|
|
521
484
|
</h3>
|
|
522
|
-
<div style="
|
|
523
|
-
<
|
|
524
|
-
<label for="concurrencySlider" style="display: block; font-size: 0.85rem; color: #94a3b8; margin-bottom: 0.5rem;">
|
|
525
|
-
Scale Virtual Users (VUs): <strong id="sliderValue" style="color: #38bdf8;">${config.threads}</strong> threads
|
|
526
|
-
</label>
|
|
527
|
-
<input type="range" id="concurrencySlider" min="5" max="${config.maxThreads || 300}" step="5" value="${config.threads}" style="width: 100%; accent-color: #38bdf8; cursor: pointer;">
|
|
528
|
-
</div>
|
|
529
|
-
<div style="display: flex; gap: 1.5rem; text-align: center;">
|
|
530
|
-
<div style="background: #090d16; padding: 0.75rem 1rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
531
|
-
<div style="font-size: 0.7rem; color: #64748b; text-transform: uppercase;">Sim. Throughput</div>
|
|
532
|
-
<div id="simThroughput" style="font-size: 1.2rem; font-weight: bold; color: #f97316;">${cards.throughput.toFixed(0)}/s</div>
|
|
533
|
-
</div>
|
|
534
|
-
<div style="background: #090d16; padding: 0.75rem 1rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
535
|
-
<div style="font-size: 0.7rem; color: #64748b; text-transform: uppercase;">Sim. Latency</div>
|
|
536
|
-
<div id="simLatency" style="font-size: 1.2rem; font-weight: bold; color: #10b981;">${cards.ttfb.toFixed(1)}ms</div>
|
|
537
|
-
</div>
|
|
538
|
-
</div>
|
|
485
|
+
<div style="color: #94a3b8; font-size: 0.85rem; margin-bottom: 1.25rem;">
|
|
486
|
+
Query metrics, log topologies, and SLA compliance profiles instantly. Try asking: <span style="color: #a5b4fc; font-family: monospace; cursor: pointer;" onclick="document.getElementById('assistantInput').value=this.innerText; runAssistantQuery();">"What was our peak throughput capacity?"</span> or <span style="color: #a5b4fc; font-family: monospace; cursor: pointer;" onclick="document.getElementById('assistantInput').value=this.innerText; runAssistantQuery();">"Summarize the server logs and confidence ratings"</span>.
|
|
539
487
|
</div>
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
<div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
548
|
-
<div class="card-title">Est. Monthly Cloud Cost</div>
|
|
549
|
-
<div class="card-value green">$${estimatedMonthlyCost} <span class="unit">/mo</span></div>
|
|
550
|
-
</div>
|
|
551
|
-
<div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
552
|
-
<div class="card-title">Recommended CPU Right-Sizing</div>
|
|
553
|
-
<div class="card-value purple">${recommendedCpuCores} <span class="unit">vCores</span></div>
|
|
554
|
-
</div>
|
|
555
|
-
<div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
|
|
556
|
-
<div class="card-title">Recommended Memory Allocation</div>
|
|
557
|
-
<div class="card-value orange">${recommendedRamGb} <span class="unit">GB RAM</span></div>
|
|
558
|
-
</div>
|
|
488
|
+
<div style="display: flex; gap: 0.75rem; margin-bottom: 1rem;">
|
|
489
|
+
<input type="text" id="assistantInput" placeholder="Ask a question regarding test telemetry..."
|
|
490
|
+
style="flex: 1; background: #030712; border: 1px solid #374151; border-radius: 6px; padding: 0.75rem 1rem; color: #f9fafb; font-size: 0.9rem; outline: none;"
|
|
491
|
+
onkeydown="if(event.key === 'Enter') runAssistantQuery();" />
|
|
492
|
+
<button onclick="runAssistantQuery()" style="background: #4f46e5; color: #ffffff; border: none; padding: 0 1.5rem; border-radius: 6px; font-weight: 600; font-size: 0.9rem; cursor: pointer; transition: background 0.2s;">
|
|
493
|
+
Query Engine
|
|
494
|
+
</button>
|
|
559
495
|
</div>
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
<title>Blaze Core Performance Report</title>
|
|
564
|
-
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
565
|
-
<style>
|
|
566
|
-
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #0b111e; color: #f8fafc; margin: 0; padding: 2rem; }
|
|
567
|
-
.container { max-width: 1300px; margin: 0 auto; }
|
|
568
|
-
.header { border-bottom: 1px solid #1e293b; padding-bottom: 1rem; margin-bottom: 1.5rem; }
|
|
569
|
-
h1 { color: #38bdf8; margin: 0; font-size: 2rem; }
|
|
570
|
-
.meta { color: #94a3b8; font-size: 0.9rem; margin-top: 0.5rem; }
|
|
571
|
-
|
|
572
|
-
.cards-wrapper { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 1.5rem; }
|
|
573
|
-
.metric-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 6px; padding: 1.25rem; position: relative; }
|
|
574
|
-
.card-title { font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.5rem; }
|
|
575
|
-
.card-value { font-size: 1.6rem; font-weight: 700; color: #ffffff; }
|
|
576
|
-
.card-value .unit { font-size: 0.9rem; font-weight: 500; color: #94a3b8; margin-left: 0.2rem; }
|
|
577
|
-
.card-value.green { color: #10b981; }
|
|
578
|
-
.card-value.orange { color: #f97316; }
|
|
579
|
-
.card-value.purple { color: #a855f7; }
|
|
580
|
-
.card-subtext { font-size: 0.8rem; color: #10b981; font-weight: 500; margin-left: 0.4rem; display: inline-block; }
|
|
581
|
-
|
|
582
|
-
.top-layout-grid { display: grid; grid-template-columns: 1fr 400px; gap: 1.5rem; margin-bottom: 2rem; }
|
|
583
|
-
.verdict-box { background: #0f172a; border: 1px dashed #ea580c; border-radius: 8px; padding: 1.25rem; }
|
|
584
|
-
.verdict-title { text-transform: uppercase; font-size: 0.85rem; font-weight: 700; color: #f97316; margin-bottom: 0.5rem; }
|
|
585
|
-
.verdict-text { font-size: 0.95rem; line-height: 1.5; color: #e2e8f0; margin-bottom: 0.75rem; }
|
|
586
|
-
.verdict-waves { background: #1f2937; border-radius: 6px; padding: 0.75rem 1rem; font-family: monospace; color: #9ca3af; font-size: 0.9rem; }
|
|
587
|
-
.wave-item { margin: 0.25rem 0; }
|
|
588
|
-
|
|
589
|
-
.matrix-box { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.25rem; }
|
|
590
|
-
.matrix-title { font-size: 1.1rem; font-weight: bold; color: #ffffff; margin-bottom: 1rem; }
|
|
591
|
-
.matrix-box .matrix-row { display: flex; justify-content: space-between; align-items: center; padding: 0.6rem 0; border-bottom: 1px solid #1e293b; }
|
|
592
|
-
.matrix-box .matrix-row:last-child { border-bottom: none; }
|
|
593
|
-
.matrix-label { font-size: 0.9rem; color: #f8fafc; display: flex; align-items: center; gap: 0.5rem; }
|
|
594
|
-
.matrix-badge { font-size: 0.7rem; font-weight: bold; padding: 0.1rem 0.3rem; border-radius: 4px; }
|
|
595
|
-
.badge-2xx { background: rgba(22, 163, 74, 0.2); color: #4ade80; }
|
|
596
|
-
.badge-3xx { background: rgba(148, 163, 184, 0.2); color: #cbd5e1; }
|
|
597
|
-
.badge-4xx { background: rgba(234, 179, 8, 0.2); color: #fde047; }
|
|
598
|
-
.badge-5xx { background: rgba(220, 38, 38, 0.2); color: #f87171; }
|
|
599
|
-
.matrix-value { font-size: 1rem; font-weight: bold; color: #ffffff; }
|
|
600
|
-
|
|
601
|
-
.charts-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; margin-bottom: 2rem; }
|
|
602
|
-
.graph-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.5rem; }
|
|
603
|
-
.graph-title { font-size: 1.1rem; font-weight: 700; color: #ffffff; margin-bottom: 1.2rem; display: flex; align-items: center; gap: 0.5rem; }
|
|
604
|
-
|
|
605
|
-
.card { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.5rem; }
|
|
606
|
-
h3 { margin-top: 0; color: #cbd5e1; border-bottom: 1px solid #1e293b; padding-bottom: 0.5rem; }
|
|
607
|
-
table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
|
|
608
|
-
th, td { padding: 0.75rem; text-align: left; border-bottom: 1px solid #1e293b; }
|
|
609
|
-
th { color: #94a3b8; font-weight: 600; }
|
|
610
|
-
.badge { padding: 0.25rem 0.5rem; border-radius: 4px; font-size: 0.8rem; font-weight: bold; }
|
|
611
|
-
.badge-success { background: #16a34a; color: #f0fdf4; }
|
|
612
|
-
.badge-fail { background: #dc2626; color: #fef2f2; }
|
|
613
|
-
</style></head><body>
|
|
614
|
-
<div class="container">
|
|
615
|
-
<div class="header">
|
|
616
|
-
<h1>\u{1F525} Blaze Core Performance Analysis</h1>
|
|
617
|
-
<div class="meta">Target Script: <code>${config.targetScript}</code></div>
|
|
618
|
-
</div>
|
|
619
|
-
|
|
620
|
-
<div class="cards-wrapper">
|
|
621
|
-
<div class="metric-card">
|
|
622
|
-
<div class="card-title">Apdex Score (T: 50ms)</div>
|
|
623
|
-
<div class="card-value green">${cards.apdex.toFixed(2)}<span class="card-subtext">(Good)</span></div>
|
|
624
|
-
</div>
|
|
625
|
-
<div class="metric-card">
|
|
626
|
-
<div class="card-title">Throughput</div>
|
|
627
|
-
<div class="card-value orange">${cards.throughput.toFixed(1)}<span class="unit">/s</span></div>
|
|
628
|
-
</div>
|
|
629
|
-
<div class="metric-card">
|
|
630
|
-
<div class="card-title">Network Bandwidth</div>
|
|
631
|
-
<div class="card-value purple">${cards.bandwidth.toFixed(2)}<span class="unit">MB/s</span></div>
|
|
632
|
-
</div>
|
|
633
|
-
<div class="metric-card">
|
|
634
|
-
<div class="card-title">Avg Time To First Byte</div>
|
|
635
|
-
<div class="card-value">${cards.ttfb.toFixed(1)}<span class="unit">ms</span></div>
|
|
636
|
-
</div>
|
|
637
|
-
<div class="metric-card">
|
|
638
|
-
<div class="card-title">DNS Lookup</div>
|
|
639
|
-
<div class="card-value">${cards.dns.toFixed(2)}<span class="unit">ms</span></div>
|
|
640
|
-
</div>
|
|
641
|
-
<div class="metric-card">
|
|
642
|
-
<div class="card-title">TCP Connect</div>
|
|
643
|
-
<div class="card-value">${cards.tcp.toFixed(2)}<span class="unit">ms</span></div>
|
|
644
|
-
</div>
|
|
645
|
-
<div class="metric-card">
|
|
646
|
-
<div class="card-title">TLS Handshake</div>
|
|
647
|
-
<div class="card-value">${cards.tls.toFixed(2)}<span class="unit">ms</span></div>
|
|
648
|
-
</div>
|
|
649
|
-
<div class="metric-card">
|
|
650
|
-
<div class="card-title">Stability (Std Dev)</div>
|
|
651
|
-
<div class="card-value">±${cards.stdDev.toFixed(1)}<span class="unit">ms</span></div>
|
|
496
|
+
<div id="assistantResponseContainer" style="display: none; background: #030712; border: 1px solid #1f2937; border-radius: 6px; padding: 1.25rem;">
|
|
497
|
+
<div style="font-size: 0.7rem; font-weight: bold; color: #6366f1; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.5rem; display: flex; align-items: center; gap: 0.3rem;">
|
|
498
|
+
<span>\u{1F916} AI Assistant Response</span>
|
|
652
499
|
</div>
|
|
500
|
+
<div id="assistantResponseText" style="font-size: 0.9rem; line-height: 1.5; color: #e5e7eb; white-space: pre-wrap;"></div>
|
|
653
501
|
</div>
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
<div class="
|
|
663
|
-
|
|
664
|
-
<div class="matrix-row">
|
|
665
|
-
<div class="matrix-label">Successful <span class="matrix-badge badge-2xx">2xx</span></div>
|
|
666
|
-
<div class="matrix-value">${responseMatrix.total2xx}</div>
|
|
667
|
-
</div>
|
|
668
|
-
<div class="matrix-row">
|
|
669
|
-
<div class="matrix-label">Redirects <span class="matrix-badge badge-3xx">3xx</span></div>
|
|
670
|
-
<div class="matrix-value">${responseMatrix.total3xx}</div>
|
|
671
|
-
</div>
|
|
672
|
-
<div class="matrix-row">
|
|
673
|
-
<div class="matrix-label">Client Error <span class="matrix-badge badge-4xx">4xx</span></div>
|
|
674
|
-
<div class="matrix-value">${responseMatrix.total4xx}</div>
|
|
675
|
-
</div>
|
|
676
|
-
<div class="matrix-row">
|
|
677
|
-
<div class="matrix-label">Server Error <span class="matrix-badge badge-5xx">5xx</span></div>
|
|
678
|
-
<div class="matrix-value">${responseMatrix.total5xx}</div>
|
|
679
|
-
</div>
|
|
680
|
-
</div>
|
|
681
|
-
</div>
|
|
682
|
-
|
|
683
|
-
<div class="charts-grid">
|
|
684
|
-
<div class="graph-card">
|
|
685
|
-
<div class="graph-title">\u{1F4CA} Throughput Velocity & Workload Volume</div>
|
|
686
|
-
<div style="height: 280px; position: relative;">
|
|
687
|
-
<canvas id="volumeChart"></canvas>
|
|
688
|
-
</div>
|
|
689
|
-
</div>
|
|
690
|
-
|
|
691
|
-
<div class="graph-card">
|
|
692
|
-
<div class="graph-title">\u{1F504} Active Concurrency (VUs) vs. Time-to-Failure (TTF) Trend</div>
|
|
693
|
-
<div style="height: 280px; position: relative;">
|
|
694
|
-
<canvas id="concurrencyChart"></canvas>
|
|
695
|
-
</div>
|
|
696
|
-
</div>
|
|
697
|
-
</div>
|
|
698
|
-
|
|
699
|
-
<div class="card">
|
|
700
|
-
<h3>Telemetry Matrix Logs</h3>
|
|
701
|
-
<table>
|
|
702
|
-
<thead>
|
|
703
|
-
<tr>
|
|
704
|
-
<th>Concurrency (Threads)</th>
|
|
705
|
-
<th>Throughput</th>
|
|
706
|
-
<th>Avg Latency</th>
|
|
707
|
-
<th>P95 Latency</th>
|
|
708
|
-
<th>Error Rate</th>
|
|
709
|
-
<th>Status</th>
|
|
710
|
-
</tr>
|
|
711
|
-
</thead>
|
|
712
|
-
<tbody>
|
|
713
|
-
${history.map((h) => {
|
|
714
|
-
const isPassed = h.apdex >= config.targetApdex && h.errorRate <= config.targetErrorRate;
|
|
715
|
-
return `<tr>
|
|
716
|
-
<td><strong>${h.threads}</strong></td>
|
|
717
|
-
<td>${h.throughput.toFixed(0)} req/sec</td>
|
|
718
|
-
<td>${h.avgLatency.toFixed(1)} ms</td>
|
|
719
|
-
<td>${h.p95Latency.toFixed(1)} ms</td>
|
|
720
|
-
<td>${(h.errorRate * 100).toFixed(2)}%</td>
|
|
721
|
-
<td><span class="badge ${isPassed ? "badge-success" : "badge-fail"}">${isPassed ? "SLO PASS" : "SLO BREACH"}</span></td>
|
|
722
|
-
</tr>`;
|
|
723
|
-
}).join("")}
|
|
724
|
-
</tbody>
|
|
725
|
-
</table>
|
|
726
|
-
</div>
|
|
727
|
-
${liveAdjusterHtml}
|
|
728
|
-
${rightSizingHtml}
|
|
729
|
-
${logClustersHtml}
|
|
730
|
-
</div>
|
|
731
|
-
|
|
732
|
-
<script>
|
|
733
|
-
const labels = ${JSON.stringify(labels)};
|
|
734
|
-
const baseThroughput = ${cards.throughput};
|
|
735
|
-
const baseLatency = ${cards.ttfb};
|
|
736
|
-
|
|
737
|
-
// Live Concurrency Adjuster interactive client logic
|
|
738
|
-
const slider = document.getElementById('concurrencySlider');
|
|
739
|
-
const sliderVal = document.getElementById('sliderValue');
|
|
740
|
-
const simThroughput = document.getElementById('simThroughput');
|
|
741
|
-
const simLatency = document.getElementById('simLatency');
|
|
742
|
-
|
|
743
|
-
slider.addEventListener('input', (e) => {
|
|
744
|
-
const val = parseInt(e.target.value, 10);
|
|
745
|
-
sliderVal.textContent = val;
|
|
746
|
-
const factor = val / ${config.threads || 10};
|
|
747
|
-
simThroughput.textContent = (baseThroughput * Math.min(factor, 2.5)).toFixed(0) + '/s';
|
|
748
|
-
simLatency.textContent = (baseLatency * Math.pow(factor, 0.8)).toFixed(1) + 'ms';
|
|
749
|
-
});
|
|
750
|
-
|
|
751
|
-
new Chart(document.getElementById('volumeChart'), {
|
|
752
|
-
type: 'bar',
|
|
753
|
-
data: {
|
|
754
|
-
labels: labels,
|
|
755
|
-
datasets: [
|
|
756
|
-
{
|
|
757
|
-
label: 'Successful Requests',
|
|
758
|
-
data: ${JSON.stringify(successRequestsData)},
|
|
759
|
-
backgroundColor: '#10b981',
|
|
760
|
-
stack: 'requests',
|
|
761
|
-
barPercentage: 0.95,
|
|
762
|
-
categoryPercentage: 0.95
|
|
763
|
-
},
|
|
764
|
-
{
|
|
765
|
-
label: 'Failed Workloads',
|
|
766
|
-
data: ${JSON.stringify(failedWorkloadsData)},
|
|
767
|
-
backgroundColor: '#ef4444',
|
|
768
|
-
stack: 'requests',
|
|
769
|
-
barPercentage: 0.95,
|
|
770
|
-
categoryPercentage: 0.95
|
|
771
|
-
}
|
|
772
|
-
]
|
|
773
|
-
},
|
|
774
|
-
options: {
|
|
775
|
-
responsive: true,
|
|
776
|
-
maintainAspectRatio: false,
|
|
777
|
-
plugins: {
|
|
778
|
-
legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } }
|
|
779
|
-
},
|
|
780
|
-
scales: {
|
|
781
|
-
x: { grid: { color: '#1e293b' }, ticks: { color: '#64748b' } },
|
|
782
|
-
y: { stacked: true, grid: { color: '#1e293b' }, ticks: { color: '#64748b' } }
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
});
|
|
786
|
-
|
|
787
|
-
new Chart(document.getElementById('concurrencyChart'), {
|
|
788
|
-
type: 'line',
|
|
789
|
-
data: {
|
|
790
|
-
labels: labels,
|
|
791
|
-
datasets: [
|
|
792
|
-
{
|
|
793
|
-
label: 'Active VU Threads',
|
|
794
|
-
data: ${JSON.stringify(activeThreadsData)},
|
|
795
|
-
borderColor: '#38bdf8',
|
|
796
|
-
backgroundColor: 'rgba(56, 189, 248, 0.1)',
|
|
797
|
-
borderWidth: 2.5,
|
|
798
|
-
pointRadius: 4,
|
|
799
|
-
fill: true,
|
|
800
|
-
yAxisID: 'yThreads'
|
|
801
|
-
},
|
|
802
|
-
{
|
|
803
|
-
label: 'Time-to-Failure (TTF) Trend',
|
|
804
|
-
data: ${JSON.stringify(ttfTrendData)},
|
|
805
|
-
borderColor: '#f43f5e',
|
|
806
|
-
borderWidth: 2,
|
|
807
|
-
borderDash: [5, 5],
|
|
808
|
-
pointRadius: 3,
|
|
809
|
-
fill: false,
|
|
810
|
-
yAxisID: 'yTtf'
|
|
811
|
-
}
|
|
812
|
-
]
|
|
813
|
-
},
|
|
814
|
-
options: {
|
|
815
|
-
responsive: true,
|
|
816
|
-
maintainAspectRatio: false,
|
|
817
|
-
plugins: {
|
|
818
|
-
legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } }
|
|
819
|
-
},
|
|
820
|
-
scales: {
|
|
821
|
-
x: { grid: { color: '#1e293b' }, ticks: { color: '#64748b' } },
|
|
822
|
-
y_threads: { position: 'left', grid: { color: '#1e293b' }, ticks: { color: '#38bdf8' }, title: { display: true, text: 'VUs / Threads', color: '#38bdf8' } },
|
|
823
|
-
y_ttf: { position: 'right', grid: { drawOnChartArea: false }, ticks: { color: '#f43f5e' }, title: { display: true, text: 'TTF Index / Latency ms', color: '#f43f5e' } }
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
});
|
|
827
|
-
</script></body></html>`;
|
|
502
|
+
</div>`;
|
|
503
|
+
let logClustersHtml = "";
|
|
504
|
+
if (semanticReport) {
|
|
505
|
+
const totalLogCount = semanticReport.clusters.reduce((sum, c) => sum + c.count, 0);
|
|
506
|
+
const uniquePatternsCount = semanticReport.clusters.length;
|
|
507
|
+
logClustersHtml = '\n <div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">\n <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;">\n \u{1F9E0} Interactive Remediation Playbooks & Log Classification\n </h3>\n <div style="color: #94a3b8; font-size: 0.9rem; margin-bottom: 1.5rem;">\n Captured <strong style="color: #f8fafc;">' + totalLogCount + '</strong> raw failures grouped into <strong style="color: #f8fafc;">' + uniquePatternsCount + "</strong> unique structural patterns.\n </div>";
|
|
508
|
+
}
|
|
509
|
+
const liveAdjusterHtml = '\n <div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">\n <h3 style="color: #38bdf8; display: flex; align-items: center; gap: 0.5rem; font-size: 1.2rem; margin-bottom: 1rem;">\n \u{1F39B}\uFE0F Live Concurrency Adjuster (Mid-Test Simulation)\n </h3>\n <div style="display: flex; gap: 2rem; align-items: center; flex-wrap: wrap;">\n <div style="flex: 1; min-width: 280px;">\n <label for="concurrencySlider" style="display: block; font-size: 0.85rem; color: #94a3b8; margin-bottom: 0.5rem;">\n Scale Virtual Users (VUs): <strong id="sliderValue" style="color: #38bdf8;">' + config.threads + '</strong> threads\n </label>\n <input type="range" id="concurrencySlider" min="5" max="' + (config.maxThreads || 300) + '" step="5" value="' + config.threads + '" style="width: 100%; accent-color: #38bdf8; cursor: pointer;">\n </div>\n <div style="display: flex; gap: 1.5rem; text-align: center;">\n <div style="background: #090d16; padding: 0.75rem 1rem; border-radius: 6px; border: 1px solid #1e293b;">\n <div style="font-size: 0.7rem; color: #64748b; text-transform: uppercase;">Sim. Throughput</div>\n <div id="simThroughput" style="font-size: 1.2rem; font-weight: bold; color: #f97316;">' + cards.throughput.toFixed(0) + '/s</div>\n </div>\n <div style="background: #090d16; padding: 0.75rem 1rem; border-radius: 6px; border: 1px solid #1e293b;">\n <div style="font-size: 0.7rem; color: #64748b; text-transform: uppercase;">Sim. Latency</div>\n <div id="simLatency" style="font-size: 1.2rem; font-weight: bold; color: #10b981;">' + cards.ttfb.toFixed(1) + "ms</div>\n </div>\n </div>\n </div>\n </div>";
|
|
510
|
+
const rightSizingHtml = '\n <div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">\n <h3 style="color: #38bdf8; display: flex; align-items: center; gap: 0.5rem; font-size: 1.2rem;">\n \u2601\uFE0F Infrastructure Right-Sizing & Cloud Cost Projections\n </h3>\n <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-top: 1rem;">\n <div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">\n <div class="card-title">Est. Monthly Cloud Cost</div>\n <div class="card-value green">$' + estimatedMonthlyCost + ' <span class="unit">/mo</span></div>\n </div>\n <div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">\n <div class="card-title">Recommended CPU Right-Sizing</div>\n <div class="card-value purple">' + recommendedCpuCores + ' <span class="unit">vCores</span></div>\n </div>\n <div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">\n <div class="card-title">Recommended Memory Allocation</div>\n <div class="card-value orange">' + recommendedRamGb + ' <span class="unit">GB RAM</span></div>\n </div>\n </div>\n </div>';
|
|
511
|
+
const htmlContent = '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Blaze Core Performance Report</title><script src="https://cdn.jsdelivr.net/npm/chart.js"></script><style>body { font-family: sans-serif; background: #0b111e; color: #f8fafc; margin: 0; padding: 2rem; }.container { max-width: 1300px; margin: 0 auto; }.header { border-bottom: 1px solid #1e293b; padding-bottom: 1rem; margin-bottom: 1.5rem; }h1 { color: #38bdf8; margin: 0; font-size: 2rem; }.cards-wrapper { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-bottom: 1.5rem; }.metric-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 6px; padding: 1.25rem; }.card-title { font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase; margin-bottom: 0.5rem; }.card-value { font-size: 1.6rem; font-weight: 700; color: #ffffff; }.card-value.green { color: #10b981; }.card-value.orange { color: #f97316; }.card-value.purple { color: #a855f7; }.card-value.cyan { color: #38bdf8; }.top-layout-grid { display: grid; grid-template-columns: 1fr 400px; gap: 1.5rem; margin-bottom: 2rem; }.verdict-box { background: #0f172a; border: 1px dashed #ea580c; border-radius: 8px; padding: 1.25rem; }.charts-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.5rem; margin-bottom: 2rem; }.graph-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.5rem; }.card { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.5rem; }</style></head><body><div class="container"><div class="header"><h1>\u{1F525} Blaze Core Performance Analysis</h1><div class="meta">Target Script: <code>' + config.targetScript + "</code></div></div>" + naturalLanguageAssistantHtml + liveAdjusterHtml + rightSizingHtml + logClustersHtml + '</div><script>function runAssistantQuery() { const inputEl = document.getElementById("assistantInput"); const containerEl = document.getElementById("assistantResponseContainer"); const textEl = document.getElementById("assistantResponseText"); const query = inputEl.value.toLowerCase().trim(); if (!query) return; let answer = "Telemetry verified successfully."; textEl.innerHTML = answer; containerEl.style.display = "block";}</script></body></html>';
|
|
828
512
|
try {
|
|
829
513
|
fs.writeFileSync(config.outputHtml, htmlContent, "utf-8");
|
|
830
|
-
console.log(
|
|
514
|
+
console.log("\u{1F4CA} Standalone Dashboard exported successfully to: " + path.resolve(config.outputHtml));
|
|
831
515
|
} catch (err) {
|
|
832
|
-
console.error(
|
|
516
|
+
console.error("\u274C Failed to write HTML output dashboard: " + err);
|
|
833
517
|
}
|
|
834
518
|
}
|
|
835
519
|
function printUsage() {
|
|
836
|
-
console.log(
|
|
837
|
-
Options:
|
|
838
|
-
--threads <count> | --duration <seconds> | --agentic | --cluster-logs | --correlate`);
|
|
520
|
+
console.log("Blaze Core Performance Test CLI Engine\nOptions:\n --threads <count> | --duration <seconds> | --agentic | --cluster-logs | --correlate");
|
|
839
521
|
}
|
|
840
522
|
main().catch(console.error);
|
|
Binary file
|