4、logrotate日志轮转:日志轮转原理、logrotate配置语法、车载存储空间管理策略

4.1 为什么车载系统离不开日志轮转?

说实话,我刚入行做车载Linux那会儿,踩过一个很蠢的坑。当时一个IVI(车载信息娱乐系统)项目,跑了大概两周,突然系统响应变得特别慢。我一查,好家伙,/var/log目录下有个日志文件撑到了2.3GB。你想想看,车载嵌入式设备的存储空间本来就金贵,一个日志文件就把emmc吃掉一大块,这谁受得了?

从那以后,我养成了一个习惯——任何上车的系统,第一件事就是配好logrotate。说白了,日志轮转就是让日志文件“自动瘦身”的机制。它不会让你的日志无限增长,而是按照你设定的规则,定期把旧日志压缩、归档、甚至删除。

车载环境尤其特殊。存储空间有限,而且往往是emmc或者NAND Flash,写入寿命有限。如果日志一直疯狂写,不仅空间会爆,Flash的寿命也会被快速消耗。嗯,这里要注意,logrotate不是万能的,但它绝对是第一道防线。

4.2 logrotate轮转原理:其实没那么玄乎

logrotate的工作原理,我用一句话就能说清楚:它是个定时任务,到了时间就把当前日志文件“挪走”,然后让应用程序重新生成一个新的空日志文件

具体流程是这样的:

  1. 系统定时器(通常是cron或者systemd timer)触发logrotate
  2. logrotate读取配置文件,检查哪些日志文件需要轮转
  3. 如果满足条件(比如文件大小超了,或者时间到了),就把当前日志重命名
  4. 通知应用程序关闭旧文件句柄,打开新文件
  5. 对旧日志进行压缩、删除等后续处理

这里有个关键点——通知机制。我记得有个项目,logrotate配置好了,但日志就是不轮转。查了半天,发现是应用程序没有正确处理SIGHUP信号。logrotate轮转完文件后,会发一个SIGHUP给应用程序,应用程序收到信号后应该重新打开日志文件。如果应用程序不处理这个信号,那日志就会继续往旧文件里写,轮转就白做了。

核心要点:logrotate本身不写日志,它只是管理日志文件。真正的日志写入者是应用程序。所以轮转后,必须确保应用程序能重新打开日志文件。

4.3 logrotate配置语法:我常用的几个模板

logrotate的配置文件通常放在/etc/logrotate.conf/etc/logrotate.d/目录下。我个人习惯把每个应用的配置单独放在/etc/logrotate.d/里,这样管理起来清晰。

先看一个最基础的配置:

/var/log/syslog {
    weekly
    rotate 4
    compress
    delaycompress
    missingok
    notifempty
    postrotate
        /usr/bin/killall -HUP syslogd
    endscript
}

这个配置什么意思?我拆开讲:

  • weekly:每周轮转一次。你也可以用dailymonthly,甚至size 100M按大小轮转
  • rotate 4:保留4个旧日志文件。超过4个,最老的那个会被删除
  • compress:旧日志用gzip压缩。车载空间紧张,我建议一定要开
  • delaycompress:延迟压缩。意思是这次轮转出来的旧日志先不压缩,等下次轮转再压缩。为什么?因为有些应用还在写旧日志,延迟压缩可以避免数据丢失
  • missingok:日志文件不存在也没关系,不报错
  • notifempty:日志文件为空就不轮转
  • postrotate/endscript:轮转完成后执行的脚本,这里就是通知syslogd重新打开日志

车载场景下,我推荐一个更实用的配置:

/var/log/ivi_app.log {
    size 50M
    rotate 3
    compress
    delaycompress
    missingok
    notifempty
    dateext
    dateformat -%Y%m%d-%s
    sharedscripts
    postrotate
        /usr/bin/killall -USR1 ivi_app
    endscript
}

