Skip to content

PostgreSQL 日志配置

PostgreSQL日志是数据库运维中重要的信息来源,它记录了数据库的运行状态、错误信息、慢查询等关键数据。合理配置PostgreSQL日志可以帮助DBA及时发现问题、分析性能瓶颈和进行故障排查。本文将详细介绍PostgreSQL日志的配置方法和最佳实践。

日志配置参数

PostgreSQL提供了丰富的日志配置参数,可以通过修改postgresql.conf文件或使用ALTER SYSTEM命令进行配置。

1. 日志输出配置

日志目标

ini
# 日志输出目标,可以是stderr、csvlog、syslog或eventlog(Windows)
log_destination = 'stderr'  # 标准错误输出

# PostgreSQL 10+ 支持多目标输出
# log_destination = 'stderr,csvlog,syslog'

# 是否将日志输出到控制台(仅在前台运行时有效)
logging_collector = on  # 开启日志收集器,将日志写入文件

日志文件配置

ini
# 日志文件目录
log_directory = 'pg_log'  # 相对路径(相对于data目录)或绝对路径

# 日志文件名称格式
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'  # 时间戳格式

# 日志文件轮换策略
log_rotation_age = 1d  # 每天轮换一次
log_rotation_size = 100MB  # 当文件大小超过100MB时轮换

# 保留的日志文件数量
log_truncate_on_rotation = on  # 同一时间段的日志文件是否覆盖
log_filename = 'postgresql-%a.log'  # 使用星期几作为文件名时,配合truncate使用

# 日志文件权限
log_file_mode = 0640  # 日志文件权限

2. 日志格式配置

日志行前缀

ini
# 日志行前缀格式
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '  # 推荐格式

# 各参数含义:
# %t - 时间戳(格式:YYYY-MM-DD HH:MM:SS UTC)
# %p - 进程ID
# %l - 日志级别
# %u - 用户名
# %d - 数据库名
# %a - 应用程序名
# %h - 客户端主机名或IP地址
# %r - 客户端地址和端口
# %s - 会话ID
# %v - 虚拟事务ID
# %x - 事务ID
# %c - 命令类型
# %i - 命令标签
# %e - SQLSTATE错误代码
# %m - 错误信息
# %n - 换行符
# %b - 后台进程类型
# %q - 被截断的查询(如果log_truncate_on_rotation开启)

日志格式选项

ini
# 是否在日志中包含进程启动时间
log_process_id = on

# 是否在日志中包含会话ID
log_session_identifier = on

# 是否在日志中包含行号
log_line_prefix = '%t [%p]: [%l-1] '  # 包含行号

# 是否在日志中包含应用程序名称
application_name = 'psql'  # 客户端应用程序名称,由客户端设置

3. 日志内容配置

日志级别

ini
# 日志级别,可选值:debug5, debug4, debug3, debug2, debug1, info, notice, warning, error, log, fatal, panic
log_min_messages = warning  # 日志文件中的最小日志级别
client_min_messages = notice  # 发送给客户端的最小日志级别

# 错误报告详细程度
log_error_verbosity = default  # 可选值:terse, default, verbose

# 是否包含错误上下文信息
log_context_lines = 10  # 错误前后显示的上下文行数

查询日志

ini
# 日志记录的语句类型,可选值:none, ddl, mod, all
log_statement = 'none'  # 不记录任何语句
# log_statement = 'ddl'  # 记录所有DDL语句
# log_statement = 'mod'  # 记录所有DDL和DML语句
# log_statement = 'all'  # 记录所有语句

# 记录执行时间超过指定毫秒数的语句
log_min_duration_statement = -1  # -1表示不记录,0表示记录所有语句,>0表示记录超过该时间的语句
# log_min_duration_statement = 1000  # 记录执行时间超过1秒的语句

# 是否记录语句参数
log_parameter_max_length = -1  # -1表示不限制,0表示不记录参数,>0表示记录参数的最大长度
log_parameter_max_length_on_error = -1  # 错误情况下记录参数的最大长度

