可观性#

日志记录#

PostgREST将基本请求信息记录到 stdout 包括经过身份验证的用户(如果可用)、请求的IP地址和用户代理、请求的URL和HTTP响应状态。

127.0.0.1 - user [26/Jul/2021:01:56:38 -0500] "GET /clients HTTP/1.1" 200 - "" "curl/7.64.0"
127.0.0.1 - anonymous [26/Jul/2021:01:56:48 -0500] "GET /unexistent HTTP/1.1" 404 - "" "curl/7.64.0"

有关服务器本身的诊断信息,PostgREST记录到 stderr

12/Jun/2021:17:47:39 -0500: Starting PostgREST 11.1.0...
12/Jun/2021:17:47:39 -0500: Attempting to connect to the database...
12/Jun/2021:17:47:39 -0500: Listening on port 3000
12/Jun/2021:17:47:39 -0500: Connection successful
12/Jun/2021:17:47:39 -0500: Config re-loaded
12/Jun/2021:17:47:40 -0500: Schema cache loaded

备注

当在SSH会话中运行它时,您必须将其与标准输出分离,否则它将在会话关闭时终止。最简单的方法是将输出重定向到日志文件或系统日志:

ssh foo@example.com \
  'postgrest foo.conf </dev/null >/var/log/postgrest.log 2>&1 &'

# another option is to pipe the output into "logger -t postgrest"

目前,PostgREST不记录针对底层数据库执行的SQL命令。

数据库日志#

要找到SQL操作,您可以查看数据库日志。默认情况下,PostgreSQL不会保留这些日志,因此您需要进行以下配置更改。

发现 postgresql.conf 在您的PostgreSQL数据目录中(要找到它,请发出以下命令 show data_directory; )。找到散布在整个文件中的设置,并将它们更改为下列值,或者将此代码块追加到配置文件的末尾。

# send logs where the collector can access them
log_destination = "stderr"

# collect stderr output to log files
logging_collector = on

# save logs in pg_log/ under the pg data directory
log_directory = "pg_log"

# (optional) new log file per day
log_filename = "postgresql-%Y-%m-%d.log"

# log every kind of SQL statement
log_statement = "all"

重新启动数据库并实时查看日志文件,以了解如何将HTTP请求转换为SQL命令。

备注

在Docker上,您可以使用自定义 init.sh

#!/bin/sh
echo "log_statement = 'all'" >> /var/lib/postgresql/data/postgresql.conf

之后,您可以启动容器并使用以下命令检查日志 docker logs

docker run -v "$(pwd)/init.sh":"/docker-entrypoint-initdb.d/init.sh" -d postgres
docker logs -f <container-id>

服务器版本#

在调试问题时,验证正在运行的PostgREST版本很重要。有三种方法可以做到这一点:

  • 寻找 Server 在每个请求上返回的HTTP响应头。

HEAD /users HTTP/1.1

Server: postgrest/11.0.1
select distinct application_name
from pg_stat_activity
where application_name ilike '%postgrest%';

      application_name
------------------------------
PostgREST 11.1.0

重要

  • 服务器设置 fallback_application_name 设置为此查询工作所需的连接URI。覆盖值集的步骤 application_name 在连接字符串上。

  • 仅当版本是有效的URI时才会设置 (RFC 3986 )。这意味着任何特殊字符都必须经过urlended编码。

  • 如果连接字符串位于中,则不会设置版本 keyword/value format

  • 这个 stderr 日志还包含版本,如上所述 日志记录

跟踪标头#

您可以通过设置启用跟踪HTTP请求 服务器跟踪标头 。在请求中指定Set标头,服务器会将其包含在响应中。

server-trace-header = "X-Request-Id"
curl "http://localhost:3000/users" \
  -H "X-Request-Id: 123"
HTTP/1.1 200 OK
X-Request-Id: 123

服务器计时头#

您可以启用 Server-Timing 通过设置表头 启用服务器计时 在……上面。此标头传达请求-响应周期中不同阶段的指标。

