Diagnostics logger
src/diag/logger.ts is a self-contained, in-app log capture and viewer. It
exists because browser DevTools choke when the app emits hundreds of thousands
of repeated WebGL errors per second: the in-app logger dedupes and rate-limits
so the stream stays readable.
It is imported first in main.ts so that boot-time errors are captured.
What it does
- Patches the console: wraps
console.log/info/warn/error/debugto fan out to both the real console (rate-limited) and an in-memory ring buffer. The originals are preserved onconsole.__original. - Captures global errors: listens for
errorandunhandledrejection. - Dedupes: identical messages collapse into a single row with a count, so a per-frame error firing 60 times a second shows as one entry with a rising count rather than thousands of lines.
- Rate-limits the native console: identical messages pass through to the
real console at most once per
RATE_LIMIT_MS(250 ms). - Renders a floating panel: with copy, download, clear, and pause controls.
Internals
const RING_LIMIT = 2000 // max entries kept in memory
const RATE_LIMIT_MS = 250 // throttle for the native console pass-through
const FLUSH_INTERVAL_MS = 100 // panel re-render cadence
Entries are stored in a ring array capped at RING_LIMIT, with a dedupe map
keyed by level + '|' + message. When the ring overflows, the oldest entry is
evicted from the ring, the dedupe map, and the lastNativeFlush map so none
of the bookkeeping maps grow unbounded. The panel re-renders on a 100 ms
timer only when something is dirty.
The panel
Toggle the panel with the small button in the bottom-right corner, or press
Ctrl + Shift + L. The panel offers:
- Copy: copy the full dump to the clipboard.
- Download: save a
.logfile (namedexepert-brain-diagnostics-<ts>.log). - Clear: empty the buffer.
- Pause: stop capturing new entries.
The window.diag API
The logger exposes a small programmatic API on window.diag for app code that
wants to log explicitly or drive the panel:
;(window as any).diag = {
log: (msg, stack?) => record('log', msg, stack),
warn: (msg, stack?) => record('warn', msg, stack),
error: (msg, stack?) => record('error', msg, stack),
open: () => togglePanel(true),
close: () => togglePanel(false),
clear: clearAll,
dump: buildTextDump,
copy: copyAll,
download: downloadAll,
entries: () => ring.slice()
}
| Method | Action |
|---|---|
diag.log/warn/error(msg, stack?) | Record an entry at the given level. |
diag.open() / diag.close() | Show/hide the panel. |
diag.clear() | Empty the buffer. |
diag.dump() | Return the full text dump as a string. |
diag.copy() | Copy the dump to the clipboard. |
diag.download() | Download the dump as a file. |
diag.entries() | Return a copy of the ring buffer. |
Standalone build for the reference pages
The logger is also bundled as a standalone IIFE so the legacy reference pages
can include it via a plain <script src> tag. The bundling is done by
scripts/build-vanilla-logger.mjs and runs as part of dev and build. See
Reference Pages.