# Logs

> How OTLP log records are stored, which fields you can filter on, and how severity and bodies are handled.

Each OTLP `LogRecord` becomes one row:

| Field | From |
| --- | --- |
| `time` | `time_unix_nano`, else `observed_time_unix_nano`, else the time Pulse received it (milliseconds) |
| `observed` | `observed_time_unix_nano` |
| `sev`, `sevText` | `severity_number` (0-24) and `severity_text` |
| `body` | A string body as is; any other value as JSON |
| `service` | The resource attribute `service.name` (empty when absent) |
| `traceId`, `spanId` | Lowercase hex, empty when absent |
| `scope` | The instrumentation scope name |
| `resource`, `attrs` | Resource attributes and the record's own attributes |

## Severity

Filters use the OpenTelemetry severity numbers: `1-4` TRACE, `5-8` DEBUG, `9-12` INFO, `13-16` WARN, `17-20` ERROR, `21-24` FATAL. "Errors and worse" is `minSev: 17`. Records without a severity number have `sev` 0 and only match when you don't filter on severity.

## Searching

In Explore, or with `POST /api/v1/query` and `"signal": "logs"`, you can filter by:

- `service`: exact match on `service.name`
- `minSev`: the lowest severity number to include
- `contains`: a case-insensitive substring of the body
- `attrs`: exact matches on attributes, checked on the record first and then on the resource

Results are newest first, 200 by default and 1,000 at most, with a count per time bucket for the histogram. See [Explore and the query API](/docs/explore-and-query-api/).

## Keep secrets out

Pulse stores what you send. Don't log passwords, tokens or special-category personal data; scrub them in the Collector (the `attributes` or `transform` processors) before they leave your network.
