前提

昨天学习「鸟哥的 Linux 私房菜」时遇到了这个问题。详情请看 18.3.3 自定义日志文件的循环功能

正文

事情是这样的:现在我有一个自定义的日志文件,要通过设置 logrotate 来自动轮循备份日志。为了安全我们将这个日志文件加上隐藏属性 +a ,这样日志文件只能增加而不能删除或修改。
首先我们来看一下轮询该日志的要求:

  • 日志文件轮循一关于进行一次
  • 该日志文件若大于 10MB 时,则主动进行轮循,不需要考虑一个月的期限
  • 保存5个备份文件
  • 备份文件需要压缩

    开始操作

  1. 先增加 +a 这个属性
  1. $ chattr +a /var/log/admin.log #设置该文件隐藏属性为 +a
  2. $ sattr /var/log/admin.log # 查看是否设置成功
  3. -----a---------- /var/log/admin.log
  4. $ mv /var/log/admin.log /var/log/admin.log.1 #测试 +a 属性是否有用
  5. mv: cannot move `/var/log/admin.log' to `/var/log/admin.log.1': Operation not permitted
  1. 增加完隐藏属性,就可以开始建立 logrotate 的配置文件,该配置文件要添加到 /etc/logrotate.d/ 目录中。
  1. $ vim /etc/logrotate.d/admin # 使用 vim 建立文件,下面是该文件的内容
  2. # This configuration is from VBird 2015/08/19
  3. /var/log/admin.log {
  4. monthly <==每个月进行一次
  5. size=10M <==日志文件容量大于 10M 则开始轮播
  6. rotate 5 <==保留五个!
  7. compress <==进行压缩工作!
  8. sharedscripts
  9. prerotate <==在启动 logrotate 之前进行的命令
  10. /usr/bin/chattr -a /var/log/admin.log
  11. endscript
  12. sharedscripts
  13. postrotate <==在启动 logrotate 之后进行的命令
  14. /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
  15. /usr/bin/chattr +a /var/log/admin.log
  16. endscript
  17. }

可以看到该文件中重要的就是设置 chattr 的关闭与开启了。这也是下面报错的地方

  1. 先测试一下 logrotate 相关功能的信息展示
  1. $ logrotate -v /etc/logrotate.d/admin # 该命令会展示该配置文件的相关信息展示,下面是显示信息
  2. reading config file /etc/logrotate.d/admin
  3. Allocating hash table for state file, size 15360 B
  4. Handling 1 logs
  5. rotating pattern: /var/log/admin.log 10485760 bytes (5 rotations)
  6. empty log files are rotated, old logs are removed
  7. considering log /var/log/admin.log
  8. log does not need rotating (log size is below the 'size' threshold)
  9. not running prerotate script, since no logs will be rotated
  10. not running postrotate script, since no logs were rotated
  11. set default create context

上面的展示信息的意思是,目前时间没有到一个月,容量也小于 10M ,所以不进行轮循。

  1. 测试一下强制执行该 logrotate 文件,与相关功能的展示
  1. $ logrotate -vf /etc/logrotate.d/admin # 这里加上了 -f 代表强制执行之意。
  2. reading config file /etc/logrotate.d/admin
  3. Allocating hash table for state file, size 15360 B
  4. Handling 1 logs
  5. rotating pattern: /var/log/admin.log forced from command line (5 rotations)
  6. empty log files are rotated, old logs are removed
  7. considering log /var/log/admin.log
  8. log needs rotating
  9. rotating log /var/log/admin.log, log->rotateCount is 5
  10. dateext suffix '-20200227'
  11. glob pattern '-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
  12. renaming /var/log/admin.log.5.gz to /var/log/admin.log.6.gz (rotatecount 5, logstart 1, i 5),
  13. old log /var/log/admin.log.5.gz does not exist
  14. renaming /var/log/admin.log.4.gz to /var/log/admin.log.5.gz (rotatecount 5, logstart 1, i 4),
  15. old log /var/log/admin.log.4.gz does not exist
  16. renaming /var/log/admin.log.3.gz to /var/log/admin.log.4.gz (rotatecount 5, logstart 1, i 3),
  17. old log /var/log/admin.log.3.gz does not exist
  18. renaming /var/log/admin.log.2.gz to /var/log/admin.log.3.gz (rotatecount 5, logstart 1, i 2),
  19. old log /var/log/admin.log.2.gz does not exist
  20. renaming /var/log/admin.log.1.gz to /var/log/admin.log.2.gz (rotatecount 5, logstart 1, i 1),
  21. old log /var/log/admin.log.1.gz does not exist
  22. renaming /var/log/admin.log.0.gz to /var/log/admin.log.1.gz (rotatecount 5, logstart 1, i 0),
  23. old log /var/log/admin.log.0.gz does not exist
  24. log /var/log/admin.log.6.gz doesn't exist -- won't try to dispose of it
  25. running prerotate script
  26. fscreate context set to system_u:object_r:var_log_t:s0
  27. renaming /var/log/admin.log to /var/log/admin.log.1
  28. running postrotate script
  29. /usr/bin/chattr: No such file or directory while trying to stat /var/log/admin.log
  30. error: error running shared postrotate script for '/var/log/admin.log '
  31. set default create context

可以看到这里已经报错了,我们来看到倒数这四行。

  1. running postrotate script
  2. /usr/bin/chattr: No such file or directory while trying to stat /var/log/admin.log
  3. error: error running shared postrotate script for '/var/log/admin.log '
  4. set default create context

