在Linux系统运维中,日志文件是排查问题、追溯操作的核心依据,但随着系统持续运行,日志会不断累积,轻则占用大量磁盘空间,重则导致磁盘满溢,影响服务正常运行。logrotate作为Linux系统内置的日志管理工具,无需手动干预,就能自动完成日志的切割、归档、压缩、清理等操作,是运维人员必备的基础工具之一。本文将从原理、配置、实战到排错,全方位拆解logrotate,让新手也能快速上手并灵活运用。
一、logrotate 核心工作逻辑(通俗理解)
logrotate的核心作用,就是“给不断变大的日志文件‘瘦身’”,其运行逻辑可简单拆解为5个步骤,无需复杂技术背景也能看懂:
定时触发:系统通过crond定时任务(默认路径/etc/cron.daily/logrotate),每天凌晨自动执行logrotate程序,无需手动启动。
读取配置:logrotate会优先读取全局配置文件/etc/logrotate.conf,再加载/etc/logrotate.d/目录下的所有应用独立配置(比如nginx、mysql的专属日志配置),独立配置会覆盖全局配置,更具针对性。
判断触发条件:根据配置中设定的“时间”或“日志大小”,判断是否需要对日志进行轮转(切割),其中“大小”条件的优先级高于“时间”条件。
执行轮转操作:核心流程为“原日志→归档日志→新建空日志”,例如access.log会先重命名为access.log.1(或带日期的格式),再新建一个空的access.log供程序继续写入,旧日志会按规则保留、压缩,超出保留数量的旧日志自动删除。
记录状态:通过/var/lib/logrotate/status文件,记录每一个日志文件的上次轮转时间,避免一天内重复轮转,确保轮转逻辑有序执行。
关键提醒:logrotate本身不具备定时功能,完全依赖crond定时任务驱动,若crond服务未启动,logrotate将无法自动执行。
二、logrotate 核心文件结构(必记)
logrotate的配置体系分为“全局配置+独立配置”,再加上一个状态记录文件,三者协同工作,缺一不可,具体如下:
1. 全局配置文件:/etc/logrotate.conf
这是logrotate的默认全局规则,所有应用的日志轮转都会继承这里的配置,除非在独立配置中明确覆盖。常见默认配置如下(附带通俗解读):
# 全局默认轮转周期(每周轮转一次)
weekly
# 保留4份旧日志,超出的自动删除
rotate 4
# 轮转后自动新建一个空日志,供程序继续写入
create
# 旧日志后缀用日期格式(如xxx-20260519),替代默认的数字后缀(.1、.2)
dateext
# 加载/etc/logrotate.d/目录下的所有独立配置文件(核心,实现分应用管理)
include /etc/logrotate.d
# 不发送日志相关的邮件通知(避免冗余邮件)
nomail
2. 应用独立配置目录:/etc/logrotate.d/
为了方便管理不同服务的日志,我们会在这个目录下为每个服务创建单独的配置文件(如nginx、mysql、tomcat等),独立配置的优先级高于全局配置,可根据服务特性灵活设置。例如,nginx的日志轮转配置文件就是/etc/logrotate.d/nginx,mysql的则是/etc/logrotate.d/mysql。
核心优势:分服务配置,互不干扰,后续修改某一个服务的日志轮转规则,无需改动全局配置,降低运维风险。
3. 状态记录文件:/var/lib/logrotate/status
该文件用于记录每一个被管理日志的上次轮转时间,格式非常简单,每行对应一个日志文件,例如:
"/var/log/nginx/access.log" 2026-05-18
"/var/log/mysql/error.log" 2026-05-17
通过查看这个文件,可以快速判断某条日志是否正常轮转,若出现轮转异常,可先检查该文件的记录是否正常。
三、核心配置参数(实战必备)
logrotate的配置参数非常多,但核心常用参数只有十几个,按“功能分类”整理,结合示例说明,新手可直接复制到配置文件中使用,无需死记硬背。
1. 轮转触发条件(二选一,核心参数)
触发条件决定了“什么时候对日志进行轮转”,分为时间触发和大小触发,两者可共存,且大小触发的优先级更高(只要达到指定大小,无论时间是否到,都会触发轮转)。
参数 | 通俗含义 | 实战示例 |
|---|
daily | 每天轮转一次(默认凌晨执行) | daily(直接写入配置) |
weekly | 每周轮转一次(默认周日执行) | weekly |
monthly | 每月1号轮转一次 | monthly |
size | 日志达到指定大小后触发轮转 | size 100M(达到100M轮转)、size 1G(达到1G轮转) |
2. 旧日志保留与命名规则
这部分参数控制旧日志的保留数量、命名格式,避免旧日志过多占用磁盘空间。
rotate N:保留最近N份旧日志,超出N份的自动删除(N为数字),示例:rotate 30(保留30份,适合需要长期追溯日志的场景)。
dateext:旧日志后缀用日期格式(如access.log-20260519),替代默认的数字后缀(access.log.1),方便快速定位某一天的日志。
dateformat .%Y%m%d:自定义日期后缀格式,默认是“-日期”,可修改为“.%Y%m%d”(如access.log.20260519),%Y(年)、%m(月)、%d(日)为固定占位符。
olddir 路径:将归档后的旧日志移动到指定目录(需与原日志在同一分区,否则无法移动),示例:olddir /var/log/oldlogs(将旧日志放到/var/log/oldlogs目录)。
3. 旧日志压缩相关(节省磁盘空间)
日志文件通常可以压缩到原大小的1/10左右,开启压缩能大幅节省磁盘空间,核心参数如下:
compress:开启gzip压缩,归档后的旧日志会变成.gz格式(如access.log-20260519.gz),默认开启。
delaycompress:延迟压缩,本次轮转产生的旧日志(如access.log.1),下次轮转时再进行压缩。核心作用:避免程序还在向旧日志写入数据时,压缩导致日志损坏,生产环境建议必加。
nocompress:关闭压缩,适合日志量小、无需节省空间的场景(不推荐生产环境使用)。
4. 新建日志的权限与归属
轮转后会新建一个空日志,若权限或归属不正确,可能导致程序无法写入日志(出现权限拒绝错误),核心参数:
5. 容错与空日志处理(生产必加)
生产环境中,可能出现日志文件不存在、日志为空的情况,若不配置容错参数,logrotate会报错,影响其他日志的轮转,核心参数:
missingok:日志文件不存在时,不报错,继续执行其他日志的轮转(生产必加,避免因单个日志缺失导致整体轮转失败)。
notifempty:日志为空时,不进行轮转(避免生成大量空的归档日志,浪费空间)。
ifempty:即使日志为空,也进行轮转(默认参数,不推荐生产环境使用)。
6. 脚本触发(解决日志写入异常的核心)
这是最容易踩坑的地方!很多程序(如nginx、apache)会持续占用原日志文件的句柄,即使logrotate将原日志重命名,程序依然会向旧日志文件写入数据,导致新日志为空、旧日志持续变大。此时,就需要通过脚本发送信号,让程序重新加载日志,释放旧句柄,开始向新日志写入。
核心脚本相关参数:
prerotate:轮转之前执行的脚本(如备份日志、停止服务,很少用)。
postrotate:轮转之后执行的脚本(核心,用于发送信号,让程序重新加载日志)。
sharedscripts:当配置通配符日志(如/var/log/nginx/*.log)时,只执行一次脚本,避免每个日志文件都执行一次脚本(冗余且可能出错)。
endscript:脚本结束标记,必须与prerotate或postrotate成对出现。
最常用的脚本示例(nginx日志轮转后重新加载):
postrotate
# 向nginx进程发送USR1信号,重新加载日志(不停止服务)
/usr/bin/kill -USR1 $(cat /run/nginx.pid) > /dev/null 2>&1 || true
endscript
注意:不同程序的信号不同,nginx用USR1,apache用USR1,mysql用flush-logs,需根据程序特性调整。
7. 其他常用参数
copytruncate:复制原日志文件的内容到归档日志,然后清空原日志,不进行重命名。适合无法发送信号、无法重新加载日志的程序(如部分自定义Java程序),缺点是复制和清空之间有极短的时间差,可能丢失少量日志。
mail 邮箱地址:将被删除的旧日志发送到指定邮箱(不推荐,日志量大时会导致邮箱满溢)。
nomail:不发送日志相关邮件(默认参数,推荐保留)。
四、实战配置示例(生产直接复制可用)
结合上面的参数,整理3个最常用的实战配置,覆盖nginx、Java程序、mysql,新手可直接复制到对应配置文件中,只需根据自身路径调整即可。
示例1:Nginx 日志轮转配置(/etc/logrotate.d/nginx)
适配nginx的access.log和error.log,每日轮转、达到500M也轮转,保留30天日志,开启延迟压缩,自动重新加载日志,生产环境通用。
# 匹配nginx的所有日志文件
/var/log/nginx/*.log {
daily # 每日轮转
size 500M # 达到500M也触发轮转
rotate 30 # 保留30份旧日志(30天)
dateext # 日期后缀
compress # 开启压缩
delaycompress # 延迟压缩(避免日志损坏)
missingok # 日志不存在不报错
notifempty # 空日志不轮转
create 640 nginx nginx # 新建日志权限和归属
sharedscripts # 通配符日志只执行一次脚本
postrotate # 轮转后执行脚本,重新加载nginx日志
/usr/bin/kill -USR1 $(cat /run/nginx.pid) > /dev/null 2>&1 || true
endscript
}
示例2:Java程序日志轮转配置(/etc/logrotate.d/java-app)
很多Java程序无法发送信号重新加载日志,因此用copytruncate参数,避免日志写入异常,适合大部分自定义Java服务。
# Java程序日志路径(根据自身实际路径修改)
/home/app/logs/app.log {
daily # 每日轮转
size 200M # 达到200M触发轮转
rotate 15 # 保留15份旧日志(15天)
dateext # 日期后缀
compress # 开启压缩
missingok # 日志不存在不报错
notifempty # 空日志不轮转
copytruncate # 复制+清空原日志,不重命名
}
示例3:MySQL 日志轮转配置(/etc/logrotate.d/mysql)
MySQL的错误日志和慢查询日志,轮转后需要刷新日志,避免影响MySQL服务。
# MySQL日志路径(根据自身实际路径修改)
/var/log/mysql/*.log {
weekly # 每周轮转
size 1G # 达到1G触发轮转
rotate 8 # 保留8份旧日志(2个月)
dateext
compress
delaycompress
missingok
notifempty
create 640 mysql mysql
sharedscripts
postrotate
# 刷新MySQL日志,无需停止服务
/usr/bin/mysqladmin -u root -p'your_password' flush-logs > /dev/null 2>&1 || true
endscript
}
注意:MySQL的flush-logs需要root权限,若配置了密码,需替换your_password为实际MySQL root密码;若未设置密码,可删除-p'your_password'。
五、常用命令(实操必备)
logrotate的命令非常简单,核心常用命令只有4个,主要用于手动测试、调试和查看状态,无需复杂操作。
强制手动执行轮转(核心测试命令):无视时间和大小条件,立即对指定配置的日志进行轮转,用于测试配置是否正确。 logrotate -f /etc/logrotate.d/nginx说明:-f 表示force(强制),后面跟配置文件路径,执行后可查看日志是否正常切割、新建。
调试模式(推荐):不实际执行轮转操作,只输出执行过程,用于排查配置错误(比如脚本写错、路径错误)。 logrotate -d /etc/logrotate.d/nginx说明:-d 表示debug(调试),执行后会输出详细的执行步骤,若有错误,会明确提示错误原因(如权限不足、路径不存在)。
详细输出模式:实际执行轮转,并输出详细执行过程,用于确认轮转是否正常。 logrotate -v /etc/logrotate.d/nginx说明:-v 表示verbose(详细),执行后会显示每一步的操作结果(如是否轮转、是否压缩、是否执行脚本)。
查看轮转状态:查看每个日志的上次轮转时间,判断是否正常轮转。 cat /var/lib/logrotate/status
六、常见坑与避坑指南(生产必看)
新手使用logrotate时,很容易遇到各种异常,以下是5个最常见的坑,结合原因和解决方案,帮你快速避坑。
坑1:轮转后,程序依然向旧日志写入,新日志为空
原因:程序持续占用原日志文件句柄,重命名后未释放,依然向旧文件写入数据。
解决方案:在配置中添加postrotate脚本,发送信号让程序重新加载日志(优先推荐);若程序无法发送信号,改用copytruncate参数(注意少量日志丢失风险)。
坑2:一天内多次轮转,日志频繁切割
原因:若配置了size参数,日志达到指定大小就会触发轮转,一天内可能多次触发(属于正常现象);若未配置size参数,一天内多次轮转,大概率是手动执行了-f命令,或状态文件异常。
解决方案:若不需要大小触发,删除size参数;若需要,属于正常情况,无需处理;若状态文件异常,可删除/var/lib/logrotate/status文件,logrotate会重新生成。
坑3:轮转失败,提示“权限不足”
原因:logrotate执行时的权限(默认是root),无法新建日志、无法修改日志文件,或无法执行脚本。
解决方案:1. 配置create参数,指定正确的权限、属主、属组;2. 确保脚本有执行权限(chmod +x 脚本路径);3. 检查日志文件的属主属组,确保root有权限操作。
坑4:日志丢失,部分日志未归档
原因:1. 使用copytruncate参数时,复制和清空之间有极短时间差,导致少量日志丢失;2. 日志文件路径配置错误,logrotate未匹配到日志文件;3. 保留数量设置过小,旧日志被提前删除。
解决方案:1. 优先用postrotate脚本替代copytruncate;2. 检查日志路径是否正确,确保通配符(*)匹配正确;3. 适当增大rotate参数,保留更多旧日志。
坑5:通配符日志(*.log),脚本被重复执行
原因:未配置sharedscripts参数,logrotate会为每个匹配到的日志文件执行一次脚本,导致重复发送信号,影响服务正常运行。
解决方案:在配置中添加sharedscripts参数,确保通配符日志只执行一次脚本。
七、进阶:自定义轮转周期(小时级轮转)
默认情况下,logrotate由/etc/cron.daily/logrotate驱动,每天执行一次,若需要更频繁的轮转(如每小时轮转,适合日志量极大的服务,如高并发nginx),可自定义执行周期,步骤如下:
创建小时级定时任务文件: touch /etc/cron.hourly/logrotate
复制每日定时任务的内容到小时级文件中(保持执行权限一致): cp /etc/cron.daily/logrotate /etc/cron.hourly/
修改对应服务的logrotate配置,添加hourly参数(触发条件改为每小时轮转):/var/log/nginx/*.log {
hourly # 每小时轮转
size 100M # 达到100M也触发
rotate 24 # 保留24份(1天)
# 其他参数不变...
}
重启crond服务,使定时任务生效: systemctl restart crond
注意:小时级轮转会产生大量归档日志,需合理设置rotate参数(如保留24份,对应1天),避免占用过多磁盘空间。
总结
logrotate的核心价值的是“自动化日志管理”,无需手动干预,就能解决日志膨胀的问题,是Linux运维的必备工具。其核心要点可总结为3点:1. 配置体系(全局+独立),灵活管理不同服务;2. 触发条件(时间+大小),按需设置轮转频率;3. 脚本触发(postrotate),解决日志写入异常。
新手入门时,可先复制本文的实战配置,根据自身服务的日志路径、需求调整参数,再用-d调试模式测试配置,确认无误后正常使用;遇到异常时,优先查看状态文件和调试输出,结合避坑指南快速排查,就能轻松掌握logrotate的使用。