mirror of
https://github.com/supabase/supabase.git
synced 2026-10-08 19:05:06 +03:00
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:
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**.
|
||||
Reference in new issue
Block a user