Logging
Debug logging is a framework capability. The worklet captures console output at startup into a bounded ring buffer, and the web layer can flush its own console output into the same buffer through the loopback ingest route.
Wire shape
Section titled “Wire shape”Entries are LogEntry:
{ seq: number, ts: number, level: 'debug'|'info'|'warn'|'error', source: 'backend'|'web', tag?: string, message: string }seq is a monotonic counter shared across every source, so read-back stays
ordered.
plugin events
Section titled “plugin events”logs.view({ tail?, level?, source? })→{ entries }— a small bounded window over the framed invoke (it must respect the header size cap).tailmust be a number; a non-numbertailor an unknownlevel/sourceis answeredPLUGIN_ERROR.logs.clear()→{ cleared }— empties the ring buffer.
import type { PluginBus } from '@ekrooh/bare/core';import { logEvents } from '@ekrooh/bare/plugins/logs/events';
declare const bus: PluginBus; // createPluginBus(messenger), see Transports
const [err, result] = await bus.invoke( logEvents.logs.view({ tail: 50, source: 'backend' }),);if (!err) console.table(result.entries);Loopback routes
Section titled “Loopback routes”Bulk read-back and ingest live on HTTP so there is no MAX_HEADER_BYTES
ceiling. The routes inherit the loopback server’s auth gate and single-server
rule:
GET /logs?tail=&level=&source=&format=jsonl|text— read-back (defaults to human-readable text;format=jsonlreturns newline-delimited JSON). This is the bulk path: atail,levelorsourceit cannot parse is ignored, so the read-back is unfiltered.POST /logswith{ entries: [...] }— ingest web/browser log batches. Every ingested entry is recorded assource: 'web'; only the worklet’s own console capture writesbackendentries.
Capture
Section titled “Capture”The worklet runtime installs a console seam at startup
(installConsoleCapture) that forwards to the originals while feeding the ring
buffer. Each captured backend message is capped at 16 KiB. Retention is a
consumer knob: the ring capacity is set via the logsCapacity runtime option
and the lowest recorded level via logsMinLevel. The console is patched once
per process and restored when the last runtime closes. A rotating file sink is an app decision and is
kept out of the framework.
The web layer can install installWebConsoleCapture, which buffers console
output and flushes it into POST /logs. Skip it in mock mode, where there is no
loopback backend to ingest into.
The log ring is readable by whoever holds the session: a route or handler that
fails is answered with a bare 500, but its cause (which can include an
exception message) is logged, and GET /logs shows it. Treat the ring as
diagnostics for the session holder, not as a place for secrets.