Linux logrotate命令详解

logrotate 是Linux系统中用于管理系统日志文件的工具,它可以自动轮转、压缩、删除和邮寄日志文件,防止日志文件无限增长占用磁盘空间,同时保持日志文件的完整性和可管理性。

1. 安装与基本配置

1.1 安装logrotate

大多数Linux发行版已经预装了logrotate。如果需要安装:

# Ubuntu/Debian
sudo apt-get update
sudo apt-get install logrotate

# CentOS/RHEL
sudo yum install logrotate

# 检查版本
logrotate --version

1.2 配置文件位置

文件/目录 用途
/etc/logrotate.conf 主配置文件
/etc/logrotate.d/ 应用程序特定的配置文件目录
/var/lib/logrotate/status 记录logrotate执行状态的文件

2. 命令语法

logrotate [选项] 配置文件

3. 常用选项

选项 说明
-d--debug 调试模式,显示执行过程但不实际执行
-f--force 强制轮转,即使不符合条件
-v--verbose 详细模式,显示详细信息
-s--state 指定状态文件位置
-l--log 指定日志文件位置
--version 显示版本信息

4. 配置文件语法详解

4.1 配置文件结构

# 全局配置选项(对所有日志生效)
全局选项

# 特定日志文件配置
/var/log/syslog {
    配置选项
}