curl "http://localhost:3000/users" -i
HTTP/1.1 200 OK

Server-Timing: jwt;dur=14.9, parse;dur=71.1, plan;dur=109.0, transaction;dur=353.2, response;dur=4.4
  • 所有的持续时间 (dur )以毫秒为单位。

  • 这个 jwt 舞台是指 基于JWT的用户模拟 已经完成了。此持续时间可通过以下方式缩短 JWT缓存

  • parse 舞台,舞台 URL语法 是被解析的。

  • plan 舞台,舞台 架构缓存 用于生成 主查询 这笔交易的。

  • 这个 transaction 阶段对应于数据库事务。看见 交易记录

  • 这个 response 阶段是计算响应状态和标头的地方。

备注

我们正在努力降低持续时间 parseplan PostgREST/postgrest#2816.上的阶段

执行计划#

你可以拿到 EXPLAIN execution plan 通过添加请求的 Accept: application/vnd.pgrst.plan 标题。这可通过以下方式实现 数据库-计划已启用 (默认情况下为False)。

curl "http://localhost:3000/users?select=name&order=id" \
  -H "Accept: application/vnd.pgrst.plan"
Aggregate  (cost=73.65..73.68 rows=1 width=112)
  ->  Index Scan using users_pkey on users  (cost=0.15..60.90 rows=850 width=36)

该计划的输出是在 text 格式,但您可以通过使用 +json 后缀。

curl "http://localhost:3000/users?select=name&order=id" \
  -H "Accept: application/vnd.pgrst.plan+json"
[
  {
    "Plan": {
      "Node Type": "Aggregate",
      "Strategy": "Plain",
      "Partial Mode": "Simple",
      "Parallel Aware": false,
      "Async Capable": false,
      "Startup Cost": 73.65,
      "Total Cost": 73.68,
      "Plan Rows": 1,
      "Plan Width": 112,
      "Plans": [
        {
          "Node Type": "Index Scan",
          "Parent Relationship": "Outer",
          "Parallel Aware": false,
          "Async Capable": false,
          "Scan Direction": "Forward",
          "Index Name": "users_pkey",
          "Relation Name": "users",
          "Alias": "users",
          "Startup Cost": 0.15,
          "Total Cost": 60.90,
          "Plan Rows": 850,
          "Plan Width": 36
        }
      ]
    }
  }
]

默认情况下,假设计划生成资源的JSON表示 (application/json ),但您可以获取 different representations that PostgREST supports 通过将它们添加到 for 参数。例如,要获得一个 text/xml ,您将使用 Accept: application/vnd.pgrst.plan; for="text/xml

其他可用参数包括 analyzeverbosesettingsbufferswal ,它们对应于 EXPLAIN command options 。要使用 analyzewal 参数,例如,您可以将它们添加为 Accept: application/vnd.pgrst.plan; options=analyze|wal

注意,与EXPLAIN命令类似,更改将在使用 analyze 选择。要避免这种情况,您可以使用 DB-TX-END 以及 Prefer: tx=rollback 标题。

确保执行计划的安全#

建议仅激活 数据库-计划已启用 因为它揭示了内部数据库的详细信息。但是,如果选择在生产中使用它,则可以添加一个 数据库-请求前 以筛选可以使用此功能的请求。

例如,要仅允许来自IP地址的请求获取执行计划:

-- Assuming a proxy(Nginx, Cloudflare, etc) passes an "X-Forwarded-For" header(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For)
create or replace function filter_plan_requests()
returns void as $$
declare
  headers   json := current_setting('request.headers', true)::json;
  client_ip text := coalesce(headers->>'x-forwarded-for', '');
  accept    text := coalesce(headers->>'accept', '');
begin
  if accept like 'application/vnd.pgrst.plan%' and client_ip != '144.96.121.73' then
    raise insufficient_privilege using
      message = 'Not allowed to use application/vnd.pgrst.plan';
  end if;
end; $$ language plpgsql;

-- set this function on your postgrest.conf
-- db-pre-request = filter_plan_requests