Linux Logrotate日志切割配置与自动清理详解

作者:技术拾光时间:2026-07-07 09:20:18浏览:197

谈到日志管理,logrotate 是 Linux 系统管理员最熟悉的工具之一。它通常随系统预装,开箱即用,但默认配置只是一个通用模板。要让其精准地为你的应用服务,关键是直接修改 /etc/logrotate.d/ 目录下的专属配置文件,而不是修改总开关 /etc/logrotate.conf。 如何

谈到日志管理,logrotate 是 Linux 系统管理员最熟悉的工具之一。它通常随系统预装,开箱即用,但默认配置只是一个通用模板。要让其精准地为你的应用服务,关键是直接修改 /etc/logrotate.d/ 目录下的专属配置文件,而不是修改总开关 /etc/logrotate.conf。

Linux Logrotate日志切割配置与自动清理详解

如何判断 logrotate 是否在运行

首先需要明确:logrotate 本身不是常驻后台的守护进程,它依赖系统的 cron 定时任务触发执行。因此,检查它是否“活着”,其实就是检查其触发机制是否正常。

以下几个命令可以快速验证:

  • ls -l /etc/cron.daily/logrotate:如果该文件存在,基本说明系统已配置每日自动执行。
  • grep logrotate /var/lib/logrotate/status:查看状态文件中记录的各日志最近一次轮转的时间戳,这是一个很好的参考。
  • systemctl list-timers | grep logrotate:在较新的系统(使用 systemd)上,用此命令确认是否有对应的定时器活跃运行。

如果以上检查均无反应,不必急于重装 logrotate,问题很可能出在 cron 服务本身。使用 systemctl status cron 或 systemctl status crond 检查 cron 服务是否正常运行,同时检查 /etc/cron.daily/ 目录下的 logrotate 脚本是否被意外注释或修改。

为什么 daily 配置没有按时切割

这是新手常遇到的误区。配置了 daily 后,第二天日志并未自动切割,问题通常出在 logrotate 的工作原理上。

它的时间判断依赖状态文件 /var/lib/logrotate/status,该文件只在实际执行轮转操作后才会更新。这导致几个典型场景:

  • 首次配置不生效:今天下午配置了 daily,它不会立刻切割。需要等到明天 cron 任务执行时,才会检查“距离上次记录是否已满24小时”。由于首次没有记录,行为可能模糊,可能会执行也可能不执行。
  • 空日志文件:默认情况下,如果启用了 notifempty 选项(很多配置默认启用),即使时间到了,但日志文件为空,logrotate 也会跳过轮转。
  • 路径陷阱:missingok 选项允许日志文件不存在时不报错,但也容易掩盖问题——日志路径错误。例如将 /var/log/nginx/access.log 拼写为 /var/log/nginx/acess.log,logrotate 会因 missingok 静默跳过,造成配置无问题的假象。
  • 权限与信号:logrotate 通常以 root 身份运行,但在 postrotate 脚本中使用类似 kill -USR1 `cat /var/run/nginx.pid` 的命令通知服务重新打开日志时,需要确保两点:一是 pid 文件可读,二是 nginx 主进程由 root 启动(或当前用户有权限向该进程发送信号),否则信号发送会失败。

如何安全测试新配置,不破坏线上服务

在线上环境修改日志配置,最担心的是“手一抖,服务抖三抖”。因此必须遵循安全的测试流程,而不是等待 cron 触发。

第一步,始终先用调试模式模拟一遍:

logrotate -d -f /etc/logrotate.d/myapp

-d(debug)参数至关重要。它会完整模拟整个轮转过程,包括读取配置、检查条件、计划执行的操作,但不会实际重命名、压缩任何文件,也不会运行 postrotate 脚本。只在终端打印出它“打算”做什么。

需要重点关注输出中的以下几行:

  • rotating pattern:确认是否正确识别了配置的日志文件路径。
  • switching to configuration file:确认加载的是刚修改的配置文件。
  • 任何以 error: 开头的行:直接暴露语法错误或路径权限等致命问题。

模拟执行无误后,第二步再强制执行一次轮转:

logrotate -f /etc/logrotate.d/myapp

执行后,立即进行现场检查:

  1. 查看原日志文件是否按预期变成空文件(如果使用了 copytruncate)或被重命名(如果使用了 create)。
  2. 检查新生成的日志文件权限、属主是否与配置中 create 0644 user group 设置一致。
  3. 最关键的一步:使用 tail -f 原日志路径 命令持续跟踪,确认应用服务是否仍在正常向该文件写入新日志内容。如果写入停止,说明服务可能因文件句柄问题“卡住”。

copytruncate 与 create 的选择关键点

这是 logrotate 配置的核心二选一,它们解决不同维度的“日志丢失”风险,用错场景会带来灾难。

copytruncate:
这是为“不听话”的服务准备的保底方案。有些应用(如某些 Java 程序、自写守护进程)无法通过信号通知其重新打开日志文件,此时使用 copytruncate。其逻辑是:先复制当前日志内容,然后清空原文件。服务可以继续向被清空的原文件描述符写入,无需重启。
代价:在“复制”和“清空”两个操作之间存在极短的窗口期。如果恰好在几毫秒内出现大量日志写入,可能丢失这部分数据。因此,它以“可能丢失微量日志”的风险换取了服务的绝对连续性。

create:
这是标准、优雅的做法。logrotate 将当前日志文件重命名(例如从 app.log 变为 app.log.1),然后创建一个同名的空文件(app.log)。
前提:服务必须能响应 postrotate 脚本中发送的信号(例如给 Nginx 发送 USR1,给 Apache 发送 USR1 或使用 graceful),使其关闭旧文件句柄,重新打开新创建的文件。如果服务不响应信号,它会继续向已被重命名的旧文件(现在是 app.log.1)写入日志,导致看不到最新日志,仿佛日志“消失”。

另一个容易出错的细节是 sharedscripts 指令。如果配置匹配多个日志文件(例如使用通配符 /var/log/myapp/*.log),并且配置了 postrotate 脚本,那么必须加上 sharedscripts。否则,logrotate 会为每个匹配的日志文件单独执行一遍 postrotate 脚本。例如,原本只需让 Nginx 重启一次日志句柄,但因为匹配了 access.log 和 error.log,kill -USR1 会执行两次,很可能导致错误。

归根结底,无论选择哪种方式,最根本的是:必须了解应用程序如何处理日志文件。有些程序会缓存文件描述符,或不检查文件 inode 的变化。对这类程序,create 模式可能失效,copytruncate 是唯一可用的选项,但必须接受其微小的数据丢失风险。弄清服务的日志写入机制,才是配置成功的基石。