# 多个日志文件
/var/log/apache/*.log {
    配置选项
}

4.2 常用配置选项

选项 说明 示例
daily/weekly/monthly 轮转周期 daily
rotate 数字 保留的旧日志文件数量 rotate 7
compress 压缩旧日志 compress
delaycompress 延迟压缩 delaycompress
missingok 日志文件不存在时不报错 missingok
notifempty 日志文件为空时不轮转 notifempty
create 模式 用户 组 创建新日志文件的权限 create 644 root root
postrotate/endscript 轮转后执行的脚本 postrotate
systemctl reload nginx
endscript
size 大小 按大小轮转 size 100M
dateext 使用日期作为扩展名 dateext
dateformat 格式 自定义日期格式 dateformat -%Y%m%d
sharedscripts 多个日志共享脚本 sharedscripts
maxage 天数 保留日志的最大天数 maxage 30
mail address 发送旧日志到指定邮箱 mail admin@example.com

5. 基本配置示例

5.1 简单日志轮转配置

# /etc/logrotate.d/myapp
/var/log/myapp.log {
    daily
    rotate 7
    compress
    missingok
    notifempty
    create 644 myapp myapp
}

5.2 多文件轮转配置

# /etc/logrotate.d/apache
/var/log/apache2/*.log {
    weekly
    rotate 4
    compress
    delaycompress
    missingok
    notifempty
    create 640 root adm
    sharedscripts
    postrotate
        /etc/init.d/apache2 reload > /dev/null
    endscript
}

5.3 按大小轮转配置

# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
    size 100M
    rotate 10
    compress
    delaycompress
    missingok
    notifempty
    create 644 www-data adm
    sharedscripts
    postrotate
        [ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid`
    endscript
}

6. 高级配置示例

6.1 自定义日期格式

/var/log/application.log {
    daily
    rotate 30
    compress
    dateext
    dateformat -%Y%m%d-%s
    missingok
    notifempty
    create 644 appuser appgroup
}

6.2 条件轮转和邮件通知

/var/log/secure.log {
    weekly
    rotate 8
    compress
    missingok

    # 只在日志大于10M时才轮转
    minsize 10M

    # 发送旧日志到管理员邮箱
    mail admin@example.com
    mailfirst     # 发送第一个删除的日志
    maillast      # 发送最后一个删除的日志

    postrotate
        /usr/bin/killall -HUP syslogd
    endscript
}

6.3 复杂的脚本执行

/var/log/mysql/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    create 640 mysql adm

    prerotate
        # 轮转前执行的脚本
        if [ -d /etc/logrotate.d/httpd-prerotate ]; then
            run-parts /etc/logrotate.d/httpd-prerotate
        fi
    endscript

    postrotate
        # 轮转后执行的脚本
        if [ -e /var/run/mysqld/mysqld.pid ]; then
            mysqladmin flush-logs
        fi
    endscript
}

7. 实际应用场景

场景1:Web服务器日志轮转

# /etc/logrotate.d/nginx-complete
/var/log/nginx/access.log
/var/log/nginx/error.log {
    daily
    rotate 30
    compress
    delaycompress
    dateext
    missingok
    notifempty
    create 640 www-data adm
    sharedscripts

    prerotate
        if [ -d /etc/logrotate.d/nginx-prerotate ]; then
            run-parts /etc/logrotate.d/nginx-prerotate
        fi
    endscript

    postrotate
        # 重新打开日志文件
        [ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid`

        # 发送通知
        echo "Nginx日志已轮转 $(date)" | mail -s "Nginx日志轮转通知" admin@example.com
    endscript
}

场景2:数据库日志轮转

# /etc/logrotate.d/mysql-server
/var/log/mysql/mysql.log
/var/log/mysql/mysql-slow.log
/var/log/mysql/error.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 640 mysql adm

    postrotate
        # 如果MySQL正在运行,刷新日志
        if test -x /usr/bin/mysqladmin && \
           /usr/bin/mysqladmin ping &>/dev/null
        then
            /usr/bin/mysqladmin flush-logs
        fi
    endscript
}

场景3:自定义应用日志轮转

# /etc/logrotate.d/myapplication
/opt/myapp/logs/*.log {
    size 50M
    rotate 10
    compress
    delaycompress
    missingok
    notifempty
    create 644 appuser appuser

    # 最大保留90天
    maxage 90

    # 如果日志超过100M,立即轮转
    maxsize 100M

    postrotate
        # 重启应用服务
        systemctl restart myapp.service

        # 记录轮转日志
        echo "$(date): 应用日志已轮转" >> /var/log/logrotate.log
    endscript
}

8. 手动执行和测试

8.1 手动执行logrotate

# 手动执行所有配置
sudo logrotate /etc/logrotate.conf

# 强制执行,即使未到轮转时间
sudo logrotate -f /etc/logrotate.conf

# 测试特定配置文件
sudo logrotate -d /etc/logrotate.d/nginx

# 强制执行并显示详细信息
sudo logrotate -vf /etc/logrotate.conf

8.2 调试和测试配置

# 调试模式(不实际执行)
sudo logrotate -d /etc/logrotate.conf

# 测试特定日志文件的配置
sudo logrotate -d /etc/logrotate.conf --debug | grep "myapp.log"

# 查看状态文件
sudo cat /var/lib/logrotate/status

# 重置状态文件(强制所有日志重新轮转)
sudo rm /var/lib/logrotate/status
sudo logrotate /etc/logrotate.conf

9. 定时任务配置

9.1 配置cron定时任务

# 查看logrotate的cron配置
sudo cat /etc/cron.daily/logrotate

# 文件内容通常如下:
#!/bin/sh

/usr/sbin/logrotate /etc/logrotate.conf
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
    /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit 0

9.2 自定义执行时间

# 创建自定义cron任务
sudo nano /etc/cron.d/logrotate-custom

# 内容:每天凌晨2点执行logrotate
0 2 * * * root /usr/sbin/logrotate /etc/logrotate.conf > /var/log/logrotate_cron.log 2>&1

# 或者每小时执行一次(用于测试)
0 * * * * root /usr/sbin/logrotate /etc/logrotate.conf

10. 故障排除

问题1:日志轮转后服务无法写入新日志

# 检查文件权限和所有权
ls -la /var/log/nginx/

# 确保使用了正确的create选项
create 644 www-data www-data

# 检查postrotate脚本是否执行成功
sudo logrotate -vf /etc/logrotate.d/nginx 2>&1 | grep -A5 -B5 "postrotate"

# 手动重新加载服务
sudo systemctl reload nginx

问题2:日志未按预期轮转

# 检查状态文件
sudo cat /var/lib/logrotate/status | grep nginx

# 强制轮转并查看详细输出
sudo logrotate -vf /etc/logrotate.d/nginx

# 检查cron是否正常执行
sudo grep logrotate /var/log/syslog

# 检查日志文件大小
ls -lh /var/log/nginx/access.log

问题3:磁盘空间未释放

# 检查是否有进程仍持有旧日志文件的句柄
sudo lsof | grep deleted | grep log

# 如果有进程持有已删除文件的句柄,需要重启该进程
sudo systemctl restart nginx

# 检查压缩文件是否生成
ls -lh /var/log/nginx/*.gz

# 使用du命令查看实际磁盘使用
sudo du -sh /var/log/nginx/

11. 最佳实践

配置建议

  1. 合理设置保留周期:根据磁盘空间和合规要求设置rotate值
  2. 启用压缩:使用compress节省磁盘空间
  3. 使用delaycompress:避免压缩最近的日志,便于查看
  4. 配置postrotate脚本:确保服务能正确重新打开日志文件
  5. 使用sharedscripts:多个日志文件共享脚本,避免重复执行
  6. 监控logrotate执行:记录logrotate的执行日志
  7. 定期清理旧日志:使用maxage选项自动删除过旧日志

11.1 安全注意事项

# 1. 配置文件权限
sudo chmod 644 /etc/logrotate.d/your-config
sudo chown root:root /etc/logrotate.d/your-config

# 2. 避免在脚本中硬编码密码
# 3. 限制日志文件访问权限
create 640 username groupname

# 4. 定期审计logrotate配置
# 5. 监控异常轮转行为

12. 监控和调试脚本

监控脚本示例
1. logrotate执行监控脚本
#!/bin/bash
# /usr/local/bin/monitor-logrotate.sh
LOG_FILE="/var/log/logrotate_monitor.log"
CONFIG_FILE="/etc/logrotate.conf"

echo "=== Logrotate监控报告 $(date) ===" | tee -a $LOG_FILE

# 检查logrotate是否安装
if ! command -v logrotate &> /dev/null; then
    echo "错误: logrotate未安装" | tee -a $LOG_FILE
    exit 1
fi

# 测试配置文件语法
echo "测试配置文件语法..." | tee -a $LOG_FILE
if sudo logrotate -d $CONFIG_FILE 2>&1 | grep -q "error"; then
    echo "发现配置错误:" | tee -a $LOG_FILE
    sudo logrotate -d $CONFIG_FILE 2>&1 | grep "error" | tee -a $LOG_FILE
else
    echo "配置文件语法检查通过" | tee -a $LOG_FILE
fi

# 检查最近轮转的日志
echo -e "\n最近轮转的日志:" | tee -a $LOG_FILE
sudo grep "rotating" /var/lib/logrotate/status | tail -10 | tee -a $LOG_FILE

# 检查日志文件大小
echo -e "\n大型日志文件 (>100M):" | tee -a $LOG_FILE
find /var/log -name "*.log" -size +100M -exec ls -lh {} \; 2>/dev/null | tee -a $LOG_FILE

echo -e "\n监控完成" | tee -a $LOG_FILE
2. 日志文件分析脚本
#!/bin/bash
# /usr/local/bin/analyze-logfiles.sh
LOG_DIR="/var/log"
REPORT_FILE="/tmp/log-analysis-$(date +%Y%m%d).txt"

echo "日志文件分析报告 - $(date)" > $REPORT_FILE
echo "=================================" >> $REPORT_FILE

# 分析日志文件数量和大小
echo -e "\n1. 日志文件统计:" >> $REPORT_FILE
find $LOG_DIR -name "*.log" -type f | wc -l | xargs echo "日志文件总数: " >> $REPORT_FILE
find $LOG_DIR -name "*.log" -type f -exec du -ch {} + | tail -1 | xargs echo "日志文件总大小: " >> $REPORT_FILE

# 列出最大的10个日志文件
echo -e "\n2. 最大的10个日志文件:" >> $REPORT_FILE
find $LOG_DIR -name "*.log" -type f -exec du -h {} + | sort -rh | head -10 >> $REPORT_FILE

# 检查轮转文件
echo -e "\n3. 轮转日志文件统计:" >> $REPORT_FILE
find $LOG_DIR -name "*.gz" -type f | wc -l | xargs echo "压缩的轮转日志数量: " >> $REPORT_FILE

echo -e "\n报告已保存到: $REPORT_FILE"

实用技巧

  • 使用 logrotate -d 测试配置而不实际执行
  • 结合 cronanacron 确保日志轮转可靠执行
  • 使用 dateextdateformat 方便日志文件管理
  • 为重要服务配置 prerotatepostrotate 脚本
  • 定期检查 /var/lib/logrotate/status 文件了解轮转状态