正德厚生,臻于至善

PostgreSQL 日志设置

适用版本:PostgreSQL 13 ~ 17(标注 15+/17+ 的为高版本特性)
定位:从”参数怎么配”到”日志怎么读、事故怎么查”的完整闭环。
阅读路径:① 日志体系总览 → ② 参数全景与生效级别 → ③ csvlog 字段逐列解析 → ④ SQLSTATE 与日志级别 → ⑤ 生产配置模板 → ⑥ 排查 SOP / Checklist。


1. 日志体系总览

PostgreSQL 的日志分三层,不要混淆:

层次作用对应参数/进程类比 Oracle
日志收集器(logger)后台进程,通过 pipe 把 postgres 进程输出到 stderr 的内容捕获、落盘/轮转logging_collector、pg logger 进程diag 进程写 alert.log
日志目的地(log_destination)落盘格式:stderr / csvlog / jsonlog(15+) / syslog / eventloglog_destinationtrace 文件格式
日志内容开关决定”记录什么”:连接、慢 SQL、锁等待、检查点、临时文件……log_* 系列audit / sql_trace / 10046 事件

1.1 核心机制(为什么 logging_collector 必须 on)

  • 后端进程(backend)本身不直接写日志文件,而是把日志写到 stderr。
  • logging_collector = on 时,启动一个专用 logger 后台进程,通过 匿名 pipe 收集所有 backend 写到 stderr 的内容,再按 log_filename 规则切片写盘。
  • 因此:
    • 要写文件日志,logging_collector 必须 = on,且它是 postmaster 级参数,改完必须 restart(不是 reload)。
    • log_directory 是相对 data_directory 的路径(除非写绝对路径)。
    • csvlog 不是独立目的地,而是在 stderr 基础上”附加一份 CSV 结构化日志”;log_destination='stderr,csvlog' 可同时输出。
    • 高版本(15+)jsonlog 输出 JSON 行,适合直接进 ES/Loki,无需再解析 CSV。

1.2 log_destination 对比

目的地格式优点缺点生产建议
stderr纯文本人读最友好无法结构化提取 SQL/状态码容器调试用
csvlogCSV(23 列)字段可入库、可 SQL 关联需 filebeat/脚本解析OLTP 主力推荐
jsonlog(15+)JSON Lines结构化、直接进日志平台旧版不支持PG15+ 上日志平台首选
syslog系统 syslog复用 syslog 链路丢上下文、时区重复、字段被 syslog 截断小规模或托管环境
eventlogWindows 事件日志Windows 原生不适合 Linux 生产仅 Windows

生产常见组合:log_destination = 'csvlog',采集端用 Filebeat/Vector 解析 CSV 后送 Loki/ES/Kafka。


2. 参数全景(按职能分组 + 生效级别)

生效级别含义:

  • postmaster:改完必须 restart。
  • sighup:改完 SELECT pg_reload_conf(); 或 pg_ctl reload 即生效。
  • superuser / user:可在会话内 SET。

2.1 输出与轮转(文件形态)

参数示例值级别说明
logging_collectoronpostmaster日志收集器开关,落盘前提
log_destination'csvlog'sighup日志目的地
log_directory'log'postmaster日志目录,相对 data 目录
log_filename'postgresql-%Y-%m-%d_%H%M%S.log'sighup文件名模板,支持 strftime 占位符 %Y %m %d %H %M %S %a(星期)
log_file_mode0600sighup日志文件权限,不要用 0666(含 SQL 可能敏感)
log_rotation_age1dsighup按时间切分
log_rotation_size1GBsighup按大小切分,任一阈值先到先切
log_truncate_on_rotationoffsighupon 时同名文件覆盖而非追加;配合 %a(按星期)做 7 天覆盖式轮转

坑:log_truncate_on_rotation = on 只有在新文件名与旧文件同名时才 truncate;log_filename 带秒级 %S 时永远不同名,truncate 永远不生效。要做”固定保留 N 天覆盖”,用 postgresql-%a.log(按星期几命名)。

2.2 日志内容开关(决定记什么)

