> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sreagent.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Read JSON logs as fields in the live stream and the Explorer

> See a JSON log line as its message and fields, filter by clicking a field in the live stream or the Explorer, and choose which fields a service shows inline.

export const Plan = ({tier}) => <Badge color="blue">{tier} plan</Badge>;

A log line that is one JSON object is shown as a time, a level, a message and a few key fields, and opening it lists every field. **Show only** and **Hide** on a field turn it into a filter. The live stream and the Logs tab of the [Explorer](/guides/respond/explore) read lines the same way, with every value redacted before it is shown.

<Plan tier="Business" />

## Where it works

* **The live stream.** Click **Explore** in the sidebar. It opens a tail of the logs your sources can serve, with the newest lines on top. It reads Loki, Datadog logs and CloudWatch Logs. Filter by service, source, level and text, and use **Pause** and **Resume** to hold it still. A stream ends after your plan's session length, 30 minutes by default, and a banner five minutes before the end offers **Keep tailing**. A stream with a service chosen has **Open in Explorer**.
* **The Explorer's Logs tab.** Open a service in the Explorer and choose **Logs**. CloudWatch Logs Insights, Loki and Datadog logs rows are shown as lines with fields. A result table, such as an aggregation, stays a table, with each cell redacted and no field actions. A Loki metric query is shown as redacted text.

A line that is not one JSON object stays text: an object behind a prefix, such as a Lambda `START RequestId` line, logfmt, an array or malformed JSON.

## Read a JSON line

A collapsed line shows the time, the level, the source, the message and up to three inline fields. Click it to open the line.

* **Fields.** The open line lists every field, with links for a trace id. A nested object becomes dotted keys, such as `http.request.method`, down to four levels, and a deeper object is one field holding its JSON. An array is one field. A line keeps at most 50 fields: the message, level, time, trace id and request id first, then the rest in the object's order. It says "12 more fields are in Raw" for the rest. Keys are cut to 128 characters and values to 8,192, with ` [cut]` marking a cut value.

* **Raw.** Click **Raw** to swap the field list for the whole redacted line, and click it again to go back. An open line and its Raw view stay as they are while new lines arrive.

* **Message, level, time and ids.** These keys have a role, matched without regard to case:

  | Role | Keys |
  | - | - |
  | Message | `message`, `msg`, `log` |
  | Level | `level`, `severity`, `lvl` |
  | Time | `time`, `timestamp`, `@timestamp` |
  | Trace id | `trace_id`, `traceId`, `trace.id`, `dd.trace_id` |
  | Request id | `request_id`, `requestId`, `req_id`, `x_request_id` |

  The level comes from the source's own level field first, then the level key. The numbers pino and bunyan write are read as 10 and 20 debug, 30 info, 40 warn and 50 and 60 error, on the level key only. The time key is shown as a field and never replaces the source's own timestamp, so a wrong clock inside a line cannot reorder the page. A line with no message key shows its first 240 characters.

* **Inline fields.** By default the three inline fields are the trace id and the request id when the line has them, then the first other fields in the line's order. [Choose your own per service](#choose-the-fields-shown-inline).

### Redaction

Every key and value is redacted before it reaches your browser. A value is masked by its key when the key says it holds a credential, such as `password`, `api_key` or `Authorization`, whatever the value looks like, and a key like that masks its whole subtree. An entry whose `name` or `key` sibling names a credential has its `value` masked too, for example `{"name":"DB_PASSWORD","value":"x"}`.

When anything in a line was masked, the line and **Raw** show the object re-encoded with the masks, and **Raw** says "Reformatted, secrets masked". A line that masked nothing is shown exactly as it arrived. The text filter matches what is shown, so a reformatted line is matched as compact JSON.

### The per-line limit

Only the first 64 KiB of a line is read. A JSON line longer than that, in the stream and in the Explorer, is never shown as text. It shows **JSON line not read: it is too large to read here.** with no text and no control, because redacting text alone can miss a secret named by a sibling field. A longer line that is not JSON keeps its truncated, redacted text.

## Filter by clicking a field

On an open line, a field that can be filtered on has **Show only** and **Hide**.

* **Show only** keeps the lines whose value for that field equals the one you clicked. A second **Show only** on the same key replaces the first.
* **Hide** drops the lines with that value. You can hide several values of one key.

Neither is offered for a value that was redacted, cut or null, or for a value over 1,024 bytes. A filter on a hidden value is refused with "A hidden value cannot be used as a filter." Each filter shows as a chip such as `level = error` or `level != debug` that removes itself when clicked, and a sentence beside the chips says what is shown.

### In the live stream

Filters narrow the stream at once, on the page, against the redacted line. They are never sent to a source. At most 8 filters can be set. They are kept in the address, so a link shares them. While a filter is set, the stream shows matching lines only.

### In the Explorer

A click writes one clause into the query, in the source's own language, and runs it again. The clause is composed through the source's query model, so a value with a quote, a backslash or a pipe cannot leave its string.

