PostgreSQL日志

PostgreSQL日志系统是数据库管理和故障排查的重要工具。通过合理配置和分析日志,可以监控数据库运行状态、诊断问题、优化性能并确保安全性。PostgreSQL提供了丰富的日志选项,可以记录从基本错误信息到详细查询执行计划的各种信息。本章将详细介绍PostgreSQL日志系统的配置、管理和分析方法。

PostgreSQL日志系统概述

PostgreSQL日志系统提供了多种类型的日志,用于记录数据库的不同方面信息。

日志类型

  • 错误日志(Error Log):记录数据库错误、警告和通知信息
  • 查询日志(Query Log):记录执行的SQL语句
  • 连接日志(Connection Log):记录客户端连接和断开信息
  • 锁日志(Lock Log):记录锁等待和死锁信息
  • 自动清理日志(Autovacuum Log):记录自动清理操作
  • 检查点日志(Checkpoint Log):记录检查点操作
  • WAL日志(Write-Ahead Log):记录数据修改操作

日志级别从低到高:

级别 说明
DEBUG 调试信息,用于开发和故障排查
INFO 一般信息,记录正常操作
NOTICE 需要注意的信息
WARNING 警告信息,可能存在问题
ERROR 错误信息,操作失败
LOG 管理日志信息
FATAL 致命错误,导致会话终止
PANIC 系统恐慌,导致所有会话终止

基本日志配置

通过postgresql.conf文件配置日志系统的基本参数。

日志目的地配置

# postgresql.conf 日志配置示例

# 日志输出目的地
log_destination = 'stderr'          # 可选: stderr, csvlog, syslog, eventlog
logging_collector = on              # 启用日志收集器
log_directory = 'log'               # 日志目录
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'  # 日志文件名模式
log_file_mode = 0600                # 日志文件权限
log_truncate_on_rotation = off      # 日志轮转时是否截断
log_rotation_age = 1d               # 日志轮转时间间隔
log_rotation_size = 100MB           # 日志轮转文件大小

# CSV日志配置
log_destination = 'csvlog'
log_statement = 'all'
log_min_duration_statement = 0

错误日志配置

# 错误报告配置
log_min_messages = warning          # 记录的最低消息级别
log_min_error_statement = error     # 记录错误SQL语句的最低级别
log_error_verbosity = default       # 错误详细程度 (terse, default, verbose)
log_stack_trace = on                # 是否记录堆栈跟踪

# 客户端连接日志
log_connections = on                 # 记录连接
log_disconnections = on             # 记录断开连接
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '  # 日志行前缀

# 锁相关日志
log_lock_waits = on                 # 记录锁等待
deadlock_timeout = 1s               # 死锁检测超时时间

# 自动清理日志
log_autovacuum_min_duration = 0     # 记录所有自动清理操作

查询日志配置

查询日志可以记录执行的SQL语句,用于性能分析和审计。

SQL语句日志

# SQL语句日志配置
log_statement = 'none'              # 记录SQL语句 (none, ddl, mod, all)
# none: 不记录任何SQL语句
# ddl: 记录数据定义语言 (CREATE, ALTER, DROP)
# mod: 记录数据修改语言 (INSERT, UPDATE, DELETE, TRUNCATE, COPY)
# all: 记录所有SQL语句

# 慢查询日志
log_min_duration_statement = 1000   # 记录执行时间超过1秒的语句 (毫秒)
log_duration = on                   # 记录所有语句的执行时间

# 示例配置
log_statement = 'mod'               # 记录DDL和DML语句
log_min_duration_statement = 500    # 记录超过500毫秒的查询
log_duration = on                   # 记录执行时间
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h,duration=%m '

详细查询日志

# 详细的查询执行信息
log_parser_stats = off              # 记录解析器统计信息
log_planner_stats = off             # 记录规划器统计信息
log_executor_stats = off            # 记录执行器统计信息
log_statement_stats = off           # 记录语句统计信息

# 启用详细统计(性能开销较大)
log_parser_stats = on
log_planner_stats = on
log_executor_stats = on

# 查询计划日志
debug_print_parse = off             # 打印解析树
debug_print_rewritten = off         # 打印重写查询
debug_print_plan = off              # 打印执行计划
debug_pretty_print = on             # 美化打印输出

# 示例:记录详细查询信息
log_statement = 'all'
log_duration = on
debug_print_plan = on
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '

日志管理

有效的日志管理包括日志轮转、清理和监控。

日志轮转配置

# 日志轮转配置
log_rotation_age = 1d               # 每天轮转一次
log_rotation_size = 100MB           # 或者文件达到100MB时轮转
log_truncate_on_rotation = off      # 轮转时创建新文件而不是截断

# 按小时轮转
log_rotation_age = 1h
log_filename = 'postgresql-%Y-%m-%d_%H.log'

# 按文件大小轮转
log_rotation_age = 0                # 禁用时间轮转
log_rotation_size = 50MB            # 每50MB轮转
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'