参数推荐值(生产)级别说明
log_min_messageswarningsighup服务器端记录的最低级别(DEBUG5/DEBUG4/…/INFO/NOTICE/WARNING/ERROR/LOG/FATAL/PANIC)
log_min_error_statementerrorsighup出错 SQL 本身在≥该级别时记录到 query 列
log_min_duration_statement300ms~`1s`sighup/superuser慢查询阈值,超过即记录完整 SQL 与时长;0=全部,-1=关闭
log_statementddlsighupnone / ddl / mod / all。all 生产禁用(量爆 + 泄露数据)
log_durationoffsighup记录每条 SQL 耗时;量极大,用 log_min_duration_statement 替代
log_checkpointsonsighup记录 checkpoint / restartpoint(估算 I/O 抖动)
log_connectionsoff(高并发)sighup每次连接一条;高并发 OLTP 会刷屏,合规要求才 on
log_disconnectionsoffsighup断开会话,可看会话时长
log_lock_waitsonsighup锁等待超过 deadlock_timeout 才记录(默认 1s,可调到 200ms 抓短锁)
deadlock_timeout1ssighup死锁检测周期,也是 log_lock_waits 的触发阈值
log_temp_files64MBsighup临时文件超过该大小即记录(0=全记,-1=关);排查排序/哈希落盘
log_autovacuum_min_duration100mssighupautovacuum 动作慢于该值才记录
log_replication_commandsonsighup记录复制起停命令(审计主从切换)
log_recovery_conflict_waitsonsighup备库因恢复冲突等待的语句(主从延迟排查关键)
log_error_verbositydefaultsighupterse / default / verbose,verbose 会带 internal query/context
log_executor_stats / log_statement_statsoffsuperuser统计每 SQL 资源开销,生产开了等于自 DoS,仅排查临时用

2.3 日志行前缀 log_line_prefix(完整占位符表)

截图用的前缀:

log_line_prefix = '%m [%p]: [%l] [txid=%x] user=%u,db=%d,app=%a,client=%r '

全部占位符(务必背熟 %c %l %x %i 这几个关联排查用得到的):

占位符含义
%aapplication_name(psql/应用连接串里设置)
%u数据库用户
%d数据库名
%p后端进程 PID
%r远端 host:port(本地连接显示 [local])
%h远端 host(IP;log_hostname=on 才反解主机名,生产保持 off 避免 DNS 延迟)
%m时间戳(带毫秒,本地时区)
%t时间戳(不带毫秒)
%n带毫秒时间戳(无 syslog 自带时间戳场景的变体)
%c会话 ID:backend_start(epoch hex).pid(hex),如 65eae855.443b,串联一个会话全部日志的主键
%l该会话内日志行序号(从 1 开始),即截图里的 “Line number”
%i当前命令标签(command tag,如 SELECT/INSERT)
%s会话启动时间
%v虚拟事务 ID(backend 级,未开事务也有)
%x顶层事务 ID;0 表示当前不在事务块中;截图里 commit 事务 ID=746
%eSQLSTATE 错误码(出错时才有值)
%q切换点:其后格式仅在会话 backend 进程中输出(WAL sender/checkpointer 等后台进程用不到时抑制)
%%字面 %

生产精简推荐前缀:

log_line_prefix = '%m [%p] %c txid=%x user=%u db=%d app=%a client=%r '

带 %c 是为了能把”某一次慢 SQL → 锁等待 → 连接断开”串成一条时间线。


3. csvlog 日志逐列解析(对照截图 15 个字段补全)

csvlog 实际有 23 列,截图是核心 15 列,完整对照表如下:

#列名截图对应说明/取值示例
1log_time① 时间戳2024-03-08 02:28:42.981 PST
2user_name② 用户名postgres
3database_name③ 数据库名postgres
4process_id④ 进程 ID17467
5connection_from⑤ 远端 IP/HOST[local] 或 10.0.0.5:5433
6session_id⑥ 会话 ID65eae855.443b,= %c
7session_line_num⑦ Line number会话内第几条日志,从 1 递增
8command_tag⑧ 数据库状态SELECT / CREATE TABLE 等命令标签
9session_start_time⑨ 会话启动时间2024-03-08 02:28:37 PST
10virtual_transaction_id—如 3/45
11transaction_id⑩ 事务 ID746;0 = 非事务中
12error_severity⑪ 日志级别LOG / STATEMENT / ERROR / FATAL …
13sql_state_code⑫ 状态码00000 表示无错误
14message⑬ 语句文本statement: create table t1(id int);
15detail—错误详情,如”键值已存在,违反唯一约束”
16hint—官方建议
17internal_query—内部触发 SQL(规则/约束)
18internal_query_pos—内部 SQL 位置
19context—上下文(如:在 PL/pgSQL 函数 foo 第 15 行)
20query—触发错误的用户 SQL(受 log_min_error_statement 控制)
21query_pos—出错 SQL 的字符偏移
22location—源码位置(仅 verbose)
23application_name⑭/⑮客户端/进程类型:psql、client backend、walreceiver…

3.1 会话 ID(%c / session_id)反查活动会话

截图给的公式可直接用——把日志里的 session_id 拆出来关联 pg_stat_activity:

-- 日志里看到 session_id = '65eae855.443b',反查它当前是否还活着、在干什么
SELECT pid, usename, datname, application_name, client_addr,
       state, wait_event_type, wait_event, query, backend_start
