现象
最近发布spring boot项目时遇到了一个奇怪的问题,日志异常信息如下:
Caused by: java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class org.slf4j.impl.SimpleLoggerFactory loaded from jar:file:/xxxxx/xxxxx.jar!/BOOT-INF/lib/slf4j-simple-1.7.30.jar!/). If you are using WebLogic you will need to add ‘org.slf4j’ to prefer-application-packages in WEB-INF/weblogic.xml: org.slf4j.impl.SimpleLoggerFactory
意思是检测到项目里面有多个slf4j-api的实现,因为我的项目里面使用logback作为我的日志库,所以造成了冲突。
问题
这个问题是这两天刚出现的,但事实上我并没有使用slf4j-simple,并且本地debug的时候也没有该报错。所以我的目标是找到这个slf4j-simple来自哪里。
排查思路一:分析pom依赖
我的第一步是打开项目的pom文件,借助idea的maven-helper插件,对整个项目的依赖库进行了过滤,但是并没有找到这个类库。
排查思路二:解压jar包
随后我根据报错的提示file:/xxxxx/xxxxx.jar!/BOOT-INF/lib/slf4j-simple-1.7.30.jar!,将流水线构建的jar包下载并解压,确实在这个路径下看到了这个jar包。于是我又给本地项目打了一个胖包,解压后发现,同样的路径下并没有这个jar文件。
排查思路三:更新本地仓库
既然本地没有找到,那么可能本地的maven仓库不是最新的,于是我把本地的maven仓库做了重命名,然后重新打开工程文件,让maven重新从远程仓库下载。
花了大约十分钟,maven依赖终于下载完毕。这一次我直接在maven本地仓库的文件夹下面查找,发现压根没有下载这个文件。
奇迹出现
就在我百思不得其解之际,我看到同事在流水线上使用同样的分支又构建了一次,并且发布成功了。这下惊掉了我的下巴,赶忙把它构建的jar包下载下来进行对比,一看它的jar包里面确实不存在slf4j-simple-1.7.30.jar。
寻求帮助
抱着这个疑问,我咨询了负责流水线的运维同学,最后在他们的不懈努力下,发现了问题。运维同学先是把所有依赖的jar包都解压,然后直接搜关键字,最后在其中一个sdk里面,发现了slf4j-simple-1.7.30.jar,但已经是被注释的状态。
真相大白
后面我咨询了同事,原来是他这两天在开发sdk时,不小心引入了这个类库,在发现问题之后,又将其注释了,但是前后的两个版本号都是同一个。并且修复的时间,恰好就在我排查问题的这个时间内。
这确实是个大坑。
正好解释了为什么这个问题是这两天才出现的,因为他前两天刚刚引入了这个类库并且在不修改sdk版本号的情况下将其上传到远程maven仓库,所以当我们进行发布的时候,就出现问题了。而我本地由于已经存在相同版本号的sdk,所以并不会更新代码,本地运行也就不会报错。
而就在刚刚他修复完sdk后,再一次用相同版本号进行了上传,此时我刚好在执行第三步的排查,更新本地的maven仓库,所以依旧没有找到破绽,因为问题实际上已经修复了。这个时候他再进行分支构建,就打出了没有问题的jar包了。
结论
本次问题的根本原因是同事修改pom代码但不修改SDK版本号就直接上传远程仓库,这种行为在实际开发中其实并不少见,有时候开发者觉得代码修改量不多、影响不大或者不愿意有问题的jar包被上传到远程仓库上,从而选择直接覆盖。假如这个时候你的同事刚好在排查问题,可能对他来说就是灾难。最后,希望这篇文章能够对大家排查类似问题提供思路。