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

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。去掉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包中的内容:

我们看到只有一个类: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中:

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

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

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

6 结束语

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

时间: 2024-09-28 19:41:13

slf4j、jcl、jul、log4j1、log4j2、logback大总结的相关文章

slf4j与jul、log4j1、log4j2、logback的集成原理

1 系列目录 jdk-logging.log4j.logback日志介绍及原理 commons-logging与jdk-logging.log4j1.log4j2.logback的集成原理 slf4j与jdk-logging.log4j1.log4j2.logback的集成原理 slf4j.jcl.jul.log4j1.log4j2.logback大总结 2 slf4j 先从一个简单的使用案例来说明 2.1 简单的使用案例 private static Logger logger=LoggerF

jcl与jul、log4j1、log4j2、logback的集成原理

1 系列目录 jdk-logging.log4j.logback日志介绍及原理 jcl与jul.log4j1.log4j2.logback的集成原理 slf4j与jdk-logging.log4j1.log4j2.logback的集成原理 slf4j.jcl.jul.log4j1.log4j2.logback大总结 前面介绍了jdk自带的logging.log4j1.log4j2.logback等实际的日志框架 对于开发者而言,每种日志都有不同的写法.如果我们以实际的日志框架来进行编写,代码就限

SLF4J和Logback日志框架详解

SLF4J和Logback日志框架详解 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs 本文讲述SLF4J和Logback日志框架.   SLF4J是一套简单的日志外观模式的Java API,帮助在项目部署时对接各种日志实现. LogBack在运行时使用JMX帮助修改日志配置,在生产状态下无需重启应用程序. SLF4J SLF4J是简单的日志外观模式框架,抽象了各种日志框架例如Logback.Log4j.Commons-logging和JDK自带的l

日志组件slf4j介绍及配置详解

1 基本介绍 每一个Java程序员都知道日志对于任何一个Java应用程序,尤其是服务端程序是至关重要的,而很多程序员也已经熟悉各种不同的日志库如java.util.logging.Apache log4j.logback.但如果你还不知道SLF4J(Simple logging facade for Java)的话,那么是时候去在你项目中学习使用SLF4J了. SLF4J不同于其他日志类库,与其它日志类库有很大的不同.SLF4J(Simple logging Facade for Java)不是

Spring boot 启动过程解析 logback

使用 Spring Boot 默认的日志框架 Logback. 所有这些 POM 依赖的好处在于为开发 Spring 应用提供了一个良好的基础.Spring Boot 所选择的第三方库是经过考虑的,是比较适合产品开发的选择.但是 Spring Boot 也提供了不同的选项,比如日志框架可以用 Logback 或 Log4j,应用服务器可以用 Tomcat 或 Jetty. http://www.ibm.com/developerworks/cn/java/j-lo-spring-boot/ sp

深入源码之Commons Logging

自从七月份去走川藏后,已经好几个月没有更新博客了.其实八月底从拉萨回来后一直在Spring的代码,也想写几篇关于Spring源码的解读,可惜Spring实在是太复杂了,花了我一个多月的时间,框架大体流程是有头绪了,但是具体实现和各个模块的具体细节还都不是很清楚,迟迟不敢动笔.其实原本我不想回到Logging这一块,我知道光看完Log4J的代码还不够,也感觉Log在系统中其实占据了蛮重要的位置(虽然很多人都没有意识到),不过一般Log框架使用简单,遇到问题也比较少,即使看完源码对实际工作也帮助不大

Taxonomy of class loader problems encountered when using Jakarta Commons Logging(转)

  Acknowledgments I would like to thank Jacob Kjome for reviewing early drafts of this document. His comments helped to clarify several important points. Jake also keeps reminding us on the log4j-dev mailing list that the child-parent delegation mode

commons-logging 的运行时发现算法到底有什么问题

问题描述 Spring的文档中提到引用 解决方案 引用No, it's not performance, it's classloader pain. JCL discovery process relies on classloader hacks to find the logging framework at runtime but this mechanism leads to numerous problems including unexpected behavior, hard t

AideRSS下的博客文章排行

AideRSS是个有趣的博客统计工具,通过一些外部工具或者反向链接来给出博客文章的综合评分,有一定的参考价值.可惜对于中文博客来说,通过Digg和Del.icio.us来评测不是特别准确,特别是Digg的中文用户很少,如果其能够使用Google Reader的Share或者鲜果阅读器的外部推荐等数据来统计,那对中文用户来说会更准确一些. AideRSS的统计主要是根据西方的社会化工具使用情况评分的,因此如果这个工具在国内不普及,那么就会出现误差. 下面是月光博客的统计数据,显示了从2007年7月