Add live, colourised logs to the web UI (#38) #82

Merged
danny merged 1 commit from issue38_webui_logs into main 2026-07-09 17:11:46 +01:00
Collaborator

Closes #38.

A fixed-capacity, overwrite-oldest ring buffer in internal/log captures every log record's time/level/message alongside the normal stderr output (wraps the existing tint handler rather than replacing it, so stderr behaviour is completely unaffected). Only allocated when web_ui.enabled is true - a new web_ui.log_buffer_lines config field (default 1000) controls the size.

GET /logs is a normal session-gated page; GET /api/logs?since=<seq> returns only entries newer than the given cursor. The frontend polls every 2s tracking the highest seq it has rendered, matching this codebase's existing plain-polling convention (no WebSocket/SSE anywhere else here).

Colour comes from the frontend mapping each entry's level to a CSS class - not from trying to convert tint's ANSI codes to HTML, which has no stable format to parse. Auto-scrolls to follow new entries unless you've scrolled away from the bottom, with an explicit toggle.

internal/log stays at 100% coverage. make lint/make test both pass.

Closes #38. A fixed-capacity, overwrite-oldest ring buffer in `internal/log` captures every log record's time/level/message alongside the normal stderr output (wraps the existing tint handler rather than replacing it, so stderr behaviour is completely unaffected). Only allocated when `web_ui.enabled` is true - a new `web_ui.log_buffer_lines` config field (default 1000) controls the size. `GET /logs` is a normal session-gated page; `GET /api/logs?since=<seq>` returns only entries newer than the given cursor. The frontend polls every 2s tracking the highest seq it has rendered, matching this codebase's existing plain-polling convention (no WebSocket/SSE anywhere else here). Colour comes from the frontend mapping each entry's level to a CSS class - not from trying to convert tint's ANSI codes to HTML, which has no stable format to parse. Auto-scrolls to follow new entries unless you've scrolled away from the bottom, with an explicit toggle. `internal/log` stays at 100% coverage. `make lint`/`make test` both pass.
claude self-assigned this 2026-07-09 14:19:50 +01:00
Add live, colourised logs to the web UI (#38)
All checks were successful
CI / lint (push) Successful in 25s
CI / build (push) Successful in 27s
CI / lint (pull_request) Successful in 24s
CI / build (pull_request) Successful in 27s
CI / release (push) Has been skipped
CI / release (pull_request) Has been skipped
c7f3ad52d8
internal/log: a fixed-capacity, overwrite-oldest ring buffer captures
every log record's time/level/message in addition to, not instead of,
the normal stderr output - wraps the existing tint slog.Handler in a
bufferHandler rather than replacing it, so stderr behavior is unaffected
whether or not the web UI is enabled. Exposed via EnableBuffer(capacity)/
Entries(sinceSeq).

New web_ui.log_buffer_lines config field (default 1000) controls the
buffer size; only ever allocated when web_ui.enabled is true, so a
process that never enables the web UI pays no cost for this.

GET /logs is a normal session-gated page; GET /api/logs?since=<seq>
returns every entry newer than the given cursor (0 fetches everything
buffered) - the frontend polls this on a 2s interval, tracking the
highest seq already rendered so each poll only fetches new lines,
matching this codebase's existing plain-polling convention (no
WebSocket/SSE used anywhere else here).

Colour comes from the frontend mapping each entry's level to a CSS
class, not from trying to convert tint's ANSI terminal codes to HTML -
there's no stable, parseable contract for that text. Auto-scrolls to
follow new entries unless the viewer has been scrolled away from the
bottom, with a toggle to disable it entirely.

internal/log stays at 100% coverage; the pre-EnableBuffer nil state is
checked via a TestMain that runs before any other test can set the
process-global buffer, cleaner than a subprocess re-exec since nothing
here calls os.Exit.
claude requested review from danny 2026-07-09 14:20:01 +01:00
danny scheduled this pull request to auto merge when all checks succeed 2026-07-09 17:04:21 +01:00
danny approved these changes 2026-07-09 17:11:44 +01:00
danny left a comment

Looks good, works well. Approving.

Looks good, works well. Approving.
danny merged commit 97ee832d74 into main 2026-07-09 17:11:46 +01:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
keyop-go/nfq_forwarder!82
No description provided.