简介这是一份开源数据库日志分析工具 pgBadger 11.5 的完整源码包面向 PostgreSQL 运维与研发人员用于快速解析 syslog、stderr、csvlog 等格式的日志并生成可视化图表报告。工具采用纯 Perl 编写内部集成 jQuery 与 jqPlot 等前端库支持直接处理 gzip 压缩日志适合在高并发、大日志量场景下排查慢查询与错误信息。压缩包共含 54 个文件约 2.2MB其中包含 pgbadger 主脚本、Perl 模块、自动化测试用例.t、前端图表资源.js/.css以及 README、ChangeLog、Pod 文档等同时附带多个压缩日志样本和测试夹具便于直接运行验证。已有 440 人学习下载。通过本包可快速部署 pgBadger掌握其日志格式自动识别与报表生成逻辑还可参考测试用例和文档进行二次开发或集成到监控系统适合作为 PostgreSQL 日志分析的实用工具包。1. 先看懂pgBadger一份日志报告替代半小时的SQL排查pgBadger是PostgreSQL日志分析器它把数据库原本零散的运行日志解析成一份按时间线组织的HTML报告。PostgreSQL日志里其实埋着大量诊断信息慢查询、临时文件、checkpoint频率、锁等待、连接数变化……这些内容散落在每天几百MB的文本里人工翻日志找问题通常要花不少时间。pgBadger的价值就是把“翻日志”变成“打开报告”先看概览再定位异常板块最后下钻到具体SQL。它适合两类人一类是DBA和运维工程师每天要巡检数据库另一类是业务侧开发遇到“数据库慢”的反馈不知道从哪里下手用pgBadger先看Top查询和临时文件能快速把问题边界划清楚。需要注意pgBadger只做日志统计不进数据库内部采集指标所以它对现有业务的侵入几乎为零。对大多数PostgreSQL使用者来说这是成本最低的日志分析起步方案。2. 日志侧准备让PostgreSQL先吐出可解析的日志pgBadger不自己访问数据库也不依赖任何扩展它的输入只有一个PostgreSQL的日志文件。所以整个方案的第一道门槛不是安装pgBadger而是确认数据库的日志格式满足解析要求。我在实际运维里见过不少案例日志参数没配全报告里要么缺失板块要么干脆解析不出来。这一章先把日志侧要做的事讲清楚。2.1 先确认日志输出格式stderr还是CSVPostgreSQL的日志输出主要由log_destination决定。常见做法是保持默认的stderr把日志交给日志收集器按文件保存另一种是csvlog字段结构化pgBadger解析起来更稳。两种格式都能做分析但踩坑方式不一样。如果走stderr配置大概是这样的log_destination stderr logging_collector on log_directory log log_filename postgresql-%Y-%m-%d.log log_rotation_age 1d log_rotation_size 0这段配置里log_destination指定输出目标为stderrlogging_collector开启后数据库才会把日志写入文件log_directory和log_filename决定日志文件的存放位置和命名方式log_rotation_age1d让日志按天轮换后续报告归档时容易对账。log_rotation_size0表示不按大小轮换避免一天内出现多个零散文件。CSV格式对应这样配置log_destination csvlog logging_collector on log_filename postgresql-%Y-%m-%d.csvCSV格式的解析速度快字段天然分开时间戳、用户、数据库、查询文本分别占一列pgBadger不需要靠正则猜字段出错的概率低很多。代价是文件体积比stderr略大。如果日常日志动不动就上GB建议直接上CSV后面第5章会专门讲大文件带来的坑。2.2 该打开的日志开关每个参数都对应报告里的一个板块pgBadger报告里有会话、慢查询、临时文件、Checkpoint、锁等待、自动vacuum这些板块。它们不是凭空生成的背后都对应postgresql.conf里的一组开关。下面这组配置是我在实际业务库上常用的底线配置log_line_prefix %m [%p] %q%u%d %h log_checkpoints on log_connections on log_disconnections on log_lock_waits on log_temp_files 0 log_autovacuum_min_duration 0 log_min_duration_statement 500参数逐个说log_line_prefix决定每行日志的前缀格式%m是带毫秒的时间戳pgBadger靠它做时间线排序%p是进程号%u是用户名%d是数据库名%h是客户端地址。这四个字段分别对应报告里按进程、按用户、按数据库的统计维度。如果前缀里没有%mpgBadger对很多行会无法识别报告数字会明显偏少。log_connections和log_disconnections记录会话建立与断开报告里才有连接数变化曲线也能定位连接风暴发生在哪个时间段。log_lock_waits记录锁等待事件搭配锁等待板块定位锁冲突。log_checkpoints记录checkpoint开始与完成报告里会有checkpoint分布与耗时能发现刷盘是否过于频繁。log_temp_files记录临时文件设0表示所有临时文件都记录这个值不是越小越好后面避坑章会展开。log_autovacuum_min_duration记录超过指定时长的autovacuum操作设0表示全记录日志量会增加。log_min_duration_statement是慢查询阈值超过500毫秒的SQL会被记录。参数报告对应板块建议值log_min_duration_statementTop查询、慢查询分析5001000按业务调整log_checkpointsCheckpoint与BGWriter打开log_temp_files临时文件统计0或1024log_lock_waits锁等待打开log_autovacuum_min_durationVACUUM与autovacuum0或1000log_connections会话连接趋势打开这组配置里不建议开log_statementall。log_statement会记录所有SQL文本日志量放大几十倍而pgBadger的分类依赖的是执行耗时和临时文件这些属性不是SQL文本本身。开了log_statementall报告反而会被大量无关语句刷屏慢查询的Top列表失去参考意义。2.3 改完参数后怎么验证别把确认交给运气配置改完要确认真的生效。用psql登进去执行下面三条命令psql -c SHOW log_line_prefix; psql -c SHOW log_min_duration_statement; psql -c SELECT pg_reload_conf();pg_reload_conf()会让大部分参数热加载不需要重启实例。但log_filename这类与日志收集相关的参数改了通常需要重启。如果只是改了log_min_duration_statement、log_lock_waits这种热加载就够。热加载之后再去看一眼原始日志长什么样tail -n 50 /var/lib/postgresql/log/postgresql-$(date %Y-%m-%d).log正常情况下日志里会出现类似这样的行2025-03-14 10:00:00.123 CST [12345] userdb 10.0.0.8 LOG: duration: 512.123 ms statement: select ...这说明%m时间戳、用户信息、耗时都写进日志了pgBadger能拿到完整字段。如果日志里只有SQL没有duration或者时间戳格式对不上先回看2.1节的配置再往下走。我习惯在业务低谷时段做这个验证避免改完参数后短时间看不到慢查询日志误以为没生效。3. 安装与跑出第一份报告从命令到报告板块解读pgBadger本身是perl脚本安装门槛很低。这一章的目标是快速跑出第一份HTML报告并知道先看哪里。3.1 安装pgBadger包管理器、源码、容器最常见做法是直接用发行版仓库安装。Debian系apt-get install pgbadgerRHEL系yum install pgbadger装完先验证版本pgbadger --versionpgBadger对perl版本有要求系统自带的老perl可能会在运行时报错。如果发行版仓库里的pgBadger版本太旧或者没有这个包用源码安装perl Makefile.PL make sudo make install源码安装主要解决仓库版本过旧的问题编译依赖很少perl环境正常就能过。容器场景下我不建议在数据库容器里塞多余的包更习惯用一个专门跑分析任务的临时容器把日志目录挂载进去再执行pgBadger分析完容器直接销毁不污染数据库实例。3.2 最小命令一条命令生成HTML报告运行pgBadger只需要指定日志文件和输出路径pgbadger /var/lib/postgresql/log/postgresql-2025-03-14.log -o report_0314.html如果不指定-f参数pgBadger会按stderr格式解析大多数默认配置都能直接对上。如果你的日志配置是csvlog要显式声明pgbadger -f csv /var/lib/postgresql/log/postgresql-2025-03-14.csv -o report_0314.html这里-o指定输出HTML文件路径-f指定日志格式可选值包括stderr、syslog、csv、json。显式指定格式能避免解析器猜错。跑完在浏览器打开report_0314.html首页是概览能看到日志覆盖时间范围、总会话数、慢查询总数、临时文件统计。先看这几个总量再点进对应板块不要一上来就钻进Top SQL细节里。3.3 报告里先看哪几块慢查询、临时文件、Checkpoint与锁等待pgBadger的报告板块很多初次拿到报告容易迷失。我一般按这个顺序看Top查询默认按总耗时排名能看出哪些SQL累计占掉了数据库大部分时间。点进去能看到每条SQL的执行次数、平均耗时、最大耗时。临时文件如果某天磁盘IO异常先看这一块。临时文件写得多说明排序或哈希操作的内存不够被下放到临时文件往往和work_mem设置或SQL写法相关。Checkpoint观察checkpoint分布是否集中在一两个时间段如果集中说明日志落盘压力集中可能要调整checkpoint相关参数。锁等待应用反馈“卡住”的时候锁等待板块会把等待最严重的库和锁类型列出来方便顺着时间点反查应用日志。VACUUM表和索引膨胀问题被反馈过的话这一块能看出autovacuum是否长时间没跑完或者是否频繁触发。经验阈值上没有绝对标准但有个习惯值得参考某个库的临时文件总量超过几百MB我就会顺着报告里的会话信息往下查多数情况能定位到一条排序或hash join语句。慢查询板块也一样与其只盯总耗时第一不如同时看平均耗时高的语句。这个细节到第5章还会专门讲。报告默认生成HTML图表和表格都打进一个文件里方便直接转发给同事看。如果需要归档把HTML文件命名为带日期和实例角色的形式比如report_orderdb_20250314.html后续检索会省很多事。4. 多日志合并、增量处理与时间范围过滤pgBadger的日常用法升级单日单文件跑通后实际使用中很快就会遇到几个问题日志跨了多天怎么合并、日志文件还在增长怎么写日报、只想看某个时间段怎么办。这一章讲的都是实战里用得上的功能。4.1 多日日志文件合并目录输入是最省事的姿势如果日志已经按日切割直接把多天文件一次性传给pgBadgerpgbadger /var/lib/postgresql/log/postgresql-2025-03-14.log \ /var/lib/postgresql/log/postgresql-2025-03-15.log \ -o report_two_days.html文件多的时候用目录输入pgbadger -d /var/lib/postgresql/log -o report_week.html-d参数让pgBadger遍历目录下的日志文件自动按时间合并生成一份报告。注意这个方式会把目录里所有日志文件都拿进来如果目录里既有stderr日志又有CSV日志或者混着logrotate产生的.gz压缩包解析器会刷出一片WARNING。更干净的做法是给pgBadger准备一个单独目录里面只放它要处理的日志。这里有一个常见误区logrotate切割后会生成postgresql-2025-03-14.log.1、postgresql-2025-03-14.log.1.gz这类文件如果它们和原始日志放在同一目录pgBadger会当成不同文件统计两次。同步的SQL执行次数会翻倍这个问题第5章会再提。4.2 增量处理一个正在增长的日志也能每天出报告很多系统不想为pgBadger额外做日志切割当天日志持续写入这就用到--incrementalpgbadger --incremental \ -O /var/lib/pgbadger/reports \ /var/lib/postgresql/log/current.log--incremental让pgBadger记住上次已解析的字节偏移下次从上次的结尾继续解析不会从头扫一遍。配合-O输出目录增量模式会生成固定命名的报告文件方便每天覆盖写入。增量模式依赖状态文件默认放在输出目录附近由pgBadger自动维护。如果状态文件被清理工具误删它会把整个文件重新解析一遍报告里的数字就会翻倍。这个坑我踩过一次后来写清理脚本时都会把状态文件目录加白名单。4.3 时间范围过滤与排除项只分析问题区间遇到“早上10点到11点数据库特别慢”这种诉求不需要把整天日志都跑一遍。用-b和-e指定时间窗口pgbadger -b 2025-03-14 10:00:00 -e 2025-03-14 12:00:00 \ /var/lib/postgresql/log/postgresql-2025-03-14.log \ -o report_peak.html-b是开始时间-e是结束时间格式是YYYY-MM-DD HH:MM:SS按服务器本地时区解析。输出报告里只会保留这个时间窗口内的事件慢查询排行也只基于这段时间。注意跨时区部署时传入的时间字符串要对齐服务器时区。报告时间比你预期差8小时基本都是时区没有对齐。如果某类日志噪音太大比如autovacuum刷屏、checkpoint频繁用-x排除对应类型pgbadger -x autovacuum,checkpoint \ /var/lib/postgresql/log/postgresql-2025-03-14.log \ -o report_no_noise.html-x后面接逗号分隔的类别常见可选值有query、connection、checkpoint、lock、tempfile、autovacuum。排除类别只影响报告统计不会改动原始日志。按库维度过滤也很常用pgbadger --dbnameorderdb \ /var/lib/postgresql/log/postgresql-2025-03-14.log \ -o report_orderdb.html多业务共库的环境里这个参数很实用只针对某个业务库生成报告排查时不会被其他库的噪声干扰。需要注意dbname过滤依赖日志里%u和%d字段如果log_line_prefix配置不完整过滤结果会偏少。5. 避坑日志解析失败与报告失真现象、原因与解决pgBadger整体很稳定但它对输入格式的要求是刚性的。这一章列了我在实际使用里遇到最多的五个问题按“现象→原因→解决”讲清楚。5.1 报告数字接近为空先查log_line_prefix有没有时间戳现象报告能生成但概览页面的会话数、查询数都接近0日志里大量行没有被解析。原因最常见的是log_line_prefix里没有%mpgBadger解析stderr时依靠前缀里的时间戳识别一行日志的起点结构对不上整条日志就会被当成无法识别的行跳过。另一个原因是log_destination实际是csvlog但命令里没加-f csv解析器按stderr去解析CSV字段必然错位。解决先执行psql -c SHOW log_line_prefix;确认包含%m再打开原始日志看每行开头长什么样如果日志是csvlog命令里显式加上-f csv。最快的验证方式是只拿一小段日志试跑报告数字能对上再用全量文件跑。5.2 同步日志出现重复统计logrotate后的文件被重复传入现象报告里的SQL执行次数明显比实际多Top查询列表里出现同一条SQL的邻近排名。原因目录输入时目录里既有原始日志也有logrotate生成的postgresql-2025-03-14.log.1或.gzpgBadger把它们当成不同文件同一批数据被统计了两遍。解决输入文件时明确指定原始日志如果非要用目录就把logrotate的后缀文件移走或者单独维护一个原始日志目录切割后再把旧文件归档到别处。日志量大的环境我更建议用logrotate的copytruncate或者直接按日命名日志让pgBadger输入的文件名保持稳定。5.3 Top查询排序失真总耗时第一不等于最该优化现象Top查询里排名第一的SQL执行上千次每次平均几十毫秒累计耗时排第一真正单次执行好几秒的SQL排在十名开外。原因pgBadger默认按总耗时排序总耗时是平均耗时乘执行次数。高次数低耗时的语句累计数字大但优化空间有限单次高耗时才是响应时间恶化的主要来源。解决看Top查询时把平均耗时和最大耗时两列一起看重点关注次数低但均值高的记录。我通常会用平均耗时倒序扫一遍先处理单次几百毫秒以上的语句如果业务指标反映的是接口偶发变慢重点看最大耗时列。5.4 临时文件板块噪声大log_temp_files0记录了一切现象临时文件报告统计出大量几KB到几十KB的小文件但磁盘IO指标并没有异常。原因log_temp_files0会把每一次临时文件创建都记录下来排序、哈希、物化都会产生小临时文件许多写入量只有几KB。报告统计的是数量和总量小文件一多板块被噪声刷满真正的大临时文件反而不容易被看到。解决把log_temp_files设成1024也就是只记录超过1MB的临时文件这是生产环境常用的起点值。参数改完热加载即可旧日志文件里已有的记录不受影响需要观察新产生的日志。5.5 pgBadger自身跑不动大日志文件耗时与内存双高现象日志文件几个GB跑一次pgBadger要好几分钟期间内存占用飙到几个GB有时还提示内存不足。原因stderr格式的日志靠正则逐行匹配解析成本与文件行数成正比如果日志里又开了log_statementall文件体积早就失控了。这是输入侧没控制好不是pgBadger的设计问题。解决优先把日志格式切成csvlog解析效率比stderr正则高一个量级再配合按日logrotate保证单日日志不要超过1GB排查问题时先用-b和-e把时间窗口缩小再跑。我最早处理过一个8GB日志硬啃到机器接近翻车后来养成的习惯是先看文件大小大文件先按时间分段。6. 把pgBadger挂在日常巡检里一条命令生成日报并归档日志轮转加定时脚本是pgBadger最省心的落地方式。前面把配置、命令、参数和坑都讲完了最后给出一套可以直接放进crontab里的日报方案。假设日志按日命名为postgresql-YYYY-MM-DD.log#!/bin/bash LOG_DIR/var/lib/postgresql/log OUT_DIR/var/lib/pgbadger/daily YESTERDAY$(date -d yesterday %Y-%m-%d) LOGFILE$LOG_DIR/postgresql-$YESTERDAY.log if [ -f $LOGFILE ]; then pgbadger $LOGFILE -o $OUT_DIR/pgbadger-$YESTERDAY.html \ -T $(hostname) PostgreSQL日报 fi find $OUT_DIR -name pgbadger-*.html -mtime 30 -delete脚本逻辑很直白先确定昨天日期文件名对得上就生成报告-T参数给HTML加上标题报告归档后不用打开就能认出是哪台机器、哪一天的最后清理三十天前的旧报告避免巡检目录无限膨胀。定时任务放在早上业务低峰之后0 7 * * * /opt/scripts/pgbadger_daily.sh /dev/null 21这样每天早上能看到昨天的报告先对比概览里的慢查询数量和临时文件总量跟前一天差异大就点进对应板块看细节。这也是我自己坚持了很久的做法。最初我只开了log_min_duration_statement报告里缺checkpoint和锁等待遇到问题还得回头翻原始日志后来把日志参数配全pgBadger报告才真正成为每天巡检的存档。版本升级后格式有变化时先拿一周历史日志试跑对照报告确认数据正常后再交给定时任务能省去很多返工。希望帮到你。本文还有配套的精品资源点击获取