debug.log 不会运行中轮转:比特币核心日志的启动瘦身 图 1
debug.log 不会运行中轮转:比特币核心日志的启动瘦身 · 图 1

不少教程告诉运维者”debug.log 写满会自动轮转,旧文件改名 debug.log.1 保留”。在 v31.0 源码里核对 logging.cpp 后会发现:运行期并没有把日志改名归档的轮转逻辑,日志文件只会被持续追加。真正会自动缩小这个文件的地方只有一处——启动时执行的 shrinkdebugfile。搞反这两件事,容易在排障时把关键证据删掉。

启动瘦身具体做什么

init/common.cpp 在启动早期调用 ShrinkDebugFile(),源码注释特意说明要抢在任何日志输出之前执行。它的判断很简单:文件体积如果超过一千一百万字节(阈值取历史保留量一千万字节的百分之一百一十),就把内容截断,只保留末尾一千万字节,前面的历史全部丢弃。

是否执行由参数 -shrinkdebugfile 决定,默认值来自 DefaultShrinkDebugFile():没有开 -debug 时为 1,开了 -debug 时为 0。逻辑写得很明白——你在调试模式,就别自动删你的日志;平时运行则替你控制体积。

debug.log 不会运行中轮转:比特币核心日志的启动瘦身 图 2
debug.log 不会运行中轮转:比特币核心日志的启动瘦身 · 图 2

这意味着运行期会发生什么

没有轮转,就没有 debug.log.1、.2 这类归档可等;文件会一路长到下一次启动瘦身为止。所以在长时间不重启的节点上,日志体积可能远超一千万字节,而日志能力(-debug=net-debug=mempool 等分类开关)是主要变量:全开调试分类时一天写出上百 MB 不奇怪,平时默认分类则增长缓慢。

由此派生两个实操结论。第一,排障要留现场:如果你的节点正在出问题,先复制一份 debug.log 再重启,否则启动瘦身会静默把上一轮故障的前段历史截掉。第二,长期运行的节点应该用外部方式管理归档,而不是指望它自我轮转:常见的做法是低峰期正常停机、复制日志、按日期改名留档,这比用 truncate 硬清空安全得多。

日志的开关与去向

写不写文件由 -debuglogfile 控制,传给一个 -nodebuglogfile 就完全停止写文件;-printtoconsole 决定是否同时往终端打。源码在启动时会明确提示日志可能包含隐私敏感信息,分享前需谨慎。默认分类下,日志主要记录连接建立与断开、同步进度、参数生效结果和错误;细粒度分类需要显式开启,而且开了之后体积增长往往比想象快,用 -debug=1 全开是最容易撑爆日志的写法。

顺带说清两个易混参数

-shrinkdebugfile 只在启动生效一次,不是持续策略;而 -printtoconsole-nodebuglogfile 决定的是”看不看得到”,不解决”占不占空间”。有些运维脚本用 cron 定期往日志文件里塞空行或调用外部 logrotate——这类外部轮转与程序自身的文件句柄有竞态风险:进程持有旧句柄继续写入,改名后的文件就成了看不见的黑洞。若确要用外部轮转,配合 copytruncate 类策略并安排在低峰停机后做,比热轮转稳妥。

体积之外的两个细节

其一,日志前缀自带元数据:时间戳、线程名、日志分类和严重级别都在每行开头,排障时先按分类过滤比全文搜索高效得多;-debugexclude 可以反向关掉最吵的分类(比如 net),保留其余细节,是”既要细节又怕体积”时的折中。其二,日志和崩溃不是一回事:进程异常退出时的最后几行可能因为缓冲未刷而缺失,重要故障请以数据目录里的完整文件为准,不要只截终端屏。

一条自检清单

日志异常增长或体积疑问时,按顺序确认:当前是否开着调试分类、是否长期没重启过、-shrinkdebugfile 是否被显式关闭、有没有其他工具在往同一个文件追加。这些都能在节点的数据目录、启动参数和一次正常重启里核实,不需要任何第三方日志中间件。本文所述行为对照 v31.0 源码;早期版本确有运行期日志处理逻辑的演化,跨版本核对请以对应版本源码为准。