如何将 logrotate 与 Log4j “滚动”文件附加器结合起来?

如何将 logrotate 与 Log4j “滚动”文件附加器结合起来?

我们有一个 Java 应用程序,它使用 log4j 并每天轮换自己的日志:

  • 当前使用的日志文件是/var/log/foo/foo.log
  • /var/log/foo/foo.log.YYYY-MM-dd当日子改变时它就被移入

我们不想改变它的配置...

然而,我们确实希望:

  1. 重命名文件后对其进行压缩
  2. 只保留一定数量

虽然编写一个 cron-job 来同时完成这两项任务并不困难,但我们宁愿留在框架中logrotate...

我创建了以下内容/etc/logrotate.d/foo

/var/log/foo/foo.log.* {
        daily
        rotate 2
        compress
        delaycompress
        missingok
        notifempty
}

但它什么也没做:

reading config file /etc/logrotate.d/foo

Handling 1 logs

rotating pattern: /var/log/foo/foo.log.*  after 1 days (2 rotations)
empty log files are not rotated, old logs are removed
considering log /var/log/foo/foo.log.2017-06-28
  log does not need rotating
considering log /var/log/foo/foo.log.2017-06-29
  log does not need rotating
considering log /var/log/foo/foo.log.2017-06-30
  log does not need rotating
considering log /var/log/foo/foo.log.2017-07-01
  log does not need rotating
considering log /var/log/foo/foo.log.2017-07-02
  log does not need rotating
considering log /var/log/foo/foo.log.2017-07-03
  log does not need rotating
considering log /var/log/foo/foo.log.2017-07-04
  log does not need rotating

当文件总数超过 2 时,如何让它压缩文件并删除最旧的文件?

答案1

我真的不认为你能在logrotate没有外部命令的情况下做你想做的事情。此外,该模式/var/log/foo/foo.log.*会将每个单独的文件视为要轮换的单独日志,而不是一组轮换文件。

man logrotate

请谨慎使用通配符。如果指定 *,logrotate 将轮转所有文件,包括之前轮转过的文件。

无论如何,也许是这样的?只需设置永远不会达到的旋转条件,因为 log4j 已经部分处理了旋转。然后将其余部分放入脚本中prerotate

/var/log/foo/foo.log {
    size 100G # something big that will never be reached/rotated since log4j does this.
    missingok
    notifempty
    # delete the other logs over 7 days old
    prerotate
        find /var/log/foo/ -name 'foo.log.*' -mtime +7 -delete
        nice gzip /var/log/foo/foo.log.*
    endscript
}

答案2

我需要实现此行为,因为应用程序团队希望使用 log4j 保持对日志和文件名格式以及轮换计划的控制。如果您阅读,man logrotate您会注意到所有 pre/post/lastaction 脚本仅在至少轮换一个日志时执行。因此,设置一些无法访问的内容size 999G不起作用。

相反,我所做的是设置copyextension选项以便:

  1. 原始日志文件从未被触及(它由 log4j 管理)
  2. logrotate 轮换的日志具有不同的扩展名,我可以对其进行过滤
/var/log/<service>/<service>.log {
    copy  # don't touch the orig. log file, it's managed by log4j
    extension .log  # End rotated files in ".log" so we can find and delete them
    rotate 1
    hourly
    missingok

    prerotate
        find /var/log/<service>/ -iname "*service.log.*" ! -iname "*.gz" -exec gzip {} \; && \
        aws s3 sync /var/log/<service>/ s3://<bucket>/<environment>/<ec2_id>/<service>/ --exclude "*" --include "*<service>*.gz" && \
        find /var/log/<service>/ -iname "*<service>.log.*" -mtime +7 -delete
    endscript

    lastaction
        find /var/log/<service>/ -iname "*<service>.*.log" -delete
    endscript
}

是的,我可以创建一个 cron 作业。我使用的理由logrotate是,我将所有的日志轮换配置管理都放在一个 Ansible 角色中,将来,我将禁用log4j轮换并改用,logrotate这将是一个简单的更改。

答案3

Log4j Rolling File Appenders 与 logrotate 不兼容。log4j 轮转会干扰 logrotate。

首先,您需要找到应用程序的 log4j 配置文件,并将滚动文件附加器替换为简单文件附加器。这将阻止 log4j 轮换文件。然后,您可以使用 logrotate 根据需要轮换日志文件。

如果您无法修改应用程序的 log4j 配置,您可以创建自己的配置,并在启动应用程序时在类路径中指定它。

-Dlog4j.configurationFile=path/to/log4j2.xml

参考:https://logging.apache.org/log4j/2.0/faq.html#config_location

相关内容