Living dev note. Iterate freely.
The dashboard also needs queue visualization — see Queues for the sidebar, queue detail, and overlap views.
The dashboard needs to render logs for several distinct surfaces:
- An exec — bash command output (one-shot or streaming).
- A run / job —
@dls.udfinvocation: stdout/stderr + Python tracebacks. - A session — interactive REPL output (live tail).
- A daemon itself — nymph's own logs (runtime, errors, config).
- A provider — cloud launch / instance provisioning logs.
These are different sources of truth. The UI should treat the log view as a generic byte renderer and let the controlplane (or a small adapter layer) resolve which source backs each view.
Pluggable log sources
| Source | Where bytes live | Reachability | Latency to render |
|---|---|---|---|
| Stream subscriber (Tier 1 — Log storage) | controlplane-owned Redis Streams, fan-out to consumers | only while exec/session active | ~ms |
| Daemon ring buffer | nymph in-memory, last ~64KB | only while daemon up; pull-on-demand via controlplane | one poll round-trip (~25s today, ~ms after wake-up) |
| Controlplane archive (Tier 2 — Log storage) | S3 (default with CP-mediated upload) or mongo for small payloads | always, as long as not GC'd | ~50ms (mongo) / ~200ms (S3 presigned GET) |
| Out-of-band shipper (CloudWatch / vector / journald) | external system | always | depends on system |
| SSH to host | files on the VM | requires SSH access from operator | seconds |
Each surface picks the right source based on:
- Is the producer active right now (stream) vs historical (archive)?
- Does the daemon have egress (S3-direct OK) vs no (must go through CP)?
- Is the volume small (fits in mongo) vs large (needs S3)?
- Does the user want live tail or just enough context to debug?
UI shape
One reusable component: <LogView>.
Routes that mount it:
The component itself doesn't know what backs the source — it talks to one controlplane endpoint that abstracts:
The dashboard fetches once and picks transport based on the returned shape (URL → direct fetch; cursor → poll; SSE stream → consume).
Useful UX details
- Auto-scroll to tail by default, but pin off on user scroll (matches journalctl + every IDE log viewer).
- Search across visible buffer — Cmd-F binding. No server-side search at v1.
- ANSI color rendering. Many of our outputs come from pytest / cargo / pip — they have meaningful escape codes.
- Timestamps optional — toggle in the toolbar. Default off because bash exec doesn't emit them; nymph logs do.
- Permalink to a line range —
#L100-L120anchor. Lets users paste a link to a specific failure in a chat message. - Download as
.log— for archived sources, this is just a redirect to the presigned URL. For streams, snapshot the current buffer.
What ships first
In order:
/runs/:idarchive view. This is the most common debugging need today (UDF dispatches fail; users want stack traces). Backed by the existing exec-result blob in mongo. Renders ANSI, no live stream needed for v1./workers/:id/logringbuf view. Pull on demand via a new controlplane endpoint that asks the daemon "give me your last 64KB" — answered on the next poll. Useful for "is this daemon OK?" debugging without SSHing./execs/:idstream view. Depends on the streaming wire from Log storage (Tier 1). Real-time tail of an active exec./sessions/:idstream view. Depends on Sessions + the stream wire. Full interactive view.
(1) is dashboard-only work; (2) needs a tiny daemon-side ringbuf
endpoint; (3) and (4) wait for the streaming wire.
What does NOT ship
- Server-side full-text search across all logs. Use grep on the
downloaded
.logfor v1. Bring it back when a user actually asks. - Forwarded retention policies (compliance, GDPR-style log expiration). When that customer comes, build it; not before.
- Cross-job log correlation (Datadog / Honeycomb style). External observability tool's job, not the dashboard's.
Open
- Mobile rendering. Log views suck on phones; do we even bother? Probably "scrollable list of failed jobs" works for triage and the full log opens a separate full-screen view.
- Live multi-tail. Combined view of N execs streaming concurrently. Useful for fleet debugging but adds protocol complexity. Defer.