项目部署上K8S Log4j多副本滚动备份日志丢失问题记录

目录(可以直接看原因和解决方案)

  • 问题场景
  • 问题描述
  • 原因分析
  • 解决方案
  • 参考链接

问题场景

公司的IT运维最近将我们运行了两年的SSH项目上K8S,好处是多副本运行统一日志管理无感发布高可用,在稳定运行了一段时间后,我们某一天发现一个问题需要根据后台输出的日志进行分析时,发现当前正在记录的日志没有问题,但是翻昨天甚至前几天的日志都发现日志的体积很小,与当前的业务量相比特别不合理。


问题描述

翻看日志发现日志只有小小的几M,而目前正在记录的日志仅半天就已经有十几M了,而且翻看里面的内容也只有凌晨3点到4点一个小时的日志量(输出的日志有带时间)。
之后我找帮我们上了K8S的运维,询问他是否对我们的日志进行了清理,或者是帮我们切割日志时出现了问题。
得到的答复是:没有删除我们的日志,也没有帮我们写脚本进行分割

为什么第一时间找的是运维呢,因为当时另一个项目是使用Linux的分割日志脚本,所以我想当然地认为这个也是,然而实际上是使用了Log4j的DailyRollingFileAppender进行每日分割

于是我就回去自己的程序里找是哪里进行的日志分割,后来找到了我们的log4j.properties文件,里面的配置是这么写的

log4j.rootLogger=INFO, dailyRollingFile

#dailyRollingFile 
log4j.appender.dailyRollingFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.dailyRollingFile.Encoding=UTF-8
# 备份的日志用.yyyy-MM-dd来重命名
log4j.appender.dailyRollingFile.DatePattern='.'yyyy-MM-dd
log4j.appender.dailyRollingFile.File=${catalina.home}/logs/web.log
log4j.appender.dailyRollingFile.layout=org.apache.log4j.PatternLayout
log4j.appender.dailyRollingFile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%t] (%c{1}:%L) - %m%n

log4j.logger.noModule=FATAL

原因分析

配置看起来没有问题,而且也是每天定时按规则分割了日志,那么问题出在了哪里,为什么分割之后前一天的日志就不完整了,然后我去搜索了一下关于Log4j日志分割的原理:

/**
     将当前的文件滚动到新文件
  */
void rollOver() throws IOException {
    // ...省略前面
    // fileName是当前日志名称, 拼接指定格式的当前时间
    String datedFilename = fileName+sdf.format(now);
    // 如果准备生成滚动日志的时间跟当前时间相等, 则等待下一周期再进行滚动生成, 这个地方有点不太理解是否有必要
    if (scheduledFilename.equals(datedFilename)) {
      return;
    }
    this.closeFile();
    // 获取一个叫scheduledFilename的文件, 如果该文件已存在则将它删除
    File target  = new File(scheduledFilename);
    if (target.exists()) {
      target.delete();
    }

    File file = new File(fileName);
    // 重命名当前的日志文件
    boolean result = file.renameTo(target);
    if(result) {
      LogLog.debug(fileName +" -> "+ scheduledFilename);
    } else {
      LogLog.error("Failed to rename ["+fileName+"] to ["+scheduledFilename+"].");
    }
}

即在生成新文件时,如果文件已存在会删除。那问题就是出现在这里,由于我们的应用存在2个副本,多个副本记录在同一个日志目录下,当应用A到时间滚动日志时,会生成一个当前日期的文件,应用B到时间滚动日志,假如比A慢了一两秒,判断到已经存在这个文件了,就将该文件删除,而被删除的这个文件实际上就是今天的日志。因此导致在第二天我们回看之前的日志时,里面已经没有前一天的内容了


解决方案

修改日志配置,不通过Log4j中的org.apache.log4j.DailyRollingFileAppender进行日志滚动备份,而是使用普通的org.apache.log4j.FileAppender进行日志记录,然后写文件执行脚本(如果是自己的Linux服务器的话就写Linux的脚本),通过在K8S的cron job进行日志的切割备份。
附上使用FileAppender的配置

log4j.rootLogger=INFO, file

log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.Encoding=UTF-8
log4j.appender.file.File=${catalina.home}/logs/web.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%t] (%c{1}:%L) - %m%n

参考链接

简书:log4j的实现原理与思考

你可能感兴趣的:(踩坑,java,java)