之前组内开发迭代多个版本偶尔出现此问题,然后组内同学也没有从根本上去排查问题,由于当时比较忙着开发跟进进度也就没来的及追究此问题。本次又是组内同学添加一个监控的类库之后添加一些跟监控有关的配置之后Push代码到了远程git仓库;随后我pull下来代码进行merge之后便无法启动而且控制台很干净不报错,很郁闷。下面描述一下排错分析过程“”
1:多次启动排查配置错误并没有解决问题,只好进行debug,天下bug唯有debug不破!!!
2:进行debug,很快就定位问题了:
放过断点之后来到了源码842行:
通过debug也可以看见异常信息,放过断点让程退出,控制台信息如下:
没有日志!!!!所以怀疑是日志配置问题,而且上面图中已经看到Logger使用的是Log4j,而本系统业务日志使用的是LogBack。
3:到此已经确认是日志问题了,所以就想办法解决方案,大概思路两种:
思路1:
Logger不打印日志,缺少配置文件所致,因此添加一个log4j.properties日志文件,内容如下:
##########Set Log Levels###############
log4j.rootLogger = ERROR, console
######### 输出到控制台 ####################
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.err
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = %d{ABSOLUTE}%5p%c{ 1 :%L-%m%n
之后执行,日志神器一般的打印出来了:
所以这种就是没有配置日志的输出位置,因此日志无法打印输出。
思路2:
让Logger使用我们自己配置的Logback的logger,这样就可以使用我们的logback日志配置打印错误信息了,但是为什么没有使用我们的logback呢?由于slf4j使用的是门面设计模式,启动时候跟动态绑定日志实现,根据这个思路就怀疑是项目中可能引入了其他Log实现,只能想到的是maven传递引入的,因此使用mvn dependency:tree > tree.txt 可以看到:
[INFO] +- tech.tablesaw:tablesaw-core:jar:0.12.0:compile
[INFO] | +- com.google.code.gson:gson:jar:2.8.2:compile
[INFO] | +- org.apache.commons:commons-math3:jar:3.6.1:compile
[INFO] | +- org.apache.commons:commons-lang3:jar:3.7:compile
[INFO] | +- com.opencsv:opencsv:jar:4.1:compile
[INFO] | | +- org.apache.commons:commons-text:jar:1.1:compile
[INFO] | | \- commons-beanutils:commons-beanutils:jar:1.9.3:compile
[INFO] | | +- commons-logging:commons-logging:jar:1.2:compile
[INFO] | | \- commons-collections:commons-collections:jar:3.2.2:compile
[INFO] | +- org.jsoup:jsoup:jar:1.11.2:compile
由于不打印日志的logger是org.apache.commons.logging中的,所以需要排除此依赖:
经过tree.txt 排查果然是有common log的依赖,部分排除依赖代码:
tech.tablesaw
tablesaw-core
${tablesaw.version}
commons-logging
commons-logging
上面的排除依赖只是部分,不是完整的,还需要将Log4j排除掉,本文不在列举!!!!经过排除之后再次运行:
也成功打印出来了!!!!!!
4:分析原因:为什么会发生这个问题呢?
首先看一下commons loggging的官网描述:
The Logging package is an ultra-thin bridge between different logging implementations. A library that uses the commons-logging API can be used with any logging implementation at runtime. Commons-logging comes with support for a number of popular logging implementations, and writing adapters for others is a reasonably simple task.
再看一下slf4j的官网描述:
The Simple Logging Facade for Java (SLF4J) serves as a simple facade or abstraction for various logging frameworks (e.g. java.util.logging, logback, log4j) allowing the end user to plug in the desired logging framework at deployment time.
可知 commons loggging与SLF4J并不是真实的日志框架,他们只是一个标准接口而已,具体实现会根据运行时绑定的具体日志进行记录log。