文档章节

slf4j、jcl、jul、log4j1、log4j2、logback大总结

乒乓狂魔
 乒乓狂魔
发布于 2015/05/04 06:37
字数 2357
阅读 29457
收藏 467

#1 系列目录

#2各种jar包总结

  • log4j1:

    • log4j:log4j1的全部内容
  • log4j2:

    • log4j-api:log4j2定义的API
    • log4j-core:log4j2上述API的实现
  • logback:

    • logback-core:logback的核心包
    • logback-classic:logback实现了slf4j的API
  • commons-logging:

    • commons-logging:commons-logging的原生全部内容
    • log4j-jcl:commons-logging到log4j2的桥梁
    • jcl-over-slf4j:commons-logging到slf4j的桥梁
  • slf4j转向某个实际的日志框架:

    场景介绍:如 使用slf4j的API进行编程,底层想使用log4j1来进行实际的日志输出,这就是slf4j-log4j12干的事。

    • slf4j-jdk14:slf4j到jdk-logging的桥梁
    • slf4j-log4j12:slf4j到log4j1的桥梁
    • log4j-slf4j-impl:slf4j到log4j2的桥梁
    • logback-classic:slf4j到logback的桥梁
    • slf4j-jcl:slf4j到commons-logging的桥梁
  • 某个实际的日志框架转向slf4j:

    场景介绍:如 使用log4j1的API进行编程,但是想最终通过logback来进行输出,所以就需要先将log4j1的日志输出转交给slf4j来输出,slf4j再交给logback来输出。将log4j1的输出转给slf4j,这就是log4j-over-slf4j做的事

    这一部分主要用来进行实际的日志框架之间的切换(下文会详细讲解)

    • jul-to-slf4j:jdk-logging到slf4j的桥梁
    • log4j-over-slf4j:log4j1到slf4j的桥梁
    • jcl-over-slf4j:commons-logging到slf4j的桥梁

#3集成总结

##3.1 commons-logging与其他日志框架集成

  • 1 commons-logging与jdk-logging集成:

    需要的jar包:

    • commons-logging
  • 2 commons-logging与log4j1集成:

    需要的jar包:

    • commons-logging
    • log4j
  • 3 commons-logging与log4j2集成:

    需要的jar包:

    • commons-logging
    • log4j-api
    • log4j-core
    • log4j-jcl(集成包)
  • 4 commons-logging与logback集成:

    需要的jar包:

    • logback-core
    • logback-classic
    • slf4j-api、jcl-over-slf4j(2个集成包,可以不再需要commons-logging)
  • 5 commons-logging与slf4j集成:

    需要的jar包:

    • jcl-over-slf4j(集成包,不再需要commons-logging)
    • slf4j-api

##3.2 slf4j与其他日志框架集成

  • slf4j与jdk-logging集成:

    需要的jar包:

    • slf4j-api
    • slf4j-jdk14(集成包)
  • slf4j与log4j1集成:

    需要的jar包:

    • slf4j-api
    • log4j
    • slf4j-log4j12(集成包)
  • slf4j与log4j2集成:

    需要的jar包:

    • slf4j-api
    • log4j-api
    • log4j-core
    • log4j-slf4j-impl(集成包)
  • slf4j与logback集成:

    需要的jar包:

    • slf4j-api
    • logback-core
    • logback-classic(集成包)
  • slf4j与commons-logging集成:

    需要的jar包:

    • slf4j-api
    • commons-logging
    • slf4j-jcl(集成包)

#4 日志系统之间的切换

##4.1 log4j无缝切换到logback

###4.1.1 案例

我们已经在代码中使用了log4j1的API来进行日志的输出,现在想不更改已有代码的前提下,使之通过logback来进行实际的日志输出。

已使用的jar包:

  • log4j

使用案例:

private static final Logger logger=Logger.getLogger(Log4jTest.class);

public static void main(String[] args){
	if(logger.isInfoEnabled()){
		logger.info("log4j info message");
	}
}

上述的Logger是log4j1自己的org.apache.log4j.Logger,在上述代码中,我们在使用log4j1的API进行编程

现在如何能让上述的日志输出通过logback来进行输出呢?