FROM pg_stat_activity
WHERE to_hex(trunc(EXTRACT(EPOCH FROM backend_start))::integer) = '65eae855'
  AND to_hex(pid) = '443b';

一个会话从 connect 到 disconnect 的所有日志,靠 session_id 聚合就是完整时间线;这是事故复盘的核心 join key。

3.2 在数据库里直接读日志(PG15+)

-- 列出日志目录下文件(需 pg_read_server_files 角色)
SELECT * FROM pg_ls_logdir();
-- 读取某日志内容
SELECT * FROM pg_read_logfile('postgresql-2026-11-07_020000.log');

4. 日志级别与 SQLSTATE

4.1 日志级别(从低到高)

DEBUG5 < DEBUG4 < DEBUG3 < DEBUG2 < DEBUG1 <
LOG <  INFO < NOTICE < WARNING < ERROR <
LOG(重复) < FATAL < PANIC
  • client_min_messages:发给客户端的级别;log_min_messages:写日志文件的级别。
  • 生产 log_min_messages = warning;error 及以上必报警。
  • STATEMENT 不是 severity,而是 log_statement=all/mod/ddl 记录的语句在 message 里以 statement: ... 出现,级别标记为 LOG。

4.2 SQLSTATE 结构(5 字符)

  • 前 2 位 = 错误类,后 3 位 = 子类。
  • 常见速查(生产值班必背):
SQLSTATE含义处置方向
00000成功正常语句日志
08006 / 08001连接失败/断开网络、pg_hba、连接数打满
23505唯一约束冲突业务重复插入
23502NOT NULL 违反上游数据缺字段
23503外键违反主从数据不一致
40P01死锁检测查 deadlock 日志的 detail 两个事务互锁语句
40001序列化失败隔离级别冲突,重试
42P01表不存在拼写/schema 错误
42601SQL 语法错误代码发布
53300超过 max_connections连接泄漏,查 idle in transaction
53100磁盘满立即清 WAL/临时文件
57P01 / 57P02管理员关闭/取消重启或 pg_cancel
XX000内部错误提 bug / 看 core

5. 生产级配置模板(OLTP 16C/128G 实例参考)

5.1 postgresql.conf 生产推荐段

# ========== 日志收集与文件 ==========
logging_collector      = on
log_destination       = 'csvlog'
log_directory         = 'log'
log_filename          = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_file_mode        = 0600
log_rotation_age      = 1d
log_rotation_size     = 1GB
log_truncate_on_rotation = off

# ========== 内容粒度 ==========
log_min_messages          = warning
log_min_error_statement   = error
log_error_verbosity        = default
log_line_prefix            = '%m [%p] %c txid=%x user=%u db=%d app=%a client=%r '

# ========== 慢 SQL(核心) ==========
log_min_duration_statement = '300ms'   # 按 P95 业务响应调整;门禁高的库用 1s
log_statement              = 'ddl'      # 审计需求交给 pgaudit,别用 all
log_duration               = off

# ========== 锁 / 死锁 ==========
log_lock_waits       = on
deadlock_timeout     = '200ms'         # 默认 1s 太长,抓 200ms 以上等待更敏感

# ========== 运维信号 ==========
log_checkpoints        = on
log_connections        = off           # 高并发保持 off;安全合规 on
log_disconnections     = off
log_temp_files         = '64MB'        # 排序/哈希落盘告警
log_autovacuum_min_duration = '100ms'
log_replication_commands    = on
log_recovery_conflict_waits = on

# ========== 不要打开的 ==========
# log_statement_stats / log_executor_stats:谁开谁背锅

5.2 auto_explain(慢 SQL 自动带执行计划,强烈推荐)

# 需先在 shared_preload_libraries 加载:
shared_preload_libraries = 'auto_explain'

auto_explain.log_min_duration   = '1s'
auto_explain.log_analyze       = on     # 真实执行统计
auto_explain.log_buffers        = on    # 缓冲区命中/读盘
auto_explain.log_nested_statements = on # 函数内嵌套 SQL 也记录
auto_explain.log_timing         = on    # 高负载采样开销大时改 off
auto_explain.log_triggers       = on

效果:超过 1s 的 SQL 自动把 EXPLAIN ANALYZE 结果写进日志,不用事后 auto_explain 复现。

5.3 合规审计:pgaudit

金融/等保场景需要记录全部 DDL/DML 与登录,不要靠 log_statement=all,装 pgaudit:

shared_preload_libraries = 'pgaudit'
pgaudit.log = 'write, ddl, role'

5.4 动态生效方式

-- 改参数后 reload(postmaster 级参数除外)
ALTER SYSTEM SET log_min_duration_statement = '500ms';
SELECT pg_reload_conf();

-- 验证
SHOW log_min_duration_statement;
-- 查哪些参数是 postmaster 级、当前值与来源
SELECT name, setting, sourcefile, pending_restart
FROM pg_settings WHERE name LIKE 'log_%' OR name = 'logging_collector';