这里提示的是运行 postrotate script 的时候,/usr/bin/chattr 找不到文件或目录导致的错误。很纳闷的是,不是 prerotate script 报的错,而是后面运行的 postrotate script 报的错,这说明这个文件被修改(日志的轮循主要是将目前的文件修文件名)之前 /usr/bin/chattr 是可以运行的。
在来看一下日志文件的隐藏属性

  1. $ lsattr /var/log/admin.log*
  2. ---------------- /var/log/admin.log
  3. ---------------- /var/log/admin.log.1

看来是正常的执行了 prerotate script ,但是由于 postrotate script 报错导致将隐藏属性复原,而且也没有将日志文件压缩。

发现问题

带着这个问题去 google 了一下,很遗憾并没有找到正确的解答方法。这难道说明目前并没有人这么用吗?
中间我也是试了各种方法:关闭 SELinux ,给配置文件权限,关机重启,在另一台虚拟机上面设置同样的方法。很不幸,都没有一点改变。
最后,我发现我执行 /etc/logrotate.conf 的时候,是可以正常运行的,也没有报错,但是轮循出来的文件和我们想要的结果不同。

/etc/logrotate.conf 是所有轮循文件的中总配置文件,通常系统进行轮循的时候只运行这一个文件,由该文件来完成对其他轮循文件的应用。

  1. $ logrotate -vf /etc/logrotate.conf
  2. reading config file /etc/logrotate.conf
  3. including /etc/logrotate.d
  4. reading config file admin
  5. ...
  6. rotating pattern: /var/log/admin.log forced from command line (5 rotations)
  7. empty log files are rotated, old logs are removed
  8. considering log /var/log/admin.log
  9. log needs rotating
  10. rotating log /var/log/admin.log, log->rotateCount is 5
  11. dateext suffix '-20200227'
  12. glob pattern '-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'
  13. glob finding old rotated logs failed
  14. running prerotate script
  15. fscreate context set to system_u:object_r:var_log_t:s0
  16. renaming /var/log/admin.log to /var/log/admin.log-20200227
  17. creating new /var/log/admin.log mode = 0600 uid = 0 gid = 0
  18. running postrotate script
  19. compressing log with: /bin/gzip
  20. set default create context to system_u:object_r:var_log_t:s0
  21. ...

由于这里输出很多,我将很多不必要的输出省略了。
可以看到这里 postrotate script 是正常运行的,也没有报错。紧接着我检查了一下轮循出来的文件

  1. $ lsattr /var/log/admin.log*
  2. -----a---------- /var/log/admin.log
  3. ---------------- /var/log/admin.log.1
  4. ---------------- /var/log/admin.log-20200227.gz

惊喜的发现,隐藏属性设置成功,说明 /etc/logrotate.d/admin 里面的设置成功,也成功压缩了对应的轮循文件,但是该压缩文件的命名并不是我们想要的。带着疑问,我查看了 /etc/logrotate.conf 配置文件

  1. $ vim /etc/logrotate.conf
  2. weekly <==默认每个礼拜对登录档进行一次 rotate 的工作
  3. rotate 4 <==保留几个日志文件呢?预设是保留四个!
  4. create <==由于日志文件被更名,因此建立一个新的来继续储存之意!
  5. dateext <==就是这个设定值!可以让被轮替的文件名加上日期!
  6. #compress <==被更动的日志文件是否需要压缩?如果日志文件太大则可考虑此参数启动
  7. include /etc/logrotate.d
  8. # 将 /etc/logrotate.d/ 这个目录中的所有文件都读进来执行轮循的工作!
  9. ...

可以看到该文件会把 /etc/logrotate.d/ 该目录下的所有文件都引入进来,admin 文件也是这样被引进来的。观察文件的设置,dateext是将文件更名为日期来存储,我们就可以解释为什么会以日期来命名了。我们还发现 create 是日志文件被更名后,重新建立一个新的文件来继续存储我们的日志。这一下我们就可以解释为什么 chattr 会报错了,因为根本就没有这个文件,而且报错也非常准确:No such file or directory。没有这个文件或目录。
哈哈,这下真相大白:是因为我没有重新建立日志文件而导致 chattr 命令出错。

解决问题

更正也非常简单,在 /etc/logrotate.d/admin 文件里加上 create 属性即可。
先将上面轮循的日志文件删除,再来测试 /etc/logrotate/admin 是否有用。

  1. $ rm /var/log/admin.log.1
  2. $ rm /var/log/admin.log-20200227.gz

测试 /etc/logrotate.d/admin ,并查看是否成功轮循

  1. $ logrotate -vf /etc/logrotate.d/admin
  2. reading config file /etc/logrotate.d/admin
  3. Allocating hash table for state file, size 15360 B
  4. Handling 1 logs
  5. ...
  6. renaming /var/log/admin.log to /var/log/admin.log.1
  7. creating new /var/log/admin.log mode = 0600 uid = 0 gid = 0
  8. running postrotate script
  9. compressing log with: /bin/gzip
  10. set default create context to system_u:object_r:var_log_t:s0
  11. set default create context

可以看到正常运行,在使用 lsattr 检查一下 logrotate 文件

  1. $ lsattr /var/log/admin.log*
  2. -----a---------- /var/log/admin.log
  3. ---------------- /var/log/admin.log.1.gz

成功达到我们要的效果。