只需要更换一下jar包就可以:

  • 第一步:去掉log4j jar包

  • 第二步:加入以下jar包

    • log4j-over-slf4j(实现log4j1切换到slf4j)
    • slf4j-api
    • logback-core
    • logback-classic
  • 第三步:在类路径下加入logback的配置文件

原理是什么呢?

###4.1.2 切换原理

看下log4j-over-slf4j就一目了然了:

log4j转slf4j

我们可以看到,这里面其实是简化更改版的log4j。去掉log4j1的原生jar包,换成该简化更改版的jar包(可以实现无缝迁移)。

但是简化更改版中的Logger和原生版中的实现就不同了,简化版中的Logger实现如下(继承了Category):

public class Category {
    private String name;
    protected org.slf4j.Logger slf4jLogger;
    private org.slf4j.spi.LocationAwareLogger locationAwareLogger;

    Category(String name) {
        this.name = name;
        slf4jLogger = LoggerFactory.getLogger(name);
        if (slf4jLogger instanceof LocationAwareLogger) {
            locationAwareLogger = (LocationAwareLogger) slf4jLogger;
        }
    }
}

从上面可以看到简化版中的Logger内部是使用slf4j的API来生成的,所以我们使用的简化版的Logger会委托给slf4j来进行输出,由于当前类路径下有logback-classic,所以slf4j会选择logback进行输出。从而实现了log4j到logback的日志切换。

下面的内容就只讲解日志系统到slf4j的切换,不再讲解slf4j选择何种日志来输出

##4.2 jdk-logging无缝切换到logback

###4.2.1 案例

private static final Logger logger=Logger.getLogger(JulSlf4jLog4jTest.class.getName());

public static void main(String[] args){
	logger.log(Level.INFO,"jul info a msg");
	logger.log(Level.WARNING,"jul waring a msg");
}

可以看到上述是使用jdk-logging自带的API来进行编程的,现在我们想这些日志交给logback来输出

解决办法如下:

  • 第一步:加入以下jar包:

    • jul-to-slf4j (实现jdk-logging切换到slf4j)
    • slf4j-api
    • logback-core
    • logback-classic
  • 第二步:在类路径下加入logback的配置文件

  • 第三步:在代码中加入如下代码:

    static{
    	SLF4JBridgeHandler.install();
    }
    

###4.2.2 切换原理

先来看下jul-to-slf4j jar包中的内容:

jul切换到slf4j

我们看到只有一个类:SLF4JBridgeHandler

它继承了jdk-logging中定义的java.util.logging.Handler,Handler是jdk-logging处理日志过程中的一个处理器(具体我也没仔细研究过),在使用之前,必须要提前注册这个处理器,即上述的SLF4JBridgeHandler.install()操作,install后我们就可以通过这个handler实现日志的切换工作,如下:

protected Logger getSLF4JLogger(LogRecord record) {
    String name = record.getLoggerName();
    if (name == null) {
        name = UNKNOWN_LOGGER_NAME;
    }
    return LoggerFactory.getLogger(name);
}

在处理日志的过程中,使用了slf4j的原生方式LoggerFactory来获取一个slf4j定义的Logger来进行日志的输出

而slf4j则又会选择logback来进行实际的日志输出

##4.3 commons-logging切换到logback

###4.3.1 使用案例

使用的jar包

  • commons-logging

案例如下:

private static Log logger=LogFactory.getLog(JulJclTest.class);

public static void main(String[] args){
	if(logger.isTraceEnabled()){
		logger.trace("commons-logging-jcl trace message");
	}
}	

可以看到我们使用commons-logging的API来进行日志的编程操作,现在想切换成logback来进行日志的输出(这其实就是commons-logging与logback的集成)

解决办法如下:

  • 第一步:去掉commons-logging jar包(其实去不去都无所谓)

  • 第二步:加入以下jar包:

    • jcl-over-slf4j(实现commons-logging切换到slf4j)
    • slf4j-api
    • logback-core
    • logback-classic
  • 第三步:在类路径下加入logback的配置文件

###4.3.2 切换原理

这个原理之前都已经说过了,可以看下commons-logging与logback的集成

就是commons-logging通过jcl-over-slf4j 来选择slf4j作为底层的日志输出对象,而slf4j又选择logback来作为底层的日志输出对象。

##4.4 常用的日志场景切换解释

上面把日志的切换原理说清楚了,下面就针对具体的例子来进行应用

先来看下slf4j官方的一张图:

