GrepBoardLog

Drop log files anywhere

Files, whole folders and .gz archives. Or press Ctrl+V to paste text.

Custom and unknown log formats

Application logs rarely follow a standard. The board still needs to know which part of a line is the time, which is the status or level, and which is a duration. This page explains how that is worked out, and how you correct it when the guess is wrong.

Everything happens in the browser. A saved format is a "recipe": parsing rules only, never log lines.

Logs that need no setup

Known formats are recognised from the first lines: nginx, Apache, HAProxy. Two generic shapes are read directly too:

{"ts":"2026-10-18T10:02:03Z","level":"error","route":"/api/upload","status":504,"duration_ms":60001}
ts=2026-10-18T10:02:03Z level=error method=POST path=/api/upload status=504 duration_ms=60001

In JSON lines and key=value logs every key becomes a field (for JSON, nested keys one level down too, as a.b). Common key names set the role: time, ts, @timestamp โ†’ time; status, status_code โ†’ status; level, severity โ†’ level; path, url, route โ†’ path; duration, duration_ms, latency, request_time โ†’ latency; msg, message โ†’ message. Other keys are typed from their values: timestamps, numbers or categories.

The Format tab: split, then label

For anything else, open the Format tab. Take this Java-style line:

2026-10-18T10:02:03.120Z ERROR [http-nio-8080-exec-7] c.e.UploadController - upload failed: timeout after 60000 ms
  1. The first lines are split into fields on spaces, quotes, brackets, key=value pairs and JSON. The split is shown as a colour band over the first line.
  2. Each field gets a guessed kind: ISO 8601, epoch or syslog timestamps, IP address, HTTP status, duration (123ms, 0.412, 1.2s), level, number, path or plain text.
  3. Click a field to set or change its role: time, status, path, latency, level, user, value, or ignore.
  4. Apply. The cards follow the roles: a time field gives the timeline and heat map, a status or level gives error rates, numbers give distributions and percentiles, categories give top lists, and free text is grouped into message patterns with numbers and ids masked.
  5. Save it as a recipe so the next file of the same kind is read the same way.

In the example, the time, the level ERROR, the thread in brackets, the logger name and the message are found as separate fields. Marking the level as "level" is usually the only click needed.

Paste a format definition

If you have the line that produced the log, it describes the layout exactly. Paste it in the Format tab under "Paste a format definition" and apply:

# nginx
log_format timed '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_time';
# Apache
LogFormat "%h %l %u %t \"%r\" %>s %b %D" timed
# HAProxy
log-format "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %tsc"

Variables map to roles directly: $request_time, %D and %Ta are latencies (in seconds, microseconds and milliseconds), $status, %>s and %ST are statuses, $time_local, %t and %tr are times. A format with extra fields in the middle โ€” a virtual host, a request id, an upstream address โ€” parses without any labelling.

Regular expressions with named groups

For layouts that splitting cannot handle, write a regular expression with named groups in the Format tab. Each group name is the field name and, when it matches a role, its role:

^(?<time>\S+) (?<level>[A-Z]+) \[(?<thread>[^\]]+)\] (?<logger>\S+) - (?<message>.*)$

Group names such as time, status, level, path and latency take that role automatically; other names become plain fields.

Recipes: saved locally, shared as a file

  • A recipe holds the split rules, field names and roles. It never holds log lines.
  • Recipes are saved in this browser's local storage. They do not leave the machine and are not tied to an account โ€” there are no accounts.
  • Export a recipe as a small JSON file and send it to a colleague; they import it in the Format tab. The page itself never uploads it.
  • Or share it as a link: the recipe is compressed into the part of the address after #, which browsers never send to a server. Opening the link adds the recipe in that browser, with no request.
  • A saved recipe is applied automatically when a dropped file looks like it: same splitting, same number of fields, and a time field that parses.
  • Clearing site data in the browser removes saved recipes. Keep the exported file if a recipe matters.

Shell one-liners for key=value and JSON lines

When there is no jq on the box, grep and cut go a long way on structured lines. Tested on small key=value and JSON-lines samples:

  • key=value: count per status.

    grep -oE 'status=[0-9]+' app.log | sort | uniq -c | sort -rn
  • key=value: three slowest requests by duration_ms.

    awk '{delete f; for (i = 1; i <= NF; i++) {split($i, kv, "="); f[kv[1]] = kv[2]} print f["duration_ms"], f["path"]}' app.log | sort -rn | head -3
  • JSON lines: count per level.

    grep -oE '"level":"[a-z]+"' app.jsonl | sort | uniq -c | sort -rn
  • JSON lines: count per route value.

    grep -oE '"route":"[^"]*"' app.jsonl | cut -d'"' -f4 | sort | uniq -c | sort -rn

These only work when keys and values are on one line and the value has no escaped quotes. For nested JSON, use the board or jq.

FAQ

Can I analyze a log format that is not listed?

Yes, if it has one record per line. JSON lines and key=value logs work directly; other layouts go through the Format tab, where you check the split and mark which field is the time, status, path or latency.

Are my recipes uploaded?

No. Recipes are saved in your browser's local storage and exported as a file you choose to send. The page cannot make network requests, so it could not upload them even if it tried.

What if a line spans several lines, like a stack trace?

Lines that do not start with a timestamp belong to the line before them. Tick "Join continuation lines" in the Format tab to group them into one record; otherwise each line is counted on its own.

Can I paste an nginx log_format to define the format?

Yes. Paste the log_format, LogFormat or log-format line in the Format tab and the fields are named and typed from the variables.

Which regex syntax is accepted?

Named groups in the (?<name>โ€ฆ) form. The group name becomes the field name, and names such as time, status, level, path and latency also set the role.

Does it work for CSV or TSV?

A delimiter-separated file splits cleanly into fields in the Format tab. Label the columns once and save the recipe.

๐Ÿ”’ Nothing leaves your browser.

Your logs are parsed and counted right here, on your machine.