# 是否记录锁等待
log_lock_waits = on  # 记录等待时间超过deadlock_timeout的锁等待

# 是否记录死锁
log_deadlocks = on  # 记录死锁信息

连接与认证日志

ini
# 是否记录连接尝试
log_connections = on  # 记录成功的连接
log_disconnections = on  # 记录连接断开

# 是否记录认证失败信息
log_failed_connections = on  # 记录认证失败的连接尝试

# 是否记录认证详细信息
log_hostname = on  # 记录客户端主机名而不是IP地址

WAL日志相关

ini
# 是否记录WAL归档信息
log_archive_command = 'cp %p /archive/%f'  # WAL归档命令
log_archive_mode = on  # 开启WAL归档日志

# 是否记录WAL回放信息(备库)
log_replication_commands = on  # 记录复制相关命令
log_statement_stats = off  # 关闭语句统计信息(性能影响大)

4. 统计信息日志

ini
# 是否记录查询执行统计信息
log_statement_stats = off  # 关闭,性能影响大
log_planner_stats = off  # 关闭查询计划统计信息
log_executor_stats = off  # 关闭执行器统计信息

# 是否记录缓冲区统计信息
log_buffer_stats = off  # 关闭缓冲区统计信息

# 是否记录锁统计信息
log_lock_stats = off  # 关闭锁统计信息

# 是否记录IO统计信息(PostgreSQL 13+)
log_io_stats = off  # 关闭IO统计信息

日志格式类型

PostgreSQL支持多种日志格式,包括文本格式、CSV格式和JSON格式。

1. 文本格式

文本格式是PostgreSQL默认的日志格式,易于阅读和分析。

2023-10-15 14:30:25 UTC [12345]: [1-1] user=postgres,db=mydb,app=psql,client=127.0.0.1 LOG:  statement: SELECT * FROM users WHERE id = 1;
2023-10-15 14:30:25 UTC [12345]: [2-1] user=postgres,db=mydb,app=psql,client=127.0.0.1 LOG:  duration: 1.234 ms  statement: SELECT * FROM users WHERE id = 1;

2. CSV格式

CSV格式适合使用电子表格或脚本工具进行分析。

ini
# 启用CSV日志
log_destination = 'csvlog'

CSV日志格式示例:

2023-10-15 14:30:25.123 UTC,12345,1,postgres,mydb,psql,127.0.0.1,,LOG,00000,statement: SELECT * FROM users WHERE id = 1;,<none>,<none>,2023-10-15 14:30:25 UTC,12345,0,0
2023-10-15 14:30:25.124 UTC,12345,2,postgres,mydb,psql,127.0.0.1,,LOG,00000,duration: 1.234 ms  statement: SELECT * FROM users WHERE id = 1;,<none>,<none>,2023-10-15 14:30:25 UTC,12345,0,0

3. JSON格式

从PostgreSQL 14开始,支持JSON格式日志,可以更方便地被日志分析工具处理。

ini
# 启用JSON日志格式
log_destination = 'stderr'
log_line_prefix = ''  # 清空前缀
log_format = 'json'  # 启用JSON格式

JSON日志格式示例:

json
{
  "timestamp": "2023-10-15 14:30:25 UTC",
  "process_id": 12345,
  "session_id": "652b9e81.3039",
  "session_line_num": 1,
  "command_tag": "SELECT",
  "session_start_time": "2023-10-15 14:30:00 UTC",
  "virtual_transaction_id": "3/456",
  "transaction_id": 0,
  "error_severity": "LOG",
  "sql_state_code": "00000",
  "message": "statement: SELECT * FROM users WHERE id = 1;",
  "user_name": "postgres",
  "database_name": "mydb",
  "application_name": "psql",
  "client_addr": "127.0.0.1",
  "client_hostname": "localhost",
  "client_port": 54321,
  "backend_type": "client backend"
}

日志配置最佳实践

1. 生产环境配置建议

