# Format and filter structured JSON logs

Pretty-print JSON log lines, flatten nested fields, filter by level or field, and export readable logs as text, table, JSON, or CSV.

## Run it

- **CLI:** `gizza tool json-log-formatter '{"time":"2026-08-08T12:00:00Z","level":"info","msg":"server started","port":8080}
{"time":"2026-08-08T12:00:09Z","level":"error","msg":"db timeout","req":{"method":"GET","url":"/api"}}'`
- **Web:** https://gizza.ai/tools/json-log-formatter/
- **Agents:** machine-readable descriptor (parameters JSON Schema) at https://gizza.ai/tools/json-log-formatter/tool.json

## Inputs

- `input` — JSON log lines _(field)_
- `level` — Minimum level _(field)_
- `field` — Field to filter (optional) _(field)_
- `filter` — Filter text _(field)_
- `match` — Filter match _(field)_
- `fields` — Columns/fields to keep _(field)_
- `level_field` — Level field override _(field)_
- `time_field` — Time field override _(field)_
- `message_field` — Message field override _(field)_
- `flatten` — Flatten nested objects to dotted fields _(field)_
- `on_invalid` — Invalid lines _(field)_
- `limit` — Maximum records _(field)_
- `output` — Output _(field)_

## Output

- Formatted logs (text)

## Query parameters

Open the tool pre-filled and auto-run via URL:

- `input` — JSON log lines
- `level` — Minimum level
- `field` — Field to filter (optional)
- `filter` — Filter text
- `match` — Filter match
- `fields` — Columns/fields to keep
- `level_field` — Level field override
- `time_field` — Time field override
- `message_field` — Message field override
- `flatten` — Flatten nested objects to dotted fields
- `on_invalid` — Invalid lines
- `limit` — Maximum records
- `output` — Output

Example: `https://gizza.ai/tools/json-log-formatter/?input=%7B%22time%22%3A%222026-08-08T12%3A00%3A00Z%22%2C%22level%22%3A%22info%22%2C%22msg%22%3A%22server%20started%22%2C%22port%22%3A8080%7D%0A%7B%22time%22%3A%222026-08-08T12%3A00%3A09Z%22%2C%22level%22%3A%22error%22%2C%22msg%22%3A%22db%20timeout%22%2C%22req%22%3A%7B%22method%22%3A%22GET%22%2C%22url%22%3A%22%2Fapi%22%7D%7D&level=all&field=req.method&filter=timeout&match=contains&fields=time%2Clevel%2Cmsg%2Creq.method%2Creq.url&level_field=severity&time_field=%40timestamp&message_field=message&flatten=true&on_invalid=skip&limit=200&output=pretty`

---

## About this tool

`json-log-formatter` is for NDJSON or JSON Lines logs: one JSON object per line. It turns dense structured logs into an aligned view such as `[time] LEVEL message key=value`, or exports the same filtered records as a Markdown table, JSON array, or CSV.

It auto-detects common timestamp, level and message keys (`time`, `ts`, `@timestamp`, `level`, `severity`, `msg`, `message`) and can flatten nested context into dotted fields like `req.method` and `user.id`. Use the field filter to keep only records where a path contains or exactly equals a value, or leave the field blank to search the whole record.

The level filter understands words (`info`, `warning`, `error`, `critical`) plus common numeric conventions: bunyan/pino-style `10` through `60`, and syslog priorities `7` through `0`. Unknown custom level words still render; they sort like `info` for minimum-level filtering.

### Limits and edge cases

- Input must be line-delimited JSON objects. A JSON array line is invalid for this tool.
- Blank lines and lines starting with `#` or `//` are skipped.
- `limit` renders at most 5,000 records after filtering; the default is 200.
- Invalid JSON lines can be skipped, kept as raw message lines, or treated as errors with line numbers.
- This is not a full jq expression engine; use `field`, `filter`, `match`, and `fields` for focused log triage.

## FAQ

<details>
<summary>What log formats does this accept?</summary>

It accepts NDJSON/JSONL: one JSON object per line. That is the common output from structured loggers. It does not parse syslog text, logfmt, Apache logs, or a single JSON array document.

</details>

<details>
<summary>How do I filter for only errors?</summary>

Set `level` to `error`. The tool keeps records whose detected level is error or fatal. Numeric levels are mapped automatically for common bunyan/pino and syslog conventions.

</details>

<details>
<summary>Can I filter a nested field?</summary>

Yes. Keep `flatten` enabled and set `field` to a dotted path such as `req.method`, `user.id`, or `items.0.status`. Use `match=contains` for case-insensitive substring search or `match=exact` for an exact value.

</details>

<details>
<summary>What happens to bad lines in a mixed log file?</summary>

The default `on_invalid=skip` skips them and adds a count notice to text outputs. Choose `keep` when you want raw non-JSON lines to remain visible, or `error` when a malformed line should fail the run and report its line number.

</details>

## Related tools

- [JSONL stats](https://gizza.ai/tools/jsonl-stats/): Summarize JSON Lines records: record count, per-key coverage, value-type distribution, distinct counts, samples, and numeric/string stats.
- [NDJSON to matrix](https://gizza.ai/tools/ndjson-to-matrix/): Turn NDJSON / JSON Lines records into one aligned table: unified columns from dotted paths, chosen fill for missing cells, CSV, TSV, matrix or JSON out.
- [CSV timeline viewer](https://gizza.ai/tools/csv-timeline-viewer/): Paste a CSV, TSV or JSON Lines event log and filter it by time range, search every column, sort, pick columns and page through the matches locally.
- [Identify a data sample's format, delimiter and columns](https://gizza.ai/tools/data-format-sniffer/): Paste a data sample and find out what it is: CSV, TSV, JSON, JSON Lines, XML, HTML, fixed-width or binary, plus delimiter, quote char, encoding and column types.
- [Elasticsearch Bulk Formatter](https://gizza.ai/tools/elasticsearch-bulk-formatter/): Build a compact Elasticsearch _bulk API body from a JSON array. Choose index/create/update/delete, _index, _id field, and doc_as_upsert locally.
