docs: merge querying-supabase-logs into logs.mdx

Fold the net-new ClickHouse reference material (logs table schema,
log_attributes access, numeric casting, key discovery) into the existing
Logs Explorer guide and drop the standalone page and its nav entry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Jordi EnricandClaude Opus 4.8 committed 2026-07-01 17:32:50 +02:00
1 parent e0e26cc37b
commit a4e5de590b
3 files changed
+62 -139

No files matched your search

@@ -2976,10 +2976,6 @@ export const telemetry: NavMenuConstant = {
name: 'Advanced log filtering',
url: '/guides/telemetry/advanced-log-filtering' as `/${string}`,
},
{
name: 'Querying Supabase logs',
url: '/guides/telemetry/querying-supabase-logs' as `/${string}`,
},
{
name: 'Logs field reference',
url: '/guides/telemetry/log-field-reference' as `/${string}`,
@@ -276,6 +276,68 @@ The two backends store logs differently:
</Admonition>
### The ClickHouse logs table
On ClickHouse, every log line from every part of the stack lives in a single `logs` table, tagged by a `source` column. To read logs from one service, filter on `source`:
```sql
select timestamp, event_message
from logs
where source = 'edge_logs'
order by timestamp desc
limit 100;
```
Each row has a small set of top-level columns. Everything specific to a service lives in `log_attributes`.
| Column | Type | Description |
| ---------------- | ------------------- | --------------------------------------------------------- |
| `id` | string | Unique log identifier. |
| `timestamp` | datetime | When the log was produced, in UTC. |
| `event_message` | string | The raw log line. |
| `severity_text` | string | Log level, when the source sets one. |
| `source` | string | The service the log came from. Always filter on this. |
| `log_attributes` | Map(String, String) | Structured fields for the source, keyed by a dotted path. |
#### Reading fields from log_attributes
`log_attributes` is a map from a string key to a string value. Read a field with bracket access:
```sql
select
log_attributes['request.method'] as method,
log_attributes['request.path'] as path,
log_attributes['response.status_code'] as status
from logs
where source = 'edge_logs'
```
Where BigQuery nested a field under `metadata.request.method`, ClickHouse stores it at `log_attributes['request.method']`.
#### Casting numeric fields
Map values are strings. To compare or aggregate a numeric field, wrap it in `toInt32OrZero`:
```sql
select count() as server_errors
from logs
where source = 'edge_logs'
and toInt32OrZero(log_attributes['response.status_code']) between 500 and 599
```
`toInt32OrZero` returns `0` for missing or non-numeric values, so it never errors on partial data.
#### Discovering the available keys
To see which keys a source sets, read `mapKeys` from a recent row:
```sql
select mapKeys(log_attributes)
from logs
where source = 'postgres_logs'
limit 1;
```
### Timestamp display and behavior
Each log entry is stored with a `timestamp`.
@@ -1,135 +0,0 @@
---
title: 'Querying Supabase logs'
description: 'Query the single logs table on the ClickHouse-backed engine'
---
The [Logs Explorer](/dashboard/project/_/logs-explorer) runs queries against a single `logs` table backed by ClickHouse. Every log line from every part of the stack lives in this table, tagged by a `source` column. To read logs from one service, filter on `source`.
```sql
select timestamp, event_message
from logs
where source = 'edge_logs'
order by timestamp desc
limit 100;
```
## The logs table
Each row has a small set of top-level columns. Everything specific to a service lives in `log_attributes`.
| Column | Type | Description |
| ---------------- | ------------------- | --------------------------------------------------------- |
| `id` | string | Unique log identifier. |
| `timestamp` | datetime | When the log was produced, in UTC. |
| `event_message` | string | The raw log line. |
| `severity_text` | string | Log level, when the source sets one. |
| `source` | string | The service the log came from. Always filter on this. |
| `log_attributes` | Map(String, String) | Structured fields for the source, keyed by a dotted path. |
The `timestamp` is a `DateTime64` in UTC, formatted like `2026-06-22T09:34:06.215000` (ISO 8601 with microseconds). You can order and compare it directly. The Logs Explorer already applies the selected time range, don't need to write a `timestamp` filter of your own.
## Sources
Set `source` to the service you want:
- `edge_logs`: API gateway requests and responses.
- `postgres_logs`: database statements and errors.
- `auth_logs`: authentication and authorization activity.
- `function_edge_logs`: edge function requests and responses.
- `function_logs`: `console` output from inside edge functions.
- `storage_logs`: object upload and retrieval activity.
- `realtime_logs`: Realtime client connections.
The Logs Explorer **Field Reference** drawer lists every source and its fields.
## Reading fields from log_attributes
`log_attributes` is a map from a string key to a string value. Read a field with bracket access:
```sql
select
log_attributes['request.method'] as method,
log_attributes['request.path'] as path,
log_attributes['response.status_code'] as status
from logs
where source = 'edge_logs'
```
There are no unnesting joins. Where BigQuery nested a field under `metadata.request.method`, ClickHouse stores it at `log_attributes['request.method']`.
### Casting numeric fields
Map values are strings. To compare or aggregate a numeric field, wrap it in `toInt32OrZero`:
```sql
select count() as server_errors
from logs
where source = 'edge_logs'
and toInt32OrZero(log_attributes['response.status_code']) between 500 and 599
```
`toInt32OrZero` returns `0` for missing or non-numeric values, so it never errors on partial data.
## Discover the available keys
To see which keys a source sets, read `mapKeys` from a recent row:
```sql
select mapKeys(log_attributes)
from logs
where source = 'postgres_logs'
limit 1;
```
## Best practices
- Always include a `LIMIT`. Log tables are large, and an unbounded query scans far more data than you need.
- Always filter by `source`. It scopes the query to one service instead of every log in the project.
- Keep the time range tight. A smaller window in the date picker returns results faster.
- Filter on the real columns (`source`, `timestamp`) before reaching into `log_attributes`.
- Order by `timestamp desc` to see the most recent logs first.
- Select the columns you need and use `count()` instead of `count(*)` or `select *`, which aren't supported.
## Examples
Count requests by status code:
```sql
select
toInt32OrZero(log_attributes['response.status_code']) as status,
count() as count
from logs
where source = 'edge_logs'
group by status
order by count desc
```
Find auth errors:
```sql
select timestamp, event_message, log_attributes['msg'] as message
from logs
where source = 'auth_logs'
and log_attributes['level'] in ('error', 'fatal')
order by timestamp desc
```
Search the raw message:
```sql
select timestamp, event_message
from logs
where source = 'postgres_logs'
and event_message ilike '%deadlock%'
order by timestamp desc
```
## Differences from BigQuery
If you have queries written for the older BigQuery engine, the main changes are:
- One `logs` table for every service, filtered by `source`, instead of a separate table per service.
- Structured fields read from the `log_attributes` map instead of `cross join unnest(metadata)`.
- ClickHouse SQL functions, such as `toInt32OrZero`, `ilike`, and `mapKeys`.
The Logs Explorer can rewrite a saved BigQuery query for you. Open it and select **Rewrite to ClickHouse**.