ini
# 日志输出配置
log_destination = 'stderr'
logging_collector = on
log_directory = '/var/log/postgresql'
log_filename = 'postgresql-%Y-%m-%d.log'
log_rotation_age = 1d
log_rotation_size = 100MB
log_truncate_on_rotation = off
log_file_mode = 0640

# 日志格式配置
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
log_process_id = on
log_session_identifier = on

# 日志内容配置
log_min_messages = warning
client_min_messages = notice
log_error_verbosity = default
log_context_lines = 10

# 查询日志配置
log_statement = 'ddl'  # 记录DDL语句
log_min_duration_statement = 1000  # 记录执行时间超过1秒的语句
log_lock_waits = on  # 记录锁等待
log_deadlocks = on  # 记录死锁

# 连接与认证日志
log_connections = on
log_disconnections = on
log_failed_connections = on
log_hostname = off  # 生产环境建议关闭,使用IP地址

# WAL相关日志
log_archive_command = 'cp %p /archive/%f'
log_replication_commands = on

# 统计信息日志(生产环境建议关闭)
log_statement_stats = off
log_planner_stats = off
log_executor_stats = off
log_buffer_stats = off
log_lock_stats = off
log_io_stats = off

2. 开发/测试环境配置建议

ini
# 日志输出配置
log_destination = 'stderr,csvlog'
logging_collector = on
log_directory = 'pg_log'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_rotation_age = 1h
log_rotation_size = 50MB

# 日志格式配置
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '

# 日志内容配置
log_min_messages = info
client_min_messages = info
log_error_verbosity = verbose
log_context_lines = 20

# 查询日志配置
log_statement = 'all'  # 记录所有语句
log_min_duration_statement = 0  # 记录所有语句的执行时间
log_lock_waits = on
log_deadlocks = on

# 连接与认证日志
log_connections = on
log_disconnections = on
log_failed_connections = on
log_hostname = on

# 统计信息日志(开发环境可以开启)
# log_statement_stats = on
# log_planner_stats = on
# log_executor_stats = on

3. 慢查询日志配置

ini
# 慢查询日志配置
log_min_duration_statement = 500  # 记录执行时间超过500ms的语句
log_statement = 'none'  # 不记录所有语句,只记录慢查询
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '  # 包含必要信息
log_error_verbosity = default

# PostgreSQL 13+ 支持将慢查询日志写入单独文件
# log_min_duration_sample = 1000  # 采样阈值
# log_statement_sample_rate = 0.1  # 采样率(10%)

日志轮换与归档

1. 内置日志轮换

PostgreSQL内置了日志轮换功能,可以根据时间或大小进行日志轮换:

ini
# 基于时间的轮换
log_rotation_age = 1d  # 每天轮换一次

# 基于大小的轮换
log_rotation_size = 100MB  # 当文件大小超过100MB时轮换

# 日志文件数量限制
# PostgreSQL没有内置的日志文件数量限制,需要使用外部工具管理

2. 使用外部工具进行日志管理

对于生产环境,建议使用外部工具如logrotate来管理日志文件:

logrotate配置示例

ini
# /etc/logrotate.d/postgresql
/var/log/postgresql/postgresql-*.log {
    daily
    rotate 7  # 保留7天的日志
    compress  # 压缩旧日志
    delaycompress  # 延迟压缩,保留最新的一个日志不压缩
    missingok  # 忽略不存在的文件
    notifempty  # 不压缩空文件
    create 0640 postgres postgres  # 创建新文件的权限和所有者
    su postgres postgres  # 以postgres用户身份运行
}

配置cron定期清理日志

bash
# 每月1日清理30天前的日志
0 0 1 * * find /var/log/postgresql -name "postgresql-*.log" -mtime +30 -delete
0 0 1 * * find /var/log/postgresql -name "postgresql-*.log.gz" -mtime +365 -delete

日志配置生效

1. 配置生效方式

sql
-- 方法1:修改postgresql.conf文件后重启PostgreSQL
-- 适用于需要重启才能生效的参数,如logging_collector