日志系统之间的切换

下面分别详细说明这三个案例

###4.4.1 左上图

  • 现状:

    目前的应用程序中已经使用了如下混杂方式的API来进行日志的编程:

    • commons-logging
    • log4j1
    • jdk-logging

    现在想统一将日志的输出交给logback

  • 解决办法:

    • 第一步:将上述日志系统全部无缝先切换到slf4j

      • 去掉commons-logging(其实去不去都可以),使用jcl-over-slf4j将commons-logging的底层日志输出切换到slf4j
      • 去掉log4j1(必须去掉),使用log4j-over-slf4j,将log4j1的日志输出切换到slf4j
      • 使用jul-to-slf4j,将jul的日志输出切换到slf4j
    • 第二步:使slf4j选择logback来作为底层日志输出

    加入以下jar包:

    • slf4j-api
    • logback-core
    • logback-classic

下面的2张图和上面就很类似

###4.4.2 右上图

  • 现状:

    目前的应用程序中已经使用了如下混杂方式的API来进行日志的编程:

    • commons-logging
    • jdk-logging

    现在想统一将日志的输出交给log4j1

  • 解决办法:

    • 第一步:将上述日志系统全部无缝先切换到slf4j

      • 去掉commons-logging(其实去不去都可以),使用jcl-over-slf4j将commons-logging的底层日志输出切换到slf4j
      • 使用jul-to-slf4j,将jul的日志输出切换到slf4j
    • 第二步:使slf4j选择log4j1来作为底层日志输出

    加入以下jar包:

    • slf4j-api
    • log4j
    • slf4j-log4j12(集成包)

###4.4.3 左下图

  • 现状:

    目前的应用程序中已经使用了如下混杂方式的API来进行日志的编程:

    • commons-logging
    • log4j

    现在想统一将日志的输出交给jdk-logging

  • 解决办法:

    • 第一步:将上述日志系统全部无缝先切换到slf4j

      • 去掉commons-logging(其实去不去都可以),使用jcl-over-slf4j将commons-logging的底层日志输出切换到slf4j
      • 去掉log4j1(必须去掉),使用log4j-over-slf4j,将log4j1的日志输出切换到slf4j
    • 第二步:使slf4j选择jdk-logging来作为底层日志输出

    加入以下jar包:

    • slf4j-api
    • slf4j-jdk14(集成包)

#5 冲突说明

仍然是这里的内容slf4j官网的冲突说明

其实明白上面介绍的各jar包的作用,就很容易理解

##5.1 jcl-over-slf4j 与 slf4j-jcl 冲突

  • jcl-over-slf4j: commons-logging切换到slf4j

  • slf4j-jcl : slf4j切换到commons-logging

如果这两者共存的话,必然造成相互委托,造成内存溢出

##5.2 log4j-over-slf4j 与 slf4j-log4j12 冲突

  • log4j-over-slf4j : log4j1切换到slf4j
  • slf4j-log4j12 : slf4j切换到log4j1

如果这两者共存的话,必然造成相互委托,造成内存溢出。但是log4j-over-slf4内部做了一个判断,可以防止造成内存溢出:

即判断slf4j-log4j12 jar包中的org.slf4j.impl.Log4jLoggerFactory是否存在,如果存在则表示冲突了,抛出异常提示用户要去掉对应的jar包,代码如下,在slf4j-log4j12 jar包的org.apache.log4j.Log4jLoggerFactory中:

slf4j-log4j12防止冲突的策略

##5.3 jul-to-slf4j 与 slf4j-jdk14 冲突

  • jul-to-slf4j : jdk-logging切换到slf4j
  • slf4j-jdk14 : slf4j切换到jdk-logging

如果这两者共存的话,必然造成相互委托,造成内存溢出

#6 结束语

至此,这个日志系列就算终于完成了。它注重于日志系统之间的交互与集成,所以想深入研究单个日志系统的架构的话,就需要各位自行去深入研究了。

欢迎关注微信公众号:乒乓狂魔

微信公众号

© 著作权归作者所有

乒乓狂魔

乒乓狂魔

粉丝 1050
博文 109
码字总数 278265
作品 0
长宁
程序员
私信 提问
加载中

评论(34)

