问题描述
今天在排查一个bug的时候发现日志被覆盖了,我们应用以jar包的方式集成了一个运维工具到项目中,应用需要启动两次,每次启动的时候根据参数来区分启动哪一个主程序。
类似如下:
public class App {
public static void main(String[] args){
if(args!=null && Objects.equals(args[0],"devOps")){
// 启动运维模式
startDevOps(args)
return ;
}
// 启动主应用
SpringApplication.run(App .class, args);
}
}
在使用这个应用的时候,会在启动脚本中,执行两次,分别是启动主应用和运维应用,运维是主应用的代理,可以操作主应用
如:
nohup java -jar xxxApp.jar # 启动主应用
nohup java -jar xxxApp.jar devOps # 启动运维模式
应用从设计和运行了一段时间都没啥问题,但是今天在查日志的时候,发现主日志文件只有运维工具的日志信息,而没有主应用的日志信息。而且查看其它节点,有的节点日志文件中是主应用的日志,有的是运维日志。让我很纳闷,
最后排查出来,在主应用和运维应用(jar)都用了log4j2打印日志,并且因为运维应用是通过jar继承的,启动入口又是从打包好的主应用jar启动,因此使用的是主应用的log4j2.xml。而在log4j2.xml中配置文件名称一致,它们是不同进程,在日志文件滚动(我们设置的一天一个日志文件),谁先满足新生成文件规则就先占用了这个文件,另一个进程就写不进去了。
问题的根源就是两个进程使用了同一个日志配置,导致两个进程操作同一个日志文件,从而造成被覆盖的问题。
问题解决
知道了问题原因要解决就不难了,毕竟办法总比困难多。
第一种,将其中一个应用的在启动的时候使用命令 nohup xxx.jar > xxx.log &指定输出,但是这种指标不治本,当日志发生文件归档的时候,还是会以输出到日志文件中,并且这种无法归档日志文件,导致一个日志文件变得很大。(PASS)
第二种,使用两个日志文件来记录,dev的使用dev日志文件,main的使用main的日志文件。
现在又提出了一个问题,日志文件在打包的时候就已经打包到了jar包中,它们都在同一个jar包中,那怎么来区分呢?
又有两种思路:
1、在启动的时候指定日志文件,在启动的时候加载JAVA_OPT参数:-Dlog4j.configuration="file:/opt/config/log4j2.xml"。如:
java -Dlog4j.configuration="file:/opt/config/log4j2.xml" -jar xxxApp.jar我没有使用这种方式,因为我们不想在启动的时候还要带个日志文件,有点繁琐了,而且也不好统一管理,改一个另一个也得改。
2、根据参数输出到不同日志中去,我们使用的是这种
先来看下我们原来的有关日志文件的配置
<RollingFile name="RollingFile" fileName="logs/xxxApp.log" filePattern="logs/xxxApp-%d{MM-dd-yyyy}-%i.log" append="false">
<PatternLayout>
<Pattern>%d{yyyy-MM-dd HH:mm:ss} %p [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="1" />
<SizeBasedTriggeringPolicy size="10 MB"/>
</Policies>
<DefaultRolloverStrategy max="5"/>
</RollingFile>
以前运行都会将日志输出当logs目录中,并且名称都是xxxApp.log,会导致两个进程使用一个日志文件。
修改后
<RollingFile name="RollingFile" fileName="logs/xxxApp${env:log4j.logSuffix:-}.log" filePattern="logs/xxxApp${env:log4j.logSuffix:-}-%d{MM-dd-yyyy}-%i.log" append="false">
<PatternLayout>
<Pattern>%d{yyyy-MM-dd HH:mm:ss} %p [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="10 MB"/>
</Policies>
<DefaultRolloverStrategy max="5"/>
</RollingFile>
修改后 ${env:log4j.logSuffix:-} 参数说明:
${前缀:变量:-默认值}
- env:标识引用变量作用域,使用环境变量
- log4j.logSuffix:指定变量名
- -:如果没有环境变量则使用默认值,-后面没接任何内容标识默认为空字符串
修改后的启动命令为:
nohup java -jar xxxApp.jar # 启动主应用
nohup java -Dlog4j.logSuffix="-devops" -jar xxxApp.jar devOps # 启动运维模式
修改后它们就能够使用同一个日志配置文件,并且分别输出到xxxApp.log和xxxApp-devops.log文件中,互不干扰。