# 保留日志文件数量
# 通过外部工具管理,如logrotate

使用logrotate管理日志

# /etc/logrotate.d/postgresql
/var/lib/pgsql/data/log/*.log {
    hourly
    rotate 168
    compress
    delaycompress
    missingok
    notifempty
    create 0600 postgres postgres
    postrotate
        /usr/bin/pg_ctl reload -D /var/lib/pgsql/data >/dev/null 2>&1 || true
    endscript
}

# 或者使用天级轮转
/var/lib/pgsql/data/log/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 0600 postgres postgres
    postrotate
        /usr/bin/pg_ctl reload -D /var/lib/pgsql/data >/dev/null 2>&1 || true
    endscript
}

日志清理脚本

#!/bin/bash
# PostgreSQL日志清理脚本 cleanup_logs.sh

# 配置变量
LOG_DIR="/var/lib/postgresql/data/log"
RETENTION_DAYS=30

# 删除指定天数前的日志文件
find $LOG_DIR -name "postgresql-*.log" -name "postgresql-*.log.gz" -mtime +$RETENTION_DAYS -delete

# 压缩旧日志文件
find $LOG_DIR -name "postgresql-*.log" -mtime +7 -exec gzip {} \;

# 统计日志文件大小
echo "Log directory size:"
du -sh $LOG_DIR

# 检查最大日志文件
echo "Largest log files:"
find $LOG_DIR -name "postgresql-*.log*" -exec ls -lh {} \; | sort -k5 -hr | head -10

# 记录清理操作
echo "$(date): Cleaned up logs older than $RETENTION_DAYS days" >> /var/log/postgresql/cleanup.log

日志分析

通过分析日志文件可以发现性能问题、安全威胁和系统异常。

常用日志分析命令

# 查看错误日志
tail -f /var/lib/postgresql/data/log/postgresql-*.log

# 查找错误信息
grep -i "error" /var/lib/postgresql/data/log/postgresql-*.log

# 查找警告信息
grep -i "warning" /var/lib/postgresql/data/log/postgresql-*.log

# 查找慢查询
grep "duration:" /var/lib/postgresql/data/log/postgresql-*.log | grep -v "duration: 0" 

# 统计慢查询数量
grep "duration:" /var/lib/postgresql/data/log/postgresql-*.log | awk -F'duration: ' '{if($2+0 > 1000) print $0}' | wc -l

# 查找连接信息
grep "connection received" /var/lib/postgresql/data/log/postgresql-*.log
grep "disconnection" /var/lib/postgresql/data/log/postgresql-*.log

# 统计连接数
grep "connection received" /var/lib/postgresql/data/log/postgresql-*.log | wc -l

# 查找死锁信息
grep "deadlock" /var/lib/postgresql/data/log/postgresql-*.log

# 查找自动清理信息
grep "automatic vacuum" /var/lib/postgresql/data/log/postgresql-*.log

日志分析脚本

#!/bin/bash
# PostgreSQL日志分析脚本 analyze_logs.sh

LOG_FILE="/var/lib/postgresql/data/log/postgresql-$(date +%Y-%m-%d).log"

# 分析慢查询
echo "=== Slow Queries (over 1 second) ==="
grep "duration:" $LOG_FILE | awk -F'duration: ' '{if($2+0 > 1000) print $0}' | head -10

# 分析错误信息
echo -e "\n=== Error Messages ==="
grep -i "error\|fatal\|panic" $LOG_FILE | head -10

# 分析警告信息
echo -e "\n=== Warning Messages ==="
grep -i "warning" $LOG_FILE | head -10

# 连接统计
echo -e "\n=== Connection Statistics ==="
echo "Total connections: $(grep "connection received" $LOG_FILE | wc -l)"
echo "Total disconnections: $(grep "disconnection" $LOG_FILE | wc -l)"

# 自动清理统计
echo -e "\n=== Autovacuum Operations ==="
echo "Autovacuum operations: $(grep "automatic vacuum" $LOG_FILE | wc -l)"

# 死锁检测
echo -e "\n=== Deadlock Information ==="
grep "deadlock" $LOG_FILE

# 生成报告
echo -e "\n=== Summary Report ==="
echo "Log file: $LOG_FILE"
echo "File size: $(du -h $LOG_FILE | cut -f1)"
echo "Date range: $(head -1 $LOG_FILE | cut -d' ' -f1) to $(tail -1 $LOG_FILE | cut -d' ' -f1)"

使用pgBadger分析日志

# 安装pgBadger
# Ubuntu/Debian
sudo apt-get install pgbadger

# CentOS/RHEL
sudo yum install pgbadger

# 配置PostgreSQL生成CSV日志
# 在postgresql.conf中添加
log_destination = 'csvlog'
log_statement = 'all'
log_min_duration_statement = 0

# 生成HTML报告
pgbadger /var/lib/postgresql/data/log/*.csv -o report.html

# 指定时间范围
pgbadger /var/lib/postgresql/data/log/*.csv -b "2025-10-15 00:00:00" -e "2025-10-15 23:59:59" -o daily_report.html

# 包含查询详情
pgbadger /var/lib/postgresql/data/log/*.csv --detail-html --disable-checkpoint --disable-temporary-file -o detailed_report.html

# 自动化报告生成
#!/bin/bash
# daily_report.sh
DATE=$(date +%Y-%m-%d)
pgbadger /var/lib/postgresql/data/log/*.csv -b "$DATE 00:00:00" -e "$DATE 23:59:59" -o "/var/www/html/reports/pg_report_$DATE.html"

日志监控和告警

建立日志监控机制,及时发现和处理异常情况。

实时日志监控

# 使用tail监控实时日志
tail -f /var/lib/postgresql/data/log/postgresql-*.log

# 监控特定错误
tail -f /var/lib/postgresql/data/log/postgresql-*.log | grep -i "error\|fatal\|panic"

# 监控慢查询
tail -f /var/lib/postgresql/data/log/postgresql-*.log | grep "duration:" | awk -F'duration: ' '{if($2+0 > 5000) print $0}'

# 使用 multitail 同时监控多个日志文件
multitail /var/lib/postgresql/data/log/postgresql-*.log

# 使用lnav查看结构化日志
lnav /var/lib/postgresql/data/log/postgresql-*.log

日志告警脚本

#!/bin/bash
# PostgreSQL日志告警脚本 alert_logs.sh

LOG_FILE="/var/lib/postgresql/data/log/postgresql-$(date +%Y-%m-%d).log"
ALERT_EMAIL="admin@example.com"

# 检查错误
ERROR_COUNT=$(grep -i "error\|fatal\|panic" $LOG_FILE | grep "$(date +%Y-%m-%d)" | wc -l)
if [ $ERROR_COUNT -gt 0 ]; then
    echo "PostgreSQL Errors Detected: $ERROR_COUNT errors found in today's log" | mail -s "PostgreSQL Error Alert" $ALERT_EMAIL
fi

# 检查死锁
DEADLOCK_COUNT=$(grep "deadlock" $LOG_FILE | grep "$(date +%Y-%m-%d)" | wc -l)
if [ $DEADLOCK_COUNT -gt 0 ]; then
    echo "PostgreSQL Deadlocks Detected: $DEADLOCK_COUNT deadlocks found in today's log" | mail -s "PostgreSQL Deadlock Alert" $ALERT_EMAIL
fi

# 检查慢查询
SLOW_QUERY_COUNT=$(grep "duration:" $LOG_FILE | awk -F'duration: ' '{if($2+0 > 10000) print $0}' | wc -l)
if [ $SLOW_QUERY_COUNT -gt 5 ]; then
    echo "PostgreSQL Slow Queries: $SLOW_QUERY_COUNT queries over 10 seconds found in today's log" | mail -s "PostgreSQL Slow Query Alert" $ALERT_EMAIL
fi

# 检查连接数
CONNECTION_COUNT=$(grep "connection received" $LOG_FILE | grep "$(date +%Y-%m-%d)" | wc -l)
if [ $CONNECTION_COUNT -gt 1000 ]; then
    echo "High Connection Count: $CONNECTION_COUNT connections today" | mail -s "PostgreSQL Connection Alert" $ALERT_EMAIL
fi

使用ELK Stack分析日志

# 配置Filebeat收集PostgreSQL日志
# filebeat.yml
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/lib/postgresql/data/log/*.log
  fields:
    type: postgresql
  fields_under_root: true

# Logstash配置
# postgresql.conf
input {
  beats {
    port => 5044
  }
}

filter {
  if [type] == "postgresql" {
    grok {
      match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} \[%{NUMBER:pid}\]: \[%{NUMBER:log_line}-1\] user=%{USERNAME:user},db=%{WORD:database},app=%{WORD:application},client=%{IP:client_ip} %{GREEDYDATA:log_message}" }
    }
    date {
      match => [ "timestamp", "yyyy-MM-dd HH:mm:ss" ]
    }
  }
}

output {
  elasticsearch {
    hosts => ["localhost:9200"]
    index => "postgresql-%{+YYYY.MM.dd}"
  }
}

# Kibana可视化配置
# 创建索引模式: postgresql-*
# 创建仪表板显示:
# - 错误趋势图
# - 慢查询统计
# - 连接数监控
# - 用户活动分析

PostgreSQL日志管理最佳实践:

  1. 合理配置日志级别:根据实际需求设置适当的日志级别,避免产生过多日志
  2. 定期轮转日志:配置日志轮转机制,防止日志文件过大
  3. 监控关键指标:重点关注错误、警告、慢查询和连接信息
  4. 使用专业工具:利用pgBadger、ELK等工具进行日志分析
  5. 建立告警机制:对关键事件设置自动告警
  6. 保护日志安全:设置适当的日志文件权限,防止未授权访问
  7. 定期清理日志:根据保留策略定期清理过期日志
  8. 备份重要日志:对包含重要信息的日志进行备份