-- 方法2:使用ALTER SYSTEM命令(PostgreSQL 9.4+)
ALTER SYSTEM SET log_min_duration_statement = 500;

-- 方法3:使用pg_reload_conf()函数重载配置
SELECT pg_reload_conf();

-- 方法4:使用pg_ctl命令重载配置
pg_ctl reload -D /var/lib/postgresql/14/main

2. 查看当前配置

sql
-- 查看所有日志相关配置
SELECT name, setting, unit, category, short_desc
FROM pg_settings
WHERE category LIKE '%Logging%' OR name LIKE '%log%';

-- 查看特定配置
SHOW log_destination;
SHOW logging_collector;
SHOW log_min_duration_statement;

常见问题与解决方案

1. 日志文件不生成

问题:开启了logging_collector,但日志文件不生成

解决方案

  • 检查log_directory目录是否存在,权限是否正确
  • 检查PostgreSQL进程是否有写权限
  • 查看PostgreSQL错误日志,是否有相关错误信息
  • 验证logging_collector是否真正开启:SHOW logging_collector;

2. 日志文件权限问题

问题:无法查看日志文件,权限被拒绝

解决方案

  • 检查日志文件权限:ls -l /var/log/postgresql/
  • 确保当前用户属于postgres组:groups $USER
  • 调整日志文件权限:chmod 0644 /var/log/postgresql/*.log
  • 修改log_file_mode参数,设置合适的权限

3. 日志过大,占用过多磁盘空间

问题:日志文件增长过快,占用过多磁盘空间

解决方案

  • 调整log_rotation_age和log_rotation_size参数,增加轮换频率
  • 减少日志级别,只记录必要的信息
  • 关闭不必要的日志记录,如log_statement=none
  • 使用logrotate等工具定期清理旧日志
  • 考虑使用JSON格式日志,便于日志分析工具处理

4. 日志格式不符合要求

问题:日志格式不便于分析,缺少必要信息

解决方案

  • 调整log_line_prefix参数,包含必要的字段
  • 考虑使用JSON格式日志,便于机器处理
  • 确保log_process_id和log_session_identifier开启

5. 慢查询日志不记录

问题:设置了log_min_duration_statement,但慢查询不记录

解决方案

  • 检查log_min_duration_statement参数是否正确设置:SHOW log_min_duration_statement;
  • 确保logging_collector开启
  • 检查日志级别,确保慢查询的日志级别被记录
  • 验证查询的执行时间是否确实超过了阈值

版本差异注意事项

PostgreSQL版本差异

版本日志特性差异
PostgreSQL 16增强了JSON日志格式,支持更多字段
PostgreSQL 15改进了日志采样功能,支持更多采样选项
PostgreSQL 14引入了JSON日志格式,支持结构化日志
PostgreSQL 13增强了慢查询日志功能,支持采样和单独文件
PostgreSQL 10支持多目标日志输出
PostgreSQL 9.4引入了ALTER SYSTEM命令,支持在线修改配置
PostgreSQL 9.3引入了log_statement_stats等统计信息日志

日志参数变更

参数版本变更内容
log_destination10+支持多目标输出
log_format14+支持JSON格式
log_min_duration_sample13+新增参数,支持慢查询采样
log_statement_sample_rate13+新增参数,设置采样率
log_replication_commands10+新增参数,记录复制命令
log_io_stats13+新增参数,记录IO统计信息

总结

合理配置PostgreSQL日志是数据库运维的重要组成部分。通过优化日志配置,可以获得更有价值的日志信息,同时减少不必要的性能开销。在配置PostgreSQL日志时,需要根据实际环境(生产、开发、测试)和需求进行调整,平衡日志的详细程度和性能影响。

建议在生产环境中启用必要的日志记录,如DDL语句、慢查询、锁等待和死锁等,同时合理设置日志轮换策略,避免日志文件过大占用过多磁盘空间。对于日志分析,可以使用专业的日志分析工具如pgBadger、ELK Stack等,提高日志分析的效率和准确性。