LogsViewer
Follow compute logs with ANSI colors, level filters, search, and a retention cap.
LogsViewer is a log pane that stays usable while output is still arriving. Rows are virtualized, so a long session scrolls at the same speed as a short one, and the viewer follows the tail until you scroll away from it.
Compute logs
StreamingBehavior
- The viewer follows new output while you sit at the bottom. Scrolling up detaches it and a pill reports how many lines arrived while you were reading; scrolling back to the bottom reattaches it.
- Only the rows in view are rendered, plus a small overscan, so 50,000 lines cost the same as 50.
maxLinescaps retention (5,000 by default) and the header states when the cap is trimming output.- ANSI escape codes render as color and weight through
anser. Text is parsed into spans, never injected as HTML. - Level filters, the time range, and search all compose. Search matches the timestamp, source, and the log text with escape codes stripped, so colored text stays findable.
- The time range (5 minutes to 24 hours) measures back from the newest line, not the wall clock, so a paused stream keeps showing the same window instead of draining as time passes. The control only appears when lines carry
at. - Scroll areas use the house scrollbar: thin, rounded, and transparent-tracked, on both axes. While the viewer is following, the scrollbar hides, since the thumb would report a position the reader does not control and would slide on every new line. It returns the moment you scroll and take over.
- Long lines scroll sideways inside the pane; the page never gains horizontal overflow.
Install
npx shadcn@latest add https://ui.neon.com/r/logs-viewer.json
Usage
import { LogsViewer } from "@/components/neon-ui/logs-viewer";
<LogsViewer lines={lines} isStreaming={isStreaming} title="Compute logs" />;
Wiring to Neon
useLogsStream reads a server-sent events endpoint that emits one JSON line per message:
const { lines, isStreaming, error } = useLogsStream({
endpoint: "/api/logs/stream?branch=br-main&compute=compute-0",
});
The endpoint belongs to the application. Neon credentials stay on the server, which also decides retention and who may read a compute’s output.
Line shape
interface LogLine {
id: string;
message: string;
level?: "debug" | "info" | "warn" | "error";
timestamp?: string;
at?: string;
source?: string;
}
timestamp is display-ready, so the application controls precision and time zone. Set at to the ISO timestamp to enable time-range filtering. message may contain ANSI escape codes.
Props
linesLogLine[]
Log lines, oldest first.
LogLine[]title?string
Heading and accessible name for the log region.
string"Logs"maxLines?number
Retention cap. Older lines are dropped.
number5000rowHeight?number
Row height in pixels, used for virtualization math.
number20visibleRows?number
Height of the pane, counted in rows.
number18follow?boolean
Controlled follow-tail state.
booleandefaultFollow?boolean
Initial follow state for uncontrolled usage.
booleantrueonFollowChange?(follow: boolean) => void
Fires when following starts or stops.
(follow: boolean) => voidquery?string
Controlled search text.
stringlevels?LogLevel[]
Controlled set of enabled levels.
LogLevel[]range?"all" | "5m" | "15m" | "1h" | "24h"
Controlled time range, measured back from the newest line.
"all" | "5m" | "15m" | "1h" | "24h"defaultRange?"all" | "5m" | "15m" | "1h" | "24h"
Initial range for uncontrolled usage.
"all" | "5m" | "15m" | "1h" | "24h""all"onRangeChange?(range: TimeRange) => void
Fires when the time range changes.
(range: TimeRange) => voidisStreaming?boolean
Marks the stream as live in the header.
booleanfalseisLoading?boolean
Renders the loading state.
booleanfalseerror?Error | string | null
Renders an error state instead of the pane.
Error | string | nullAccessibility
The pane is a log region with an accessible name, and it is focusable so keyboard users can scroll it. Search has a real label and a clear button. Level filters are pressed buttons inside a fieldset, and the time range uses the shared select, so its menu is keyboard driven and styled with the rest of the system. Level is carried by text as well as color. The follow pill states its purpose and the pending line count. The streaming dot and the pill entrance both stop under reduced motion.