常见日志框架


目录:

  1. 概览

  2. 日志的发展历程

  3. 基本用法

  4. 1 log4j

  5. 2 jul

  6. 3 jcl

  7. 4 slf4j

  8. 5 log4j2

参考/来源:

概览

  1. 市面流行的日志框架

    • JUL:java util logging Java原生日志框架。
    • Log4j:Apache的一个开源项目。
    • Logbcak :由Log4j之父做的另一个开源项目,业界中称为 log4j 后浪。他是一个可靠、通用且灵活的Java日志框架。
    • Log4j2 :Log4j的第二个版本,各个方面与Logback及其相似。具有插件式结构、配置文件优化等特征,在Spring Boot1.4版本之后就不在支持 log4j ,所以出现了第二个版本的。
    • JCL
    • SLF4j
  2. 分类:

    • 日志框架技术 :JUL、Log4j、Logbcak、Log4j2
    • 日志门面技术 :JCL、SLF4j
  3. 为什么要使用日志门面技术:

    • 每一种日志框架都有自己单独的API,要使用对应的框架就要使用对应的API,这就大大的增加了应用程序代码对于日志框架的耦合性。使用日志门面技术之后,不论底层是什么日志框架,我们拿到代码之后可以使用自己习惯的日志框架就行解读,不用修改一行代码。

      image-20211213141008145
    • 其实框架1调用的是自己的方法a() ,框架2调用的自己的方法b() ,此时将这两个方法抽取出来称为方法c()。

日志的发展历程

  1. 从最早期开始,大家都是使用System.outSystem.err来打印日志;不灵活也不可以配置;要么全部打印,要么全部不打印;没有一个统一的日志级别

  2. 后来Log4j就出现了,它是Ceki Gülcü这个大佬开发的,后来Log4j成为了Apache基金会项目中的一员

  3. 后来Java也推出了自己的日志框架JUL(Java Util Logging),在package java.util.logging

  4. Apache又推出了日志接口Jakarta Commons Logging,也就是日志抽象层,你就可以很方便的在Log4jJUL之间做切换

  5. Ceki Gülcü觉得觉得JCL不好,开发了一套新的日志门面Slf4j(Simple Logging Facade for Java)、它的实现Logback以及一些桥接包:

    jcl-over-slf4j.jar :jcl ——> slf4j
    slf4j-jcl.jar :slf4j ——> jcl
    log4j-over-slf4j :log4j ——> slf4j
    slf4j-log4j12.jar :slf4j ——> log4j
    jul-to-slf4j :jul ——> slf4j
    slf4j-jdk14.jar :slf4j ——> jul

  6. 后来Apache直接推出新项目,不是Log4j1.x升级,而是新项目Log4j2,因为Log4j2是完全不兼容Log4j1.x的,它也搞了分离的设计,分化成log4j-apilog4j-core,这个log4j-api也是日志接口,log4j-core是日志实现,它也出了很多桥接包:

    log4j-jcl :jcl ——> log4j2
    log4j-1.2-api :log4j ——> log4j2
    log4j-slf4j-impl :slf4j ——> log4j2
    log4j-jul :jul ——> log4j2
    log4j-to-slf4j :log4j2 ——> slf4j

基本用法

log4j

  • 依赖

    <dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>
  • 配置文件

    log4j.properties

    # Set root logger level to DEBUG and its only appender to A1.
    log4j.rootLogger=DEBUG, A1
    # A1 is set to be a ConsoleAppender.
    log4j.appender.A1=org.apache.log4j.ConsoleAppender
    # A1 uses PatternLayout.
    log4j.appender.A1.layout=org.apache.log4j.PatternLayout
    log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
  • 测试类

    import org.apache.log4j.Logger;
    public class Main {
        public static void main(String[] args) {
            Logger logger = Logger.getLogger(Main.class);
            logger.info("hello, world!");
        }
    }
     
    /*
    输出:
    0    [main] INFO  cn.eagleli.log.log4j.Main  - hello, world!
    */

jul

