老版本NacosClient 结合 Logstash出现 'File' option has the same value 疑问
使用的版本 spring cloud 2021.0.9 spring cloud alibaba 2021.0.6.1 内部自带nacos-client:2.2.0
nacos-client:2.2.0 不启动logstash日志是正常的 nacos-client的日志可以正常写入到${user.home}/logs下 相关日志不会输出到控制台上
启用logstash日志后出现'File' option has the same value 日志append重复加载
升级nacos-client:2.4.0/2.5.1/2.5.2 新增了两个扩展包 nacos-logback-adapter/logback-adapter
两个扩展包都剔除掉 启用logstash 日志正常,但nacos-client 日志输出被打印到控制台了 不会往本身定义的日志文件里写入
剔除掉nacos-logback-adapter-12 启用logstash 日志出错 append被重复加载
剔除掉logback-adapter 启用logstash 日志正常,但nacos-client 日志输出被打印到控制台了 不会往本身定义的日志文件里写入
这个情况是对的吗?正常情况下日志不应该输出到控制台 而是由客户端包记录到自己的日志文件中吗?
有什么办法可以解决这个问题吗?日志由nacos-client记录并输出到自己本身的目录,控制台只输出项目本身的信息
这部分是错误信息 21:10:23,069 |-ERROR in ch.qos.logback.core.rolling.RollingFileAppender[CONFIG_LOG_FILE] - 'File' option has the same value "C:\Users\xxx/logs/nacos/config.log" as that given for appender [CONFIG_LOG_FILE] defined earlier. 21:10:23,070 |-ERROR in ch.qos.logback.core.rolling.RollingFileAppender[CONFIG_LOG_FILE] - Collisions detected with FileAppender/RollingAppender instances defined earlier. Aborting.
21:10:43,018 |-WARN in ch.qos.logback.core.rolling.RollingFileAppender[REMOTE_LOG_FILE] - Attempted to append to non started appender [REMOTE_LOG_FILE]. 21:10:43,025 |-WARN in ch.qos.logback.core.rolling.RollingFileAppender[REMOTE_LOG_FILE] - Attempted to append to non started appender [REMOTE_LOG_FILE]. 21:10:43,027 |-WARN in ch.qos.logback.core.rolling.RollingFileAppender[REMOTE_LOG_FILE] - Attempted to append to non started appender [REMOTE_LOG_FILE].
看起来像是logstash阻塞了logback的日志初始化流程,导致nacos-client想要加载自己的日志配置时失败了。 欢迎详细研究一下原理,然后帮助社区优化这部分流程。
如果只是想跳过这个问题, 可以复制nacos-lient中的日志配置到自己的日志配置中。
https://github.com/loki4j/loki-logback-appender/discussions/256
补充:使用其他日志框架也出现类似问题
发现nacos-client 2.0.4版本无此问题 从2.1.0版本开始报错
nacos-client:2.4.0 2.5.1 2.5.2
logback-adapter 它是需要支持logback >= 1.3.x 项目boot 2.7.18 logback1.2.13 它是不支持的 com.alibaba.nacos.client.logging.NacosLogging:54 判断失败 会走项目本身的日志适配器,所以看不到报错,直接把日志打印到程序控制台了 疑问点是这个警告并不会打印 LOGGER.warn("Nacos Logging don't find adapter, logging will print into application logs.");
nacos-logback-adapter-12它支持logback 1.2.x 使用它后程序就开始出现重复加载append
getLogger("com.alibaba.nacos.client.naming")#loadConfiguration loggingProperties -defaultLocation: classpath:nacos-logback12.xml
com.alibaba.cloud.nacos.logging.NacosLoggingAppRunListener#environmentPrepared#loadConfiguration loggingProperties -defaultLocation: classpath:nacos-logback12.xml
spring boot logo 开始打印
com.alibaba.cloud.nacos.logging.NacosLoggingAppRunListener#contextPrepared#loadConfiguration loggingProperties -defaultLocation: classpath:nacos-logback12.xml
LoggerContext loggerContext = this.loadConfigurationOnStart(location); 执行开始出现错误 重复加载
LoggerContext loggerContext = this.loadConfigurationOnStart(location); if (this.hasNoListener(loggerContext)) { this.addListener(loggerContext, location); }
怀疑是不是先加载了再去做的判断导致的 com.alibaba.nacos.logger.adapter.logback12.LogbackNacosLoggingAdapter#loadConfigurationOnStart this.configurator.configure(ResourceUtils.getResourceUrl(location)); 它好像是拿到资源直接添加配置到logback里了 com.alibaba.nacos.logger.adapter.logback12.NacosLogbackConfiguratorAdapterV1#configure
个人理解: 已知:loadConfiguration() 方法会执行三次: 1.初始化SpringCloud 上下文 2.初始化SpringBoot 上下文 3.初始化ConfigService时,Logger对象调用LogUtils,static方法初始化
2.1.0版本对LogUtils类的static方法初始化Logback配置进行了重写 NacosLogging.getInstance().loadConfiguration();
类:LogbackNacosLogging
下面的代码会获取一个单例的LoggerContext
@Override
public void loadConfiguration() {
LoggerContext loggerContext = loadConfigurationOnStart();
if (loggerContext.getObject(CoreConstants.RECONFIGURE_ON_CHANGE_TASK) != null) {
addListener(loggerContext);
}
}
private LoggerContext loadConfigurationOnStart() {
String location = getLocation(NACOS_LOGBACK_LOCATION);
try {
LoggerContext loggerContext = (LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory();
NacosJoranConfigurator configurator = new NacosJoranConfigurator();
configurator.setContext(loggerContext);
configurator.doNacosConfigure(ResourceUtils.getResourceUrl(location));
return loggerContext;
} catch (Exception e) {
throw new IllegalStateException("Could not initialize Logback Nacos logging from " + location, e);
}
}
而在LogUtils static方法初始化时, loggerContext对象中的FA_FILENAME_COLLISION_MAP 已包含CONFIG_LOG_FILE,NAMING_LOG_FILE,REMOTE_LOG_FILE 所以报错 报错位置:FileAppender.checkForFileCollisionInPreviousFileAppenders()
2.0.4版本 每次都会重新new一个 LoggerContext
@Override
public void loadConfiguration() {
String location = getLocation(NACOS_LOGBACK_LOCATION);
if (StringUtils.isBlank(location)) {
return;
}
try {
loggerContext = new LoggerContext();
new ContextInitializer(loggerContext).configureByResource(ResourceUtils.getResourceUrl(location));
} catch (Exception e) {
throw new IllegalStateException("Could not initialize Logback Nacos logging from " + location, e);
}
}
所以现在目的是期望日志按照nacos-client自身的设定,输出到指定文件中而不是控制台中,且希望加载日志不报错对吧。
首先不能移除拓展包,因为加载日志配置文件的逻辑是在拓展包中的,移除之后就不会加载appender, 那么日志一定输出在控制台上(或者其他root logger的appender里)
如果加入拓展包的情况, 需要分析Logstash到底影响了什么加载的内容,导致nacos-client的日志appender被加载失败且报错了。
然后才能找到解决办法,这部分需要您这边有可复现的现场进行分析。
我这里需要提供什么样的现场?最小demo吗?如果是具体版本号的话上方提供的可以准确回显,期望是日志按照nacos-client自身的设定执行且加载日志不报错,因为不确定会引发什么问题
如果有可稳定复现的最小demo自然最好, 如果没有的话仅提供对应版本可能别人无法复现或别人没有那么多时间去搭建可复现环境, 问题被解决的可能性会降低。