From a4e5de590ba332a2154187a0eba554ee268b563e Mon Sep 17 00:00:00 2001 From: Jordi Enric Date: Wed, 1 Jul 2026 17:32:50 +0200 Subject: [PATCH] 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 --- .../NavigationMenu.constants.ts | 4 - apps/docs/content/guides/telemetry/logs.mdx | 62 ++++++++ .../telemetry/querying-supabase-logs.mdx | 135 ------------------ 3 files changed, 62 insertions(+), 139 deletions(-) delete mode 100644 apps/docs/content/guides/telemetry/querying-supabase-logs.mdx diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index 7e637553546..013402458e9 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -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}`, diff --git a/apps/docs/content/guides/telemetry/logs.mdx b/apps/docs/content/guides/telemetry/logs.mdx index 9bcabef60cb..5a35cef1169 100644 --- a/apps/docs/content/guides/telemetry/logs.mdx +++ b/apps/docs/content/guides/telemetry/logs.mdx @@ -276,6 +276,68 @@ The two backends store logs differently: +### 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`. diff --git a/apps/docs/content/guides/telemetry/querying-supabase-logs.mdx b/apps/docs/content/guides/telemetry/querying-supabase-logs.mdx deleted file mode 100644 index 34e44431fb7..00000000000 --- a/apps/docs/content/guides/telemetry/querying-supabase-logs.mdx +++ /dev/null @@ -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**.