# logs

Timestamped log messages, one row per entry.

Telemetry table, so every query must filter by `dataset_rid`.

For how Nominal treats log data, see [Log](https://dev.nominal.io/platform/reference/glossary.md#log) in the glossary.

## Columns

| Column | Type | Nullable | Notes |
| --- | --- | --- | --- |
| `ts` | `TIMESTAMP` | No | Log time, nanosecond precision. |
| `message` | `VARCHAR` | No | The log text. |
| `channel` | `VARCHAR` | No | Channel the entry was logged to. |
| `args` | `MAP` | No | Structured fields recorded with the message. |
| `dataset_rid` | `VARCHAR` | No | Dataset the entry belongs to. Required in the `WHERE` clause. |
| `tags` | `MAP` | No | Key-value pairs recorded with the series. See [Filtering by tag](https://dev.nominal.io/sql-guides/writing-queries.md#filtering-by-tag). |

`args` holds the structured counterpart to `message`: the individual values a formatted log line was built from, where the producer recorded them separately. Index it by key like any other map.

## Examples

Read a dataset’s log in time order:

```sql
SELECT ts, channel, message
FROM logs
WHERE dataset_rid = '<dataset-rid>'
ORDER BY ts
LIMIT 500
```

Find entries mentioning a term. Matching is case-sensitive, so normalize if you need to:

```sql
SELECT ts, message
FROM logs
WHERE dataset_rid = '<dataset-rid>'
  AND UPPER(message) LIKE '%FAULT%'
ORDER BY ts
```

Filter on a structured field rather than the message text:

```sql
SELECT ts, message, args['severity'] AS severity
FROM logs
WHERE dataset_rid = '<dataset-rid>'
  AND args['severity'] = 'ERROR'
ORDER BY ts
```

Count entries per channel:

```sql
SELECT channel, COUNT(*) AS entries
FROM logs
WHERE dataset_rid = '<dataset-rid>'
GROUP BY channel
ORDER BY entries DESC
```

## Next steps

- [Function reference](https://dev.nominal.io/sql-reference/schema/function-reference.md): the available string functions.
- [Writing queries](https://dev.nominal.io/sql-guides/writing-queries.md): scoping and query patterns.
