Discovering and Interpreting API Errors in the Logs
为 Postgres 日志制作了一个免费的指南
浏览 API 日志: #
🌐 Navigating the API logs:
数据库 API 由 PostgREST 网页服务器 提供支持,每个请求都会记录到 API Edge 网络日志中。要精确浏览它们,可以使用 SQL 编辑器,并将查询源设置为 Logs。这些日志运行在 ClickHouse 上。每条日志都是单个 logs 表中的一行,通过 source 列进行标记。
🌐 The Database API is powered by a PostgREST web-server, recording every request to the API Edge Network logs. To precisely navigate them, use the SQL Editor with the query source set to Logs. These logs run on ClickHouse. Every log line is a row in a single logs table, tagged by a source column.
API 请求就是那些 source = 'edge_logs' 的行。
🌐 API requests are the rows where source = 'edge_logs'.
值得注意的是,它包含:
| 字段 | 描述 |
|---|---|
| event_message | 日志的消息 |
| timestamp | 事件记录的时间 |
| log_attributes | 结构化的请求和响应字段,用点路径作为键 |
🌐 Notably, it contains:
| field | description |
|---|---|
| event_message | the log's message |
| timestamp | time event was recorded |
| log_attributes | structured request and response fields, keyed by dotted path |
请求和响应的详细信息保存在 log_attributes 映射中。使用方括号访问字段,同时保留完整的点分键。没有任何非嵌套的联合操作。
🌐 Request and response details live in the log_attributes map. Read a field with bracket access, keeping the full dotted key. There are no unnesting joins.
字段访问示例
select -- event_message is a column, so it needs no lookup event_message, -- response.status_code is a log_attributes key log_attributes['response.status_code'] as status_codefrom logswhere source = 'edge_logs'limit 100;最有用来调试的字段有:
🌐 The most useful fields for debugging are:
注意:下面并未包含所有字段。要查看完整列表,请查阅 API Gateway 和 Function Edge 的 日志字段参考。
请求对象 #
🌐 Request object
Cloudflare 地理数据: #
🌐 Cloudflare geographic data:
建议使用场景:
- 检测来自特定地区的滥用行为
- 检测某些区域的活动高峰
| 列 | 描述 | 示例值 |
|---|---|---|
| request.cf.city | 请求者的城市 | 慕尼黑 |
| request.cf.country | 请求者的国家 | 德国 |
| request.cf.continent | 请求者的洲 | 欧洲 |
| request.cf.region | 请求者的地区 | 巴伐利亚 |
| request.cf.latitudex | 请求者的纬度 | 48.10840 |
| request.cf.longitude | 请求者的经度 | 11.61020 |
| request.cf.timezone | 请求者的时区 | 欧洲/柏林 |
展开示例:
select log_attributes['request.cf.city'] as cityfrom logswhere source = 'edge_logs'limit 100;IP 和浏览器/环境数据: #
🌐 IP and browser/environment data:
建议使用场景:
- 从IP检测请求行为
- 通过IP检测滥用
- 通过用户代理检测错误
| 列 | 描述 | 示例值 |
|---|---|---|
| request.headers.cf_connecting_ip | 请求者的 IP | 80.81.18.138 |
| request.headers.user_agent | 请求者的浏览器或应用环境 | Mozilla/5.0 (Linux; Android 11; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Mobile Safari/537.36 |
展开示例:
select log_attributes['request.headers.cf_connecting_ip'] as cf_connecting_ipfrom logswhere source = 'edge_logs'limit 100;查询类型和格式化数据: #
🌐 Query type and formatting data:
建议使用场景:
- 找出有问题的查询
| 列 | 描述 | 示例值 |
|---|---|---|
| request.method | 请求方法(PATCH, GET, PUT...) | GET |
| request.url | 请求 URL,包含 PostgREST 格式的查询 | https://yuhplfrsdxxxtldakizi.supabase.co/rest/v1/users?select=username&id=eq.63b6190e-214f-4b8a-b72d-3af6e1921411&limit=1 |
展开示例:
select log_attributes['request.method'] as method, log_attributes['request.url'] as urlfrom logswhere source = 'edge_logs'limit 100;响应对象 #
🌐 Response object
状态码: #
🌐 Status code:
建议使用场景:
- 检测成功/错误
| 列 | 描述 | 示例值 |
|---|---|---|
| response.status_code | 响应状态码 (200, 404, 500...) | 404 |
展开示例:
select log_attributes['response.status_code'] as status_codefrom logswhere source = 'edge_logs'limit 100;查找错误 #
🌐 Finding errors
API级别错误 #
🌐 API level errors
metadata.request.url 包含 PostgREST 格式的查询。
🌐 The metadata.request.url contains PostgREST formatted queries.
例如,下面对 JS 客户端的调用:
🌐 For example, the following call to the JS client:
let { data: countries, error } = await supabase.from('countries').select('name')对应调用以下端点:
🌐 translates to calling the following endpoint:
https://<project ref>.supabase.co/rest/v1/countries?select=name你可以使用正则表达式 (高级正则指南) 来查找与你的查询相关的对象。尝试按以下方式隔离:
🌐 You can use regex (Advanced Regex Guide) to find the objects related to your query. Try isolating by:
- 函数名
- 列名
- 表名
- 查询方法(选择、插入、...)
示例:
🌐 Example:
select timestamp, log_attributes['response.status_code'] as status_code, log_attributes['request.url'] as url, event_messagefrom logswhere source = 'edge_logs' -- find all errors and toInt32OrZero(log_attributes['response.status_code']) >= 400 -- find queries featuring a specific <table_name> and <column_name> and match(log_attributes['request.url'], '<table_name>') and match(event_message, '<column_name1>|<column_name2>')order by timestamp desclimit 100;PostgREST 有一个 错误参考表,你可以用它来解读状态码。
🌐 PostgREST has an error reference table that you can use to interpret status codes.
数据库级错误 #
🌐 Database-level errors
不过,通过数据库 API 报告的一些错误是在 Postgres 层发生的。如果不清楚发生了哪种错误,你应该参考错误的时间戳,并尝试查看是否可以在 Postgres 日志中找到它。
🌐 However, some errors that are reported through the Database API occur at the Postgres level. If it is not clear which error occurred you should reference the timestamp of the error and try to see if you can find it in the Postgres logs.
select timestamp, log_attributes['parsed.error_severity'] as error_severity, log_attributes['parsed.user_name'] as user_name, log_attributes['parsed.query'] as query, log_attributes['parsed.detail'] as detail, log_attributes['parsed.sql_state_code'] as sql_state_code, event_messagefrom logswhere source = 'postgres_logs' -- filter only for error events and log_attributes['parsed.error_severity'] in ('ERROR', 'FATAL', 'PANIC') -- All DB API requests are registered as the authenticator role and log_attributes['parsed.user_name'] = 'authenticator' -- find failed queries featuring the function <function_name> and match(log_attributes['parsed.query'], '<function_name>') -- limit the time of the search to be around the time of the failed API request and timestamp between '2024-04-15 10:50:00' and '2024-04-15 10:50:27'order by timestamp desclimit 100;像 PostgREST 一样,Postgres 也有一个参考表用来解释错误代码。
🌐 Like PostgREST, Postgres has a reference table for interpreting error codes.
PostgREST 服务器和 Cloudflare 错误 #
🌐 PostgREST server and Cloudflare errors
在某些情况下,错误可能是由于 Cloudflare 或 PostgREST 服务器错误引起的。对于 500 及以上的错误,你可能需要检查你的 PostgREST 日志以及 Cloudflare 文档。
🌐 In some cases, errors may emerge because of Cloudflare or PostgREST server errors. For 500 and above errors, you may want to check your PostgREST logs and the Cloudflare docs.)
实际例子: #
🌐 Practical examples:
查找所有错误:
select timestamp, log_attributes['response.status_code'] as status_code, event_message, log_attributes['request.path'] as pathfrom logswhere source = 'edge_logs' -- find all errors and toInt32OrZero(log_attributes['response.status_code']) >= 400 -- only look at DB API and match(log_attributes['request.path'], '^/rest/v1/')order by timestamp desclimit 100;按路径和代码分组错误:
select log_attributes['response.status_code'] as status_code, log_attributes['request.path'] as path, count() as reoccurrence_per_pathfrom logswhere source = 'edge_logs' -- find all errors and toInt32OrZero(log_attributes['response.status_code']) >= 400 and match(log_attributes['request.path'], '^/rest/v1/') -- only look at DB APIgroup by path, status_codeorder by reoccurrence_per_path desclimit 100;按地区查找请求:
select log_attributes['request.path'] as path, log_attributes['request.cf.region'] as region, count() as region_countfrom logswhere source = 'edge_logs' -- only look at DB API and match(log_attributes['request.path'], '^/rest/v1/')group by region, pathorder by region_count desclimit 100;按IP统计总请求数:
select log_attributes['request.headers.cf_connecting_ip'] as ip, count() as ip_countfrom logswhere source = 'edge_logs' and match(log_attributes['request.path'], '^/auth/v1/')group by iporder by ip_count desclimit 100;