Collect browser-side worker round-trips, computation times, main-thread operations, and feature counts, batch them client-side, and expose as Prometheus histograms via a new POST /api/perf endpoint.
46 lines
1.1 KiB
TypeScript
46 lines
1.1 KiB
TypeScript
interface PerfSample {
|
|
metric: string;
|
|
operation: string;
|
|
value: number;
|
|
}
|
|
|
|
const FLUSH_INTERVAL_MS = 30_000;
|
|
let batch: PerfSample[] = [];
|
|
let flushTimer: ReturnType<typeof setInterval> | null = null;
|
|
|
|
export function record(metric: string, operation: string, value: number): void {
|
|
batch.push({ metric, operation, value });
|
|
}
|
|
|
|
function flush(): void {
|
|
if (batch.length === 0) return;
|
|
const blob = new Blob([JSON.stringify(batch)], { type: 'application/json' });
|
|
batch = [];
|
|
|
|
if (navigator.sendBeacon) {
|
|
navigator.sendBeacon('/api/perf', blob);
|
|
} else {
|
|
fetch('/api/perf', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: blob,
|
|
keepalive: true,
|
|
}).catch(() => {});
|
|
}
|
|
}
|
|
|
|
export function startCollector(): void {
|
|
if (flushTimer) return;
|
|
flushTimer = setInterval(flush, FLUSH_INTERVAL_MS);
|
|
document.addEventListener('visibilitychange', () => {
|
|
if (document.visibilityState === 'hidden') flush();
|
|
});
|
|
}
|
|
|
|
export function stopCollector(): void {
|
|
if (flushTimer) {
|
|
clearInterval(flushTimer);
|
|
flushTimer = null;
|
|
}
|
|
flush();
|
|
}
|