日志配置(log_destination / logging_collector)
从本页开始进入日志系统章节。PostgreSQL 的日志能力常被低估:它不只是「出了错打一行 ERROR」,而是一套可配置、可结构化、可对接外部系统的完整观测管道。慢查询、连接审计、死锁现场、autovacuum 行为、DDL 变更历史——生产环境的大量关键证据都写在日志里。日志配得好不好,直接决定故障时你是「翻证据」还是「猜原因」。
配置日志要回答三个问题:写到哪去(log_destination、logging_collector、文件命名与目录)、什么时候写(各级别阈值与慢语句阈值)、写多少细节(log_line_prefix、详细度、是否带语句原文)。本页聚焦「写到哪去」与「写多少细节」,轮转与清理留给下一页,CSV 与 JSON 两种结构化格式各有专页。
先建立一条主线:PostgreSQL 的日志参数分属 postgresql.conf 的 logging 区块,多数支持 reload 生效,但 logging_collector 等少数参数必须重启。改配置前先弄清每个参数的生效方式,避免「改了没生效」的困惑。
前置知识
建议先阅读:常用监控 SQL 汇总
基础概念
PostgreSQL 的日志产生路径可以画成一条流水线:
后端进程/辅助进程产生消息
│
├─ 消息级别低于阈值 ──► 丢弃
│
▼
按 log_destination 决定去向
│
├─ stderr ──► logging_collector = on ──► 收集进程写入日志文件
│ logging_collector = off ─► 交给父进程(如 systemd journal)
├─ csvlog ──► 收集进程写入 CSV 文件(需 collector)
├─ jsonlog ─► 收集进程写入 JSON 文件(需 collector,PG15+)
├─ syslog ──► 交给系统 syslog 守护进程
└─ eventlog ─► Windows 事件日志核心概念有三个:
| 概念 | 说明 |
|---|---|
logging_collector | 后台收集进程。开启后由它捕获所有进程的 stderr 并写入文件;修改需重启 |
log_destination | 消息去向,可同时逗号分隔配置多个 |
| 消息级别(severity) | 从 DEBUG5 到 PANIC 的分级体系,log_min_messages 控制入日志的下限 |
一个容易混淆的点:logging_collector 收集的是 stderr 流。log_destination = stderr 与 csvlog、jsonlog 的区别只是「写文件时用什么格式」——后两者必须经由收集进程落地,因此不能与 syslog/eventlog 混用(这两个去向绕过收集进程)。
消息级别体系
服务器日志与客户端消息共用同一套级别,从低到高:
| 级别 | 含义 | 常见来源 |
|---|---|---|
DEBUG5 ~ DEBUG1 | 开发调试信息,逐级更详细 | 排查内核行为时临时开启 |
INFO | VACUUM VERBOSE 等命令的显式输出 | 用户命令 |
NOTICE | 提示性消息(如 CREATE TABLE 会转换列类型) | 用户命令 |
WARNING | 警告(潜在问题,语句仍成功) | 应用与运维命令 |
LOG | 服务器运行信息(检查点、连接、慢语句) | 服务器自身 |
ERROR | 当前语句失败 | 语句错误 |
FATAL | 连接被终止(认证失败、后台崩溃) | 服务器 |
PANIC | 所有子进程崩溃 | 罕见、严重 |
log_min_messages 的默认值是 warning,意味着默认日志里没有 LOG 级消息——而连接、检查点、慢语句统统是 LOG 级。生产库几乎一定要显式设置 log_min_messages,否则日志接近空白。
语法与用法
最小生产配置
# postgresql.conf —— 日志基础配置的典型起点
# ---- 去向 ----
logging_collector = on # 开启收集进程(修改需重启)
log_destination = 'csvlog' # 结构化 CSV(或 'stderr' / 'jsonlog')
# ---- 文件位置与命名 ----
log_directory = 'log' # 相对于数据目录;也可写绝对路径
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_file_mode = 0600 # 文件权限(非 Windows)
# ---- 记录什么 ----
log_min_messages = warning # 低于 warning 的不进日志
log_min_error_statement = error # ERROR 及以上附带语句原文
log_error_verbosity = default # terse / default / verbose
log_connections = on # 连接建立时记录
log_disconnections = on # 连接断开时记录
log_line_prefix = '%m [%p] %q%u@%d %r %b ' # 每行前缀,见下文
# ---- 轮转(下一页详解)----
log_rotation_age = 1d
log_rotation_size = 100MB
log_truncate_on_rotation = off# 修改后 reload 使多数参数生效
pg_ctl reload -D /var/lib/postgresql/18/main
# 或 SQL 方式
psql -c "SELECT pg_reload_conf();"在线核对配置
-- 当前生效值
SHOW log_destination;
SHOW logging_collector;
SELECT name, setting, source, pending_restart
FROM pg_settings
WHERE name LIKE 'log_%'
ORDER BY name;
-- 配置文件里写了什么、是否生效
SELECT * FROM pg_file_settings WHERE name LIKE 'log_%';pg_settings.pending_restart = true 表示该参数改了但要重启才生效——排查「改了没生效」的第一站。
详细说明
log_destination 的五种去向
| 取值 | 说明 | 依赖 collector |
|---|---|---|
stderr | 写入 stderr(被收集进程捕获后写文件) | 写文件需要;否则交给父进程 |
csvlog | 以 CSV 格式写文件,固定 26 列结构 | 是 |
jsonlog | 每条消息一个 JSON 对象(PG15+) | 是 |
syslog | 交给系统 syslog 守护进程 | 否(绕过 collector) |
eventlog | 写 Windows 事件日志(仅 Windows) | 否 |
要点:
- 可以多选:
log_destination = 'stderr,csvlog'会同时写普通文本与 CSV 两套文件,适合过渡期。 - csvlog/jsonlog 与 syslog 互斥使用:结构化格式由收集进程负责,syslog 是另一条通道。既要 syslog 又要结构化文件,就同时配置两者,靠不同管道各走各的。
- 选型建议:要机器处理就选
csvlog或jsonlog(后者对现代日志栈更友好);只求人看,stderr+ 合理前缀即可。 jsonlog需要 PG15+;老版本只有前四种。
logging_collector 的进程模型
logging_collector = on 时,Postmaster 会 fork 一个收集进程,所有后端把 stderr 写到管道,由收集进程统一落盘。行为要点:
- 修改必须重启。这是 logging 区块里最常「改了不生效」的参数,检查
pg_settings.pending_restart。 - 关闭时 stderr 直接继承给父进程:systemd 部署下消息进入 journal,容器部署下进入容器的 stdout。这不是「没有日志」,而是「日志由进程管理器接管」。
- 收集进程自身很轻,但它是单点:日志盘 I/O 饱和时,消息会在管道里排队,极端情况下反压后端。日志目录必须与数据目录分盘,这是磁盘规划的硬规则。
- 收集进程会把「多进程各自的 stderr」合并成单一文件流,这也是它存在的原因之一。
文件位置三件套:log_directory / log_filename / log_file_mode
log_directory = 'log' # 相对数据目录,或绝对路径
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_file_mode = 0600| 参数 | 默认值 | 说明 |
|---|---|---|
log_directory | log(较新版本;更早为 pg_log) | 相对路径基于数据目录 |
log_filename | postgresql-%Y-%m-%d_%H%M%S.log | 支持 strftime 风格格式化符 |
log_file_mode | 0600 | 八进制文件权限,Windows 上忽略 |
log_filename 的格式化符直接决定轮转行为,几个常用示例:
| 取值 | 效果 |
|---|---|
postgresql-%Y-%m-%d.log | 按天一个文件 |
postgresql-%Y-%m-%d_%H.log | 按小时一个文件 |
postgresql-%Y-%m-%d_%H%M%S.log | 每次轮转产生新文件(默认值) |
postgresql-%a.log | 按星期几循环覆盖(配合 log_truncate_on_rotation = on) |
文件名里嵌入的时间精度与轮转周期要匹配:想要「按天+小时」的命名,就把 log_rotation_age 设为 1 小时;名字里没有时间变化,同一文件就会被反复追加(或配合 truncate 覆盖)。这套配合关系在《日志轮转与清理》一页展开。
log_min_messages 与级别阈值
log_min_messages = warning # debug5..debug1, info, notice, warning, log, error, fatal, panic语义:达到或高于设定级别的消息写入服务器日志。两个高频坑:
- 默认
warning会滤掉所有LOG级消息,而连接日志、检查点、慢语句都是LOG级。生产常见做法是log_min_messages = warning保持不变、但显式开启需要的单项开关(log_connections等会以 LOG 级输出吗?——会,单项开关输出的消息不受log_min_messages过滤)。若希望日志里出现全部运行信息,可设为log或notice,代价是日志量增大。 LOG级别的排序在服务器端与客户端不一致:对服务器日志而言LOG总是排在ERROR之下、WARNING之上附近的位置;对客户端而言它排在FATAL与ERROR之间。这是官方文档明确说明的特例,写级别比较逻辑时别踩。
单项开关(如 log_connections)产生的消息不受 log_min_messages 过滤,这是「保留 warning 阈值、同时获得连接日志」的标准姿势。
log_error_verbosity:消息详细度
log_error_verbosity = default # terse / default / verbose| 取值 | 输出内容 |
|---|---|
terse | 级别 + 主文本 + 位置,抑制 DETAIL、HINT、QUERY、CONTEXT |
default | 上述 + DETAIL / HINT / QUERY / CONTEXT 等字段 |
verbose | 再加 SQLSTATE 错误码、产生错误的源码文件/函数/行号(LOCATION) |
排障场景(死锁、约束冲突分析)建议 verbose:死锁日志的 DETAIL 环描述、错误码都是分诊的关键。日志量大且已有 APM 收敛时可用 terse。
log_min_error_statement:错误时附带语句原文
log_min_error_statement = error达到该级别(或更高)的错误会在日志中附带引发错误的 SQL 语句原文(截断到 2048 字符)。默认 error 意味着普通业务报错都会带语句——这对定位问题极有价值,但也意味着错误日志可能包含业务数据。敏感行业要评估该默认值,必要时收紧到 fatal,并配合权限与脱敏策略。
log_line_prefix:给每一行打上身份标签
默认的 log_line_prefix 几乎为空(只有一个空格),导致多进程并发写日志时无法分辨「这行是谁写的」。生产环境必须配置它。全部转义符如下:
| 转义符 | 含义 |
|---|---|
%a | application_name |
%u | 用户名 |
%d | 数据库名 |
%r | 远程主机名/IP 与端口(形如 host(54321)) |
%h | 远程主机名/IP |
%b | 后端类型(backend_type,PG13+) |
%p | 进程号 PID |
%P | 并行组 leader 的 PID(PG14+;无则为空) |
%t | 时间戳(不含毫秒) |
%m | 时间戳(含毫秒) |
%n | 时间戳(含毫秒,Unix epoch 格式) |
%i | 命令标签(command tag,如 SELECT、UPDATE) |
%e | SQLSTATE 错误码 |
%c | 会话 ID(可关联同一会话的多行日志) |
%l | 每个会话内的行号 |
%s | 进程启动时间戳 |
%v | 虚拟事务 ID(形如 3/4821) |
%x | 事务 ID(无事务为 0) |
%Q | 当前查询的 query ID(PG14+;未计算则为 0) |
%q | 终止符:其后内容不输出给非会话进程(如后台进程) |
%% | 字面 % |
推荐的生产取值(兼顾可读性与机器解析):
log_line_prefix = '%m [%p] %q%u@%d/%a %r %b '%q 的用法要特别理解:放在 %q 之前的内容所有进程都输出,之后的内容只有普通会话进程输出。%c(会话 ID)是把一次连接产生的多行日志串起来的关键——日志平台的「会话视图」靠它实现。
连接与断开日志
log_connections = on # 连接建立(含认证成功)时记录
log_disconnections = on # 会话结束时记录(含时长)
log_duration = off # 每条语句结束后记录执行时长(无语句内容)log_connections/log_disconnections是安全审计的基石,配置语义与完整示例见《log_connections / log_disconnections》一页。log_duration记录的是「每条语句一条时长日志」,与慢语句阈值(log_min_duration_statement)是两回事;后者按阈值过滤且可附带执行计划,是慢查询治理的主通道,相关细节由慢查询章节专门展开,本页不重复。- 连接风暴场景下这两个开关会让日志量暴涨,配合
log_connections时要同时规划日志容量。
日志参数的生效方式速查
| 参数 | 生效方式 |
|---|---|
logging_collector | 重启 |
log_destination | reload |
log_directory / log_filename / log_file_mode | reload(对新开的日志文件生效) |
log_min_messages / log_error_verbosity / log_min_error_statement | reload(可按会话覆盖部分) |
log_line_prefix | reload |
log_connections / log_disconnections / log_duration | reload(可按会话/角色覆盖) |
log_rotation_age / log_rotation_size / log_truncate_on_rotation | reload |
配置生效方式的总方法论(reload 与 restart 的差别、ALTER SYSTEM)见《配置参数生效方式》一页。
syslog 专用参数
选择 syslog 去向时,还有一组配套参数:
syslog_facility = 'LOCAL0' # syslog 设施(LOCAL0..LOCAL7),便于过滤
syslog_ident = 'postgres' # syslog 标识
syslog_sequence_numbers = on # 消息序号(便于发现丢失)
syslog_split_messages = on # 按行拆分(默认按 900 字节拆,适配 syslog 行长限制)syslog 通道的优点是复用系统级日志设施(集中收集、轮转交给 syslog 管理);缺点是消息被拆分、结构化字段丢失,且多一层守护进程的可靠性依赖。
两条时长通道:log_duration 与 log_min_duration_statement
记录语句耗时有两个参数,语义不同、叠加行为官方文档有明确定义:
| 参数 | 记录什么 | 是否带语句文本 |
|---|---|---|
log_duration = on | 每条完成的语句的耗时 | 不带 |
log_min_duration_statement = 200 | 耗时超过 200ms 的语句(设 0 则全部) | 带(超阈值时) |
两者同时开启时:所有语句的耗时都会记录,但只有超过阈值的语句才附带语句文本。这个组合在高负载系统上很实用——耗时分位数靠全量时长日志,语句内容只对慢的保留:
log_duration = on # 全量时长(不带文本)
log_min_duration_statement = 500 # 超过 500ms 的附语句文本只有一个阈值需求时,单独用 log_min_duration_statement 即可;两者都开时要知道日志里同一慢语句会出现两条记录(一条带文本、一条纯时长),统计口径按需过滤。
log_parameter_max_length:绑定参数的截断控制
语句日志默认会带上扩展协议语句的绑定参数值,由此带来两个反向需求:性能(大参数转文本的开销)与合规(参数值可能就是敏感数据)。PG13 引入的两个参数分别管两条通道:
| 参数 | 作用范围 | 默认值 |
|---|---|---|
log_parameter_max_length | 非错误语句日志(log_statement、时长日志等) | -1(完整记录) |
log_parameter_max_length_on_error | 错误消息中的参数 | 0(不记录) |
# 高负载库的典型组合:时长日志截断大参数、错误消息不落参数
log_parameter_max_length = 64
log_parameter_max_length_on_error = 0两个参数都是超级用户级设置(SUSET);非零值会带来「语句开始时就保存参数文本」的额外开销,扩展协议下更明显。需要完整参数值做重放调试时临时放开,用完收回。
按角色与会话覆盖日志行为
日志参数大多支持按角色/会话覆盖,这把「全局一刀切」变成了「分而治之」:
-- 报表角色:慢语句阈值收紧到 100ms,便于收集优化素材
ALTER ROLE report_user SET log_min_duration_statement = '100ms';
-- ETL 角色:批量操作的日志噪音单独关闭
ALTER ROLE etl_user SET log_statement = 'none';
-- 临时排查某个会话(仅本会话生效)
SET log_min_duration_statement = 0;注意权限语义:log_min_duration_statement、log_statement 属于超级用户级参数,普通角色不能自行放宽;log_duration 等用户级参数可由会话调整。排查结束后记得清理会话级覆盖(RESET),并把角色级设置纳入配置版本管理。
application_name 的工程约定
application_name 在日志(%a)、pg_stat_activity、CSV/JSON 日志里反复出现,是串联三者的关键标签。约定三条:
- 每个服务实例一个可识别的名字:形如
order-service-pool2,而不是所有服务共用驱动默认值。 - 连接池要透传:应用 → pgbouncer → 数据库的链路里确认
application_name没有在中间被覆盖,否则日志标签失真。 - 与发布流水联动:把构建号拼进去(如
order-service@build-4821),「这条慢 SQL 来自哪个版本」直接可查。
# 验证连接串设置的生效情况
psql "dbname=appdb application_name=dba-debug" \
-c "SELECT application_name FROM pg_stat_activity WHERE pid = pg_backend_pid();"systemd 与容器部署的日志归属
logging_collector = off(默认)时,stderr 交给父进程,日志的「文件管理权」随之转移:
| 部署形态 | 日志去向 | 轮转责任人 | 注意点 |
|---|---|---|---|
| systemd(宿主机) | journald | journald(SystemMaxUse 等配额) | journalctl -u postgresql 查询 |
| Docker/K8s | 容器 stdout → json-file / 集群采集器 | Docker max-size/max-file 或平台 | 单行一条,多行日志靠 stdout 编排 |
| 传统 sysv / 手工部署 | 终端或文件 | 需要自己接管 | 这种形态建议直接开 collector 文件化 |
两种模式各有生态(journald 的持久化与检索、容器平台的采集管道),关键是全团队统一预期:不要出现「一半实例文件化、一半实例 stdout」的混合状态。容器形态的轮转与容量限制在《日志轮转与清理》里展开。
消息级别的完整阶梯
日志参数大多围绕「级别」工作,完整阶梯(从详尽到严重):
| 级别 | 语义 | 服务器排序 |
|---|---|---|
DEBUG5 ~ DEBUG1 | 开发调试信息,量最大 | 最详细 |
LOG | 运行信息(检查点、连接、慢语句) | 详细 |
NOTICE / WARNING | 有用提示 / 潜在问题 | 详细 |
ERROR | 当前命令失败 | 中间 |
LOG(错误通道) | 后台运行信息(与上面的 LOG 是同一个词、不同位置) | 中间 |
FATAL | 连接中断 | 严重 |
PANIC | 全体后端崩溃 | 最严重 |
两个经典细节:LOG 在 log_min_messages 的服务器排序里出现两次(普通级别区与错误级别区各一个),导致「把 log_min_messages 设到 LOG 收不到 LOG」的困惑;客户端排序里 CLIENT_MIN_MESSAGES 的相邻关系又不同。拿不准时直接 SHOW log_min_messages; 看当前值,用 set_config 试验而不是硬背。
-- 现场验证当前级别配置
SHOW log_min_messages;
SHOW client_min_messages;log_checkpoints:让检查点写进日志(PG15+ 起默认开启)
检查点日志是「IO 抖动复盘」的第一手材料,PG15 起 log_checkpoints 默认 on:
LOG: checkpoint starting: time
LOG: checkpoint complete: wrote 20413 buffers (3.1%), wrote 3 WAL files, ...checkpoint complete 行里有写缓冲数量、WAL 回收数量与耗时,配合 log_rotation_age 按时间轴归档后,就能回答「每晚 2 点的 IO 尖峰是不是检查点」。PG16 及以前该参数默认 off,升级到新版本时会「突然多出」这类日志,日志量预算要预留。
stderr 模式下的最小前缀推荐
不开 logging_collector、把 stderr 交给 journald/容器时,log_line_prefix 是唯一的上下文载体。最小推荐:
log_line_prefix = '%m [%p] %q%u@%d/%a '拆解:时间 %m、进程号 %p、%q(无会话上下文时截断后半段)、用户 @ 库 / 应用名 + 空格。这五个要素让 journald/容器日志至少能完成「哪条消息属于哪个会话」的初筛。需要更细的排查再追加 %c(会话 ID)与 %x(事务 ID),但前缀越宽、每行体积越大,按需取舍。
特殊取值语义:0、-1 与关闭
记录类参数的特殊值语义不一致,最容易记混的就是它们:
| 参数 | 关闭 | 全量 | 说明 |
|---|---|---|---|
log_min_duration_statement | -1 | 0(所有语句都算慢) | 单位 ms,正值是阈值 |
log_parameter_max_length | -1 即不限制 | — | 正值是字符数上限 |
log_parameter_max_length_on_error | 0(不记录参数) | -1 | 与上面正好相反 |
「0 到底是关还是全量」取决于参数自己的定义,配置 review 时逐个对照官方文档,不要靠类比记忆。
运行时验证:配置真的生效了吗
日志参数的生效方式不一(重启 / reload / 会话级),验证一步到位:
-- 看当前值与来源(source 列显示是配置文件、会话还是角色级设置)
SELECT name, setting, source, pending_restart
FROM pg_settings
WHERE name IN ('logging_collector', 'log_destination', 'log_min_duration_statement',
'log_line_prefix', 'log_duration')
ORDER BY name;pending_restart = true 的参数(如 logging_collector)改了也不会 reload 生效,必须安排重启窗口;source = 'session' 说明被会话级覆盖过——排查「日志行为与配置文件不一致」时,这个查询就是答案。
实战示例
示例一:从零配置一个可生产的日志基线
# 1) 开启收集器与结构化格式(重启生效)
logging_collector = on
log_destination = 'csvlog'
# 2) 文件命名:按天 + 每次启动新建
log_directory = 'log'
log_filename = 'postgresql-%Y-%m-%d.log'
# 3) 让每行可溯源
log_line_prefix = '%m [%p] %q%u@%d %r %b '
# 4) 记录内容
log_min_messages = warning
log_error_verbosity = verbose
log_min_error_statement = error
log_connections = on
log_disconnections = on
# 5) 轮转兜底:单文件不超过 100MB
log_rotation_size = 100MB# 6) 重启使 collector 生效,随后验证
pg_ctl restart -D /var/lib/postgresql/18/main
psql -c "SHOW logging_collector;" logging_collector
-------------------
on
(1 row)# 7) 确认日志目录与文件
ls -l $PGDATA/log/-rw------- 1 postgres postgres 20480 Sep 30 10:15 postgresql-2026-09-30.log示例二:验证一条错误日志的完整信息
-- 制造一条带详细信息的错误
SELECT 1/0;2026-09-30 10:20:01.123 CST [18241] app@appdb 10.0.0.11(51022) client backend ERROR: division by zero
2026-09-30 10:20:01.123 CST [18241] app@appdb 10.0.0.11(51022) client backend STATEMENT: SELECT 1/0;verbose 级别下还会有 SQLSTATE(如 22012 除零)与 LOCATION 行。用 log_line_prefix 里的会话 ID(%c)可以把同一连接的 ERROR、STATEMENT、DETAIL 串成一组。
示例三:syslog 通道的最小接入
log_destination = 'syslog'
syslog_facility = 'LOCAL0'
syslog_ident = 'pg-main'# rsyslog 侧按 facility 过滤到独立文件
echo "local0.* /var/log/postgresql/main.log" >> /etc/rsyslog.d/30-postgresql.conf
systemctl reload rsyslog之后由 syslog 生态统一负责转发与轮转,PostgreSQL 侧不再管理文件。
示例四:按角色差异化日志策略
目标:OLTP 应用安静、报表可观测、DBA 会话全量留痕。
# 全局基线:安静,只留错误与必要审计
log_min_messages = warning
log_min_duration_statement = 1s
log_error_verbosity = verbose
log_connections = off
log_disconnections = off-- 报表角色:100ms 阈值 + 连接审计(角色级覆盖)
ALTER ROLE report_user SET log_min_duration_statement = '100ms';
ALTER ROLE report_user SET log_connections = on;
ALTER ROLE report_user SET log_disconnections = on;
-- DBA 运维角色:全语句记录(仅该角色,评估日志量后使用)
ALTER ROLE dba_ops SET log_statement = 'all';
ALTER ROLE dba_ops SET log_min_duration_statement = 0;
-- 验证生效
SELECT rolname, rolconfig FROM pg_roles
WHERE rolname IN ('report_user', 'dba_ops', 'app_user'); rolname | rolconfig
-------------+----------------------------------------------------------
report_user | {log_min_duration_statement=100ms,log_connections=on,...}
dba_ops | {log_statement=all,log_min_duration_statement=0}
app_user |
(3 rows)这套策略的前提是角色划分清晰(应用、报表、运维各自独立角色);日志量按角色评估,报表与 DBA 角色的日志增量单独观察三天再定稿。
示例五:两分钟排障——日志为什么没有输出
改了配置却没有日志,按固定顺序排查,通常两分钟内定位:
-- 1) 输出去向对不对?
SHOW log_destination; -- 期望含 csvlog / jsonlog
SHOW logging_collector; -- 期望 on
-- 2) 改动是否还在等重启?
SELECT name, setting, pending_restart
FROM pg_settings
WHERE name IN ('logging_collector', 'log_destination');
-- 3) 级别门是不是全关了?
SHOW log_min_messages; -- warning 会吞掉 LOG 级消息
SHOW log_min_duration_statement;# 4) 目录与权限
SHOW log_directory;
ls -la /var/lib/postgresql/18/main/log/ | head四步覆盖了「目的地、生效方式、级别门、文件系统」的全部常见断点:log_min_messages = warning 是最隐蔽的一个——它会把连接审计、慢语句这些 LOG 级消息全部静默。
注意事项
logging_collector 改动必须重启。 它是「配置了却一直没生效」的高发区。改完用 pg_settings.pending_restart 核对,别反复 reload 无效配置。
日志盘与数据盘必须分离。 收集进程写日志的 I/O 与数据库 I/O 混盘时,日志风暴会直接拖垮数据读写;反之数据盘打满也会连累日志。规划层面就要分开。
log_line_prefix 默认近乎为空。 不配置前缀的多进程日志基本不可分析。哪怕只用 %m [%p] ,也让每行有了时间与进程身份。
log_min_messages 与单项开关是两套逻辑。 单项开关(log_connections 等)不受级别阈值过滤;想要连接日志不需要把阈值降到 log。反过来,把阈值设成 debug1 会产生海量日志,只用于短时排查。
默认日志名带 %H%M%S,每次轮转都是新文件。 想要按天合并文件需要显式改 log_filename;「日志文件怎么这么多」多半是这个原因,轮转策略见下一页。
CSV/JSON 与 syslog 不能混为一谈。 csvlog、jsonlog 只能由收集进程写文件;配置了 syslog 的实例不会产生结构化文件。既要集中收集又要结构化,用 syslog 收集后再解析,或让日志采集 agent 直接读结构化文件。
错误日志会包含语句原文。 log_min_error_statement = error 下,业务报错的 SQL 会进日志,其中的常量可能就是敏感数据。合规要求严格的系统要评估级别、加密日志存储并限制访问权限。
容器与 systemd 部署有额外一层。 logging_collector = off 时日志进 journal/容器 stdout,多数云环境反而推荐这种「交给进程管理器」的模式;本页的文件化配置主要面向传统部署。两种模式不要混用同一套预期。
最佳实践
- 生产库必配
log_line_prefix,且包含%m [%p] %q%u@%d %b。 时间、进程、用户、数据库、后端类型是所有日志分析的最小需求;需要会话串联就加%c。 - 结构化日志优先选
csvlog或jsonlog。 有现代日志栈(ELK/Loki)直接选jsonlog(PG15+)或csvlog;前者对采集器最友好,格式细节见后续两页。 - 保持
log_min_messages = warning,用单项开关定制内容。 避免整体降级产生海量日志;需要什么(连接、autovacuum、检查点)就开对应开关。 - 错误详细度用
verbose。 SQLSTATE 与DETAIL/HINT是自动化分诊的原料,详细度换来的日志增量完全值得。 - 连接审计标配
log_connections+log_disconnections。 结合本站的审计专题页做留存策略;连接风暴时它能给出「谁在连」的直接证据。 - 日志目录独立磁盘、独立容量监控。 日志盘使用率告警阈值要比数据盘更严(如 70%),因为日志增速最难预测。
- 改日志配置先核对生效方式。 用
pg_settings的source与pending_restart字段确认配置来源与是否需要重启,减少无效折腾。 - 错误语句原文的合规评估前置。 确定保留
log_min_error_statement = error之前,先过一遍数据分级;必要时收紧级别并用日志侧加密与访问控制补偿。 - 容器部署明确日志归属。 明确「collector 文件化」还是「stdout 交给平台」,并在文档里写死,避免两套预期并存。
- 每次变更后用真实消息验证格式。 制造一条已知错误(如
SELECT 1/0),检查时间戳、前缀、级别、语句原文都符合预期,再收工。
下一节
继续学习:日志轮转与清理