使用nacos做注册中心导致log4j日志服务异常

问题起源

日志框架用的log4j,接入阿里云Alibaba Cloud Log Log4j Appender做日志采集,以及错误预警。某天发现线上无法正常采集日志数据,怀疑是dubbo日志包冲突影响导致。报错信息:

1
2
3
4
5
main DEBUG Using configurationFactory org.apache.logging.log4j.core.config.ConfigurationFactory$Factory@1153ee42

main DEBUG Closing JarURLInputStream sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@31fcad71

main WARN No Root logger was configured, creating default ERROR-level Root logger with Console appender

问题追溯

IDEA有个功能,可以查看maven项目依赖总览图。如图所示功能:
image
这样很方便就可以找到是哪个jar包包含的依赖有冲突。
去除了dubbo的log4j依赖,问题依然重现。再判断是否nacos导致的。查看nacos源码发现以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public Log4J2NacosLogging() {
String location = this.getLocation("classpath:nacos-log4j2.xml");
if(!StringUtils.isBlank(location)) {
this.locationList.add(location);
}

}

public void loadConfiguration() {
if(!this.locationList.isEmpty()) {
List configList = this.findConfig(this.getCurrentlySupportedConfigLocations());
if(configList != null) {
this.locationList.addAll(configList);
}

ArrayList configurations = new ArrayList();
LoggerContext loggerContext = (LoggerContext)LogManager.getContext(false);
Iterator compositeConfiguration = this.locationList.iterator();

while(compositeConfiguration.hasNext()) {
String location = (String)compositeConfiguration.next();

try {
Configuration e = this.loadConfiguration(loggerContext, location);
if(e instanceof AbstractConfiguration) {
configurations.add((AbstractConfiguration)e);
}
} catch (Exception var7) {
throw new IllegalStateException("Could not initialize Log4J2 Nacos logging from " + location, var7);
}
}

CompositeConfiguration compositeConfiguration1 = new CompositeConfiguration(configurations);
loggerContext.start(compositeConfiguration1);
}
}

nacos注册中心会查找nacos的日志配置文件,如果找不到怎么办呢,再下面代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private String[] getCurrentlySupportedConfigLocations() {
ArrayList supportedConfigLocations = new ArrayList();
if(ClassUtils.isPresent("com.fasterxml.jackson.dataformat.yaml.YAMLParser")) {
Collections.addAll(supportedConfigLocations, new String[]{"log4j2.yaml", "log4j2.yml", "log4j2-test.yaml", "log4j2-test.yml"});
}

if(ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper")) {
Collections.addAll(supportedConfigLocations, new String[]{"log4j2.json", "log4j2.jsn", "log4j2-test.json", "log4j2-test.jsn"});
}

supportedConfigLocations.add("log4j2.xml");
supportedConfigLocations.add("log4j2-test.xml");
return (String[])supportedConfigLocations.toArray(new String[supportedConfigLocations.size()]);
}

nacos会引用它默认的配置信息,导致之前项目的log4j配置失效。如何禁用nacos的默认配置,在它配置工厂类有写:

private boolean isDefaultConfigEnabled() {
        String property = System.getProperty("nacos.logging.default.config.enabled");
        return property == null || BooleanUtils.toBoolean(property);
}

我们只需要在系统变量中设置nacos.logging.default.config.enabled=false,然后把nacos的日志配置信息放到我们项目中的log4j文件中即可,在nacos-client源码中我们可以找到log4j以及logback的写法。