Logs
The log stream opens application logs, access logs, audit trails and build output in the page — from a file the user drops, a URL, a stream, or lines your application appends as they happen — and makes them searchable at once. Nothing is uploaded and there is no log server: the lines stay on the machine that opened them.
It reads JSON lines, logfmt, syslog, Apache and Nginx access logs, CSV and TSV and plain
text, finds the level and the time in every line, keeps each stack trace with the entry it belongs to,
and draws terminal colours as colours. Search with words, "phrases", /regular expressions/
and fields — status:>=500, level:>=warn, -healthcheck
— and every match is highlighted.
Masking hides email addresses, IP addresses, card numbers, tokens and keys on screen, in
search and in every export, so a support engineer can read a customer's log without reading the
customer. Lines are always drawn as text, never as markup: a log that carries
<script> shows it and runs nothing.
An incident, two hundred thousand lines
A day of a checkout service's log, made up in this page: requests, background jobs, a database pool that runs dry just after two o'clock, and the stack traces that follow. Press a query below, or type your own. The timeline over the lines shows the errors piling up: drag across the red to show only that half hour, and Zoom out to go back. Click a level chip to hide that level. Select a line and press Enter to see its fields; press M to bookmark it. A stack trace folds away with the arrow beside it. Export saves what is on show as text, CSV or JSON.
Fields come from the line itself. In a JSON line they are its properties; in logfmt and
plain text, its key=value pairs; in an access log, the method, path, status and size; in a
CSV file, its columns. status:>=500 compares numbers, path:/api/* matches a
pattern, user:* finds the lines that have a user at all.
A link reopens the view. The search, the levels, the time range, the bookmarks and the
chosen line are one short string: await log.getState(), and log.setState(text)
to open it again. This page keeps it in its address as you work, so a copied link, or a reload, comes
back to exactly what you were looking at.
Fields and columns
Six hours of an API gateway's JSON log, thirty thousand lines, laid out as columns. The fields panel on
the right lists every field with its commonest values: choose ap-south-1 under
region to see that one region's errors, or the minus beside a value to leave it out. The
column button beside each field adds it to the table or takes it away.
Counted in the page. The values are counted over the lines on show, so they follow the search and the time range; past twenty thousand entries a sample spread through them is counted instead, and the panel says so. Values that masking would hide are never listed.
A live tail
Lines your application appends as they arrive — from a WebSocket, server-sent events, a build that is still running. With Follow on, the newest line stays in view; scroll up to read and it stops, and a button counts what has arrived since. The search and the level chips apply to new lines as they come in. This one keeps the latest twenty thousand lines and drops the oldest.
A socket in one line. log.connect('wss://your-host/logs') follows a
WebSocket, and an https: URL is read as server-sent events; the connection is opened again
when it drops, after one, two, four seconds and so on, and the status bar shows where it stands. Or append
lines yourself: await log.appendLog(text) takes a chunk of text or an array of lines. Listen
for bmxLogFilter to count matches as they arrive — to raise your own alert on the fifth
error in a minute, say.
Every format, read on sight
The same viewer, six kinds of log. Nothing tells it which is which: it reads the first lines and
decides. Levels come from a JSON level, a syslog priority, an access log's status or a
word in the text; times from ISO dates, epoch numbers, syslog and access-log stamps. Build output keeps
its terminal colours.
Masking personal data
An audit trail with customers' email addresses, their IP addresses, a card number that should never
have been logged, a bearer token and an API key. With masking on, none of them is shown, found by a
search or written to an export; the rest of each line reads as before. Turn it off to compare, then
search for @example with it on and off.
Your own rules too. redact="email card" chooses among the built-in rules;
redactRules adds your own — an account number, a patient reference — as a
regular expression and the mask to put in its place. Card numbers are masked only when they pass the
Luhn check, so an order number of the same length is left alone.
A million lines
Press the button to make a million lines of JSON in this page and open them. Lines are stored
compactly and only the rows in view are drawn, and reading and searching run in slices between
frames, so the page keeps responding throughout — type a search while it is still reading.
A .gz file dropped on any of these viewers is unpacked as it is read.
Press Open a million lines, or drop a log file here.