6. 生产级实践要点

6.1 日志保留与磁盘治理

  • pg_log/log 目录必须纳入监控:磁盘水位 > 70% 告警,> 85% 自动清理 N 天前日志(cron + find -mtime +7 -delete)。
  • 保留周期建议:在线 7~14 天;合规要求的审计日志送中心化存储长期留存,本地只留热数据。
  • 大日志文件排查:先 ls -lh 找最大文件,按 session_id grep 聚合。

6.2 慢日志:日志 vs pg_stat_statements,怎么选

维度日志(log_min_duration_statement)pg_stat_statements
形态单次、带参数原文、带时长/计划聚合、带 calls/mean/total_time
用途事故现场、抓单笔慢 SQL找 TOP SQL、趋势基线
建议两者都开,慢查询门禁靠日志,常态优化靠 pg_stat_statements

6.3 常见”日志坑”清单

  1. logging_collector 改了不重启 → 文件根本没生成,以为参数没生效。
  2. log_statement=all 上生产 → 日志 GB/小时,磁盘打满,触发 53100 全站故障。
  3. log_connections=on 在万级 TPS 连接池上 → 日志量压垮 I/O。
  4. log_file_mode=0666 → 含敏感数据的 SQL 任何系统用户可读。
  5. log_line_prefix 不带 %c → 复盘时无法把同一会话的多条日志串起来。
  6. log_hostname=on → 每条连接反解 DNS,引发连接延迟毛刺。
  7. log_temp_files=-1 忘开 → 排序爆内存落盘却无任何告警。
  8. csvlog 直接用文本编辑器 grep → 引号转义把 SQL 拆成多行,应按 CSV 解析(filebeat 或 COPY ... WITH CSV HEADER 入库)。

6.4 日志采集上平台

  • Filebeat/Vector 采集 $PGDATA/log/*.csv,用 CSV 解析器拆出 23 列,加 host/cluster/tag 后送 Loki 或 ES。
  • 告警规则(PromQL / Loki):
    • rate(log{severity=”ERROR”}[5m]) > 5 → 数据库报错风暴
    • 53300(too_many_connections)出现即 P1
    • deadlock_detected(40P01)出现即 P2
    • 出现 PANIC / XX000 → P0 立即介入

7. 事故排查 SOP(值班 Checklist)

  • 确认时间窗:根据故障时间,定位对应切片日志文件。
  • 按 severity 过滤:先抓 ERROR / FATAL / PANIC,看 SQLSTATE。
  • 按 session_id 聚合:拿到异常会话的完整时间线(connect → SQL → wait → error → disconnect)。
  • 关联活动会话:用第 3.1 节 SQL 反查 pg_stat_activity,确认该会话是否还在跑、等什么(wait_event_type/wait_event)。
  • 死锁:日志里 deadlock detected 段落自带两个事务的 SQL 与持锁关系,按 detail 逐行读。
  • 慢 SQL:log_min_duration_statement 记录里找 duration: xxx ms 开头的行,看是否伴随 auto_explain 的 Query Plan。
  • 锁等待:log_lock_waits 记录 “process %d still waiting for …”,对比持锁进程。
  • 检查点抖动:checkpoint starting: time/write 与 checkpoint complete: wrote ... buffers,看 write 耗时是否撞上业务高峰。
  • 临时文件暴涨:log_temp_files 记录 temporary file: path "base/pgsql_tmp...", size xxx,定位哪个排序/哈希。
  • 磁盘/连接:53100 / 53300 出现时立即查 pg_stat_activity 的 idle in transaction 与连接来源 IP。
  • 备库:主从延迟先看 log_recovery_conflict_waits 与 WAL receiver 日志。

8. 附:与 Oracle 的对照(便于 Oracle DBA 快速映射)

PostgreSQLOracle 对应
postgresql-*.csv(logger 进程)alert_.log
log_min_duration_statement 慢 SQLsql_trace / 10046 事件
auto_explain10053 trace / 执行计划
pg_locks + log_lock_waitsUTLLOCKT / 锁阻塞链
pg_stat_statementsAWR / v$sqlarea 聚合
pgauditFGA / audit_trail
WAL sender / receiver 日志DG 备库 alert.log / LNS/RFS
csvlog 23 列trace 文件字段的结构化版本

赞(0) 打赏
未经允许不得转载:徐万新之路 » PostgreSQL 日志设置

支持快讯、专题、百度收录推送、人机验证、多级分类筛选器,适用于垂直站点、科技博客、个人站,扁平化设计、简洁白色、超多功能配置、会员中心、直达链接、文章图片弹窗、自动缩略图等...

联系我们

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续提供更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫

微信扫一扫

登录

找回密码

注册