| Source | **Show only** and **Hide** write |
| - | - |
| CloudWatch Logs Insights | `filter key = "v"` or `filter key != "v"`. A number is written bare, as `filter key = 500` or `filter key != 500`. A dotted key is written in backticks. |
| Loki | A JSON field adds `\| json` and a label filter, `name="v"` or `name!="v"`, after the pipeline. A number is written `name == 500` or `name != 500`. A stream label is also a label filter after the pipeline, not a selector matcher. |
| Datadog logs | The term appended to the parenthesised query, `(query) @key:"v"` or `(query) -@key:"v"`. The attributes `service`, `host`, `source`, `status`, `trace_id` and `message` are written without the `@`, and the level is `status`. A number, `true` or `false` is written bare. |

Loki names a JSON key the way its `json` parser does: nested keys joined with `_`, and `<name>_extracted` when a stream label already has the name.

**Hide on CloudWatch keeps events that lack the field.** Logs Insights treats a missing field as not equal to any value, so `filter key != "v"` removes the events whose `key` is `v` and keeps every event with no `key` at all. To drop those too, add `filter ispresent(key)` to the query yourself.

Two notes appear beside the chips when they apply. On CloudWatch: "Logs Insights reads at most 200 fields of a JSON event; a filter on a field past that finds nothing." On Datadog, with a number: "Datadog searches a number through a facet only; add a facet for @key if nothing comes back."

**When a source cannot hold the value.** The Explorer then filters the rows it already loaded, sends nothing, and the chip says "Filtered in the loaded rows only" with the reason. The cases are:

* **Any source.** The query was edited in code and has no place for a clause, or the value has a control character such as a new line.
* **CloudWatch Logs Insights.** The value is a boolean, an object or a list, is over 1,000 characters, or is a number Insights reads only in code, such as `1e5`. The key starts with `@` or a path segment holds a dot. The query already has 20 filters.
* **Loki.** The query is a metric query or reads its lines as logfmt. The field is an object or a list. The name is not a Loki label name. The query already has 64 label filters.
* **Datadog logs.** The field was read from the message text rather than from the attributes Datadog extracted itself. The name is not a Datadog attribute name. The query would pass 16,384 bytes.

A source chip stays while the query text is the text it composed. Removing it removes its clause and runs the query again. Typing in the query, the Builder, a reset or a change of source or scope drops the source chips. Loaded-row chips stay until the scope, the source or a reset changes.

### The Explorer's row limits

The Logs tab reads up to 10,000 rows and shows at most 1,000 of them after its filters, with "Showing the first 1000 of N rows. Narrow the query or the filters to see the rest." when it cuts. The **level** and **text** boxes narrow the loaded rows.

Reading a line's fields costs far more than reading its text, so one answer has a budget. Lines are read newest first until it is spent. For the default 1,000 rows of an ordinary service the budget is not reached. When it is, the page says "Fields shown for the first N lines. The answer is larger than one view reads in full; narrow the query to see fields on every line." A text line after that is shown as redacted text without fields, cut at 2,048 bytes. A JSON line after that is never shown as text. It shows **JSON line not read: this answer's field budget is spent.** with **Read this line**. Click it to read that one line, masked exactly as the lines within the budget. A line past the 64 KiB limit, or one the page can no longer hold, shows the "too large to read here" sentence and has no button.

Lines the page already holds are kept, so **Load more**, **Show only** and **Hide** read only the rows they did not have.

## Choose the fields shown inline

An organization admin can choose the fields a service shows inline, for the stream and for the Explorer.

<Steps>
  <Step title="Open the service">
    Open the service from **Services**, or click **Choose inline fields** on the live stream (once a
    service is chosen) or on the Explorer's Logs tab (with a service in scope). It takes you to the
    section.
  </Step>

  <Step title="Name up to three fields">
    In **Log fields shown inline**, under **Telemetry**, type up to three keys in the boxes **Field
    1**, **Field 2** and **Field 3**, as an opened line lists them: `user.id` for a nested field.
  </Step>

  <Step title="Save">Click **Save inline fields**.</Step>
</Steps>

The fields show in that order on every line of the service, for every environment. A key is 1 to 128 characters with no control character, and each key can be named once. Leave the boxes empty to return to the built-in choice. A key that a line does not have is skipped for that line. Members and viewers can read the choice and cannot change it. The section needs the Business plan, like the rest of the service's telemetry.

The same choice is available over MCP, as `log_inline_fields` on `set_service_binding` (an array of at most three keys; leaving it out keeps the stored value, and `null` or `[]` clears it), and through the `service_bindings` resource of the configuration API. A binding for one environment refuses it: inline fields are set for the whole service. A save is audited as `service_telemetry_binding.updated`.

## Related

* [Explore logs, metrics and traces](/guides/respond/explore): the Explorer's scope, tabs, Builder and Code modes.
* [Find and manage your services](/guides/get-started/services): the service page, and where telemetry is bound to a service.
* [Connect your data](/guides/get-started/connect-your-data): connect the Loki, Datadog and CloudWatch sources the stream reads.
* [MCP tools](/api-reference/mcp): how to connect a client.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.