这里有几个车载专用的技巧:

  • size 50M:按大小轮转,而不是按时间。车载日志量波动大,按大小更靠谱
  • rotate 3:只保留3个旧文件。车载存储有限,别贪多
  • dateext:用日期命名旧文件,方便排查问题
  • sharedscripts:如果匹配多个日志文件,脚本只执行一次

我的经验:车载系统里,我一般把日志总大小控制在200MB以内。比如每个日志文件50MB,保留3个旧文件,再加上当前文件,总共也就200MB。这个量级对于大多数车载设备来说是可以接受的。

4.4 车载存储空间管理策略:实战中的取舍

车载存储管理,说白了就是一场“空间与信息”的博弈。你想保留更多日志方便排查问题,但存储空间就那么点。我经历过一个项目,客户要求保留30天的日志,但emmc只有4GB。你算算,系统本身占掉2GB,应用数据占1GB,留给日志的只有1GB。30天,每天33MB,这怎么可能?

所以,我总结了一套车载存储管理的策略:

策略 说明 适用场景
按大小轮转 设置单个日志文件上限,比如50MB 日志量波动大的场景
限制总大小 通过rotate数量控制总日志量 存储空间固定的嵌入式设备
分级存储 关键日志保留更久,普通日志快速清理 需要区分日志重要性的场景
压缩归档 旧日志用gzip压缩,压缩比通常5:1 所有车载设备都建议开启
远程上传 重要日志上传到云端,本地只保留最近几份 有网络连接的车载系统

我曾经在一个T-Box项目里用过“分级存储”策略。系统日志只保留3天,但CAN总线日志保留7天,故障快照保留30天。怎么实现的?很简单,不同的日志写到不同的目录,分别配置logrotate规则:

/var/log/system/*.log {
    size 10M
    rotate 2
    compress
}

/var/log/canbus/*.log {
    size 20M
    rotate 5
    compress
}

/var/log/crash/*.log {
    size 5M
    rotate 10
    compress
    # 故障快照不自动删除,由专门脚本管理
}

警告:千万不要把所有日志都塞到同一个目录下用同一个规则。车载系统里,不同模块的日志重要性和量级完全不同。混在一起管理,要么重要日志被过早清理,要么空间被不重要日志占满。

4.5 避坑指南:我踩过的那些坑

做车载logrotate配置这么多年,我踩过的坑真不少。挑几个典型的说说:

坑一:轮转后应用不写日志了
我曾经遇到一个情况,logrotate配置好了,轮转也正常执行,但应用就是不写新日志。查了半天,发现是copytruncate参数的问题。这个参数的意思是“先复制再截断”,不通知应用。但有些应用对文件截断处理不好,会导致日志丢失。我的建议是:能用create方案就别用copytruncate

坑二:轮转频率太高把Flash写坏了
emmc和NAND Flash都有写入寿命。如果设置daily轮转,每次轮转都要压缩、写入新文件,对Flash的磨损不小。我建议车载系统里,非关键日志用weekly或者size触发,别让日志轮转变成Flash杀手。

坑三:忘记测试轮转后的恢复场景
我记得有一次,客户反馈说车机死机重启后,日志文件全丢了。我一查,原来是logrotate配置了create,但重启后日志目录权限变了,应用没有权限创建新日志文件。从那以后,我每次配置完logrotate,都会做一次“断电重启测试”,确保日志系统在异常场景下也能正常工作。

4.6 总结一下

logrotate这东西,配置起来不难,但要想在车载环境里用好,还是得花点心思。核心就三点:

  1. 按需配置:不同模块不同策略,别一刀切
  2. 控制总量:车载存储有限,总日志量必须设上限
  3. 测试验证:配置完一定要做压力测试和异常场景测试

嗯,如果你现在去配logrotate,我建议先从size 50Mrotate 3开始,配合compressdateext。这个组合在大多数车载场景下都不会出大问题。等跑一段时间,再根据实际日志量调整参数。

下一章,我们会聊聊日志分析工具和故障诊断方法。到时候我会分享一些我实际用过的调试技巧,保证比你看文档来得实在。