import java.util.logging.Logger;
public class Main {
    public static void main(String[] args) {
        Logger logger = Logger.getLogger(Main.class.getName());
        logger.info("hello, world!");
    }
}
/*
输出:
八月 11, 2021 11:06:19 下午 cn.eagleli.log.jul.Main main
信息: hello, world!
*/

jcl

  • 依赖:

    <dependencies>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>
  • 测试类

    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    public class Main {
        public static void main(String[] args) {
            Log log = LogFactory.getLog(Main.class);
            log.info("hello, world!");
        }
    }
    /*
    输出:
    八月 11, 2021 11:08:25 下午 cn.eagleli.log.jcl.Main main
    信息: hello, world!
    */

    从上面输出结果可以看出,默认会使用jul作为底层的日志框架

    如果我们想换成log4j作为底层的日志框架,怎么办呢?只需要加一个依赖即可,如下:

  • 依赖

    <dependencies>
           <dependency>
               <groupId>commons-logging</groupId>
               <artifactId>commons-logging</artifactId>
               <version>1.2</version>
           </dependency>
           <dependency>
               <groupId>log4j</groupId>
               <artifactId>log4j</artifactId>
               <version>1.2.17</version>
           </dependency>
       </dependencies>
  • 输出

    0    [main] INFO  cn.eagleli.log.jcl.Main  - hello, world!

    从结果可以看出,底层日志框架已经变了,同样发现,我们的代码没有任何改动,只是加了一个依赖,由此可以看出接口的重要性。

slf4j

  • 依赖

    <dependencies>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>1.7.30</version>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
                <version>1.2.3</version>
            </dependency>
        </dependencies>
  • 测试类

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    public class Main {
        public static void main(String[] args) {
            Logger logger = LoggerFactory.getLogger(Main.class);
            logger.info("hello, world!");
        }
    }
    /*
    输出:
    23:14:30.893 [main] INFO cn.eagleli.log.slf4j.Main - hello, world!
    */

    上面底层日志框架使用的是logback

    那如果我们想切换成jcl作为底层实现框架,怎么办呢?只需换一个依赖即可,如下:

  • 改变依赖

    <dependencies>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.30</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-jcl</artifactId>
            <version>1.7.30</version>
        </dependency>
    </dependencies>
  • 输出

    输出:
    八月 11, 2021 11:18:27 下午 org.slf4j.impl.JCLLoggerAdapter info
    信息: hello, world!

    从上面结果可以看出,底层已经切到jcl了,而jcl默认采用的是jdk日志框架

    cl-over-slf4jslf4j-jcl是不能同时使用的,因为前一个使用jcl API桥接到slf4j,后一个是使用slf4j API桥接到jcl,如果同时引用会导致循环调用,进而导致栈溢出

log4j2

  • 依赖

    <dependencies>
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-api</artifactId>
                <version>2.14.1</version>
            </dependency>
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-core</artifactId>
                <version>2.14.1</version>
            </dependency>
        </dependencies>
  • 测试类

    测试类:
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    public class Main {
        public static void main(String[] args) {
            Logger logger = LogManager.getLogger(Main.class);
            logger.error("hello, world!");
        }
    }
    /*
    输出:
    23:22:12.148 [main] ERROR cn.eagleli.log.log4j2.Main - hello, world!
    */

    以上我们采用的log4j2作为底层的实现,我们想要用slf4j作为底层的实现,怎么办呢?只需加一个依赖即可,如下:

  • 改变依赖

    <dependencies>
           <dependency>
               <groupId>org.apache.logging.log4j</groupId>
               <artifactId>log4j-api</artifactId>
               <version>2.14.1</version>
           </dependency>
           <dependency>
               <groupId>org.apache.logging.log4j</groupId>
               <artifactId>log4j-to-slf4j</artifactId>
               <version>2.14.1</version>
           </dependency>
       </dependencies>
  • 输出

    SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
    SLF4J: Defaulting to no-operation (NOP) logger implementation
    SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

    从结果看出,我们底层日志框架已经切换了,因为没有任何slf4j的实现类框架,所以没有输出日志。


文章作者: 小小千千
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 小小千千 !
评论
  目录