c
codinggggg
大神!太感谢了,看此系列再也不用视日志入猛虎了!
m
mnisummer
收货很大。了解清楚,后续就不会那么迷糊了
adamfei
adamfei
点赞!
看了一遍,想问比较弱的问题,我可以理解为 log4j /log4j2/logback其实底层都是基于jdk logging来封装实现的吗?而common-logging和slf4j是封装各类日志系统的门面,可以实现不同日志系统快速切换的吗?
zzuqiang
zzuqiang
读君4篇文,了却多日之困惑!真赞!
缘字诀
缘字诀
very very good
闲来觅箫声
看完文章才发现原来很简单,谢谢!
乒乓狂魔
乒乓狂魔 博主

引用来自“涂冰冰”的评论

刚哥好猛呢
过奖过奖
涂冰冰
涂冰冰
刚哥好猛呢
FinnLian
FinnLian
够厉害
William威廉
William威廉
够厉害
jcl与jul、log4j1、log4j2、logback的集成原理

1 系列目录 - jdk-logging、log4j、logback日志介绍及原理- jcl与jul、log4j1、log4j2、logback的集成原理- slf4j与jdk-logging、log4j1、log4j2、logback的集成原理- slf4j、jcl、jul、log...

乒乓狂魔
2015/04/29
4.6K
2
Java混乱的日志体系(logback)(转)

作为一名 Java 程序员,日常开发工作中肯定会接触日志系统,但是众多的框架,包括 Log4j、Log4j2、Logback、Slf4j、Apache Common logging 等等,引用的 maven 依赖众多,到底可以去掉哪些,...

easonjim
2017/12/27
0
0
slf4j与jul、log4j1、log4j2、logback的集成原理

1 系列目录 - jdk-logging、log4j、logback日志介绍及原理- commons-logging与jdk-logging、log4j1、log4j2、logback的集成原理- slf4j与jdk-logging、log4j1、log4j2、logback的集成原理- s...

乒乓狂魔
2015/04/30
4.8K
5
jdk-logging、log4j、logback日志介绍及原理

系列文章已完成,目录如下: - jdk-logging、log4j、logback日志介绍及原理- commons-logging与jdk-logging、log4j1、log4j2、logback的集成原理- slf4j与jdk-logging、log4j1、log4j2、log...

乒乓狂魔
2015/04/27
14.5K
17
【Spring Boot】4.日志

1 日志框架的选择 1.1 框架一览 JUL、JCL、JBoss-logging、log4j、log4j2、slf4j等。 日志门面(抽象层) 日志实现 JCL(Jakra Commons Logging) SLF4j(Simple Logging Facade for Java) Jbo...

落花时节又逢卿
2018/12/27
167
0

没有更多内容

加载失败,请刷新页面

加载更多

移动深度学习:人工智能的深水区

人工智能技术经历6年的快速发展,重新定义了很多行业的用户体验,而这仅是开始。 随着5G商用大规模落地,以及智能手机硬件性能越来越强、AIoT设备的快速普及,基于云-边缘-端算法和算力结构的...

博文视点Bv
33分钟前
4
0
vim 分屏 操作

$vim -On file file2 #大写O垂直分屏打开文件 $vim -on file file2 #小写水平打开 # n 表示分屏数,直接n等于文件个数 如果n小于文件,按顺序打开前面的n个,如果大于,打开空编辑页面 分屏快...

突突突酱
35分钟前
4
0
MySQL/Mariadb设置中文字符集(linux)

编辑/etc/my.cnf,添加以下设置 [mysql]default-character-set=utf8[mysqld]character_set_server=utf8[mysqld.safe]default-character-set=utf8[client]default-chara...

编程老陆
38分钟前
4
0
关于linux常用的挂载命令

挂载:就把一块磁盘(可以是光盘,U盘)绑定到一个空目录下面 一般情况下会挂载到mnt目录下面 挂载光盘(把光盘挂载到/mnt/cdrom这个目录中) mount -t iso9660 /dev/cdrom /mnt/cdrom 退出当前目录...

chenhongjiang
39分钟前
4
0
如何分享brain内容外部共享?几个需要知道的TheBrain问答

TheBrain(点击下载)是一款与众不同的思维导图软件,其所有信息通过一个又一个的节点进行联系,最终形成一个杂而不乱的网状结构。从头开始设计,让您捕获您的想法和信息在一个网络的联想,匹...

mnrssj
39分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部