你是否遇到过配置了日志,但打印不出来的情况?
你是否遇到过配置了logback,启动时却提示log4j错误的情况?像下面这样:
log4j:WARN No appenders could be found for logger (org.example.App).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
你是否遇到过SLF4J的这种报错?
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/jiang/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/jiang/.m2/repository/org/slf4j/slf4j-log4j12/1.7.30/slf4j-log4j12-1.7.30.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
你是否遇到过DUBBO日志打印不正常的情况?
你是否遇到过Mybatis SQL日志打印不出来的情况?
你是否遇到过JPA/Hibernate SQL日志无法打印的情况?
你是否遇到过复杂项目中,很多框架内部日志无法打印的情况?
你是否遇到过Tomcat工程,日志文件打印了多份,catalina.out和其他文件?
你是否遇到过SpringBoot项目,日志文件打印了多份的问题?
你是否遇到过各种日志配置问题……
上面的这些问题,基本都是由于多套日志框架共存或配置错误导致的。那么为什么会出现共存或者冲突呢?
一般是以下几种原因:
1. 项目手动引用了各种日志框架的包 - 比如同时引用了log4j/log4j2/logback/jboss-logging/jcl等
2. 包管理工具的传递依赖(Transitive Dependencies)导致,比如依赖了dubbo,但是dubbo依赖了zkclient,可zkclient又依赖了log4j,此时如果你的项目中还有其他日志框架存在并有使用,那么就会导致多套共存
3. 同一个日志框架多版本共存
Java 里的各种日志框架
日志抽象/门面
日志实现
1. log4j - Apache(老牌日志框架,不过多年不更新了,新版本为log4j2)
2. log4j2 - Apache(log4j 的新版本,目前异步IO性能最强,配置也较简单)
3. logback - QOS(slf4j就是这家公司的产品)
4. jul(java.util.logging) - jdk内置
Spring Boot + Dubbo 日志框架冲突的例子
spring-boot-starter
依赖,此时我想集成dubbo,使用zookeeper作为注册中心,此时我的依赖配置是这样:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.9</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>2.7.9</version>
</dependency>
</dependencies>
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/jiang/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/jiang/.m2/repository/org/slf4j/slf4j-log4j12/1.7.30/slf4j-log4j12-1.7.30.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
----------------------------------人肉分割线----------------------------------------
log4j:WARN No appenders could be found for logger (org.apache.dubbo.common.logger.LoggerFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
1. slf4j报错,提示找到多个slf4j的日志绑定
2. log4j报错,提示log4j没有appender配置
logback/jcl(apache commons-logging)/log4j/jul-to-slf4j/slf4j-log4j/log4j-to-slf4j
slf4j-log4j
是log4j的slf4j实现,作用是调用slf4j api的时候使用log4j输出;而
log4j-to-slf4j
的作用是将
log4j
的实现替换为
log4j
,这样一来不是死循环了
slf4j-log4j
也是一样实现了slf4j的抽象,
logback
,项目里共存了两套
slf4j
的实现,那么在使用
slf4j
接口打印的时候会使用哪个实现呢?
log4j-over-slf4j
的包,这个包复制了一份log4j1的接口类(Logger等),同时将实现类修改为slf4j了。
log4j-over-slf4j
,就解决了这个log4j的问题。现在来修改下pom中的依赖(查看依赖图可以使用maven的命令,或者是IDEA自带的Maven Dependencies Diagram,再或者Maven Helper之类的插件)
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>2.7.9</version>
<scope>compile</scope>
<!--排除log4j-->
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!--增加log4j-slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.30</version>
</dependency>
slf4j-log4j
这个实现的依赖即可
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>2.7.9</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
日志适配大全
总结
1. 统一使用一套日志实现
2. 删除多余的无用日志依赖
3. 如果有引用必须共存的话,那么就移除原始包,使用“over”类型的包(over类型的包复制了一份原始接口,重新实现)
4. 不能over的,使用日志抽象提供的指定方式,例如jboss-logging
中,可以通过org.jboss.logging.provider
环境变量指定一个具体的日志框架实现
推荐阅读
1. 一份 Spring Boot 项目搭建模板
2.
Spring Boot 实现应用监控和报警
3. Nginx 从入门到实战
4. 一键式搭建分布式文件服务器
5. 团队开发中 Git 最佳实践
喜欢文章,点个
在看
本文分享自微信公众号 - Java后端(web_resource)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。