关于log4j、jul、jcl、slf4j等等日志组件的理解

MrLiar 2020-04-27

日志组件:

我们经常在开发项目的时候,需要打印记录项目过程中的一些日志。那我们经常大概会用到 log4j、jul、jcl、slf4j、simple、nop、logback 等等,那我们就详细介绍下这些组件是怎么做日志打印的

JUL:

JUL全称Java util Logging是java原生的日志框架,使用时不需要另外引用第三方类库,相对其他日志框架使用方便,学习简单,能够在小型应用中灵活使用。
架构介绍:

             关于log4j、jul、jcl、slf4j等等日志组件的理解

Loggers :被称为记录器,应用程序通过获取Logger对象,调用其API来发布日志信息。Logger通常为应用程序访问日志系统的入口程序。
  Appenders :也被称为Handlers,每个Logger都会关联一组Handlers,Logger会将日志交给关联Handlers处理,由Handlers负责将日志做记录。Handlers在此是一个抽象,其具体的实现决定了日志记录的位置可以是控制台、文件、网络上的其他日志服务或操作系统日          志等。
  Layouts :也被称为Formatters,它负责对日志事件中的数据进行转换和格式化。Layouts决定了数据在一条日志记录中的最终形式。
  Level :每条日志消息都有一个关联的日志级别。该级别粗略指导了日志消息的重要性和紧迫,我可以将Level和Loggers,Appenders做关联以便于我们过滤消息。
  Filters :过滤器,根据需要定制哪些信息会被记录,哪些信息会被放过。

总结:
    用户使用Logger来进行日志记录,Logger持有若干个Handler,日志的输出操作是由Handler完成的。
    在Handler输出日志前,会经过Filter的过滤,判断哪些日志级别过滤放行哪些拦截,
    Handler会将日志内容输出到指定位置(日志文件、控制台等)。Handler在输出日志时会使用Layout,将输出内容进行排版

   案例: 

public class JULTest {

    @Test
    public void test01() {
        // 1.获取日志记录器对象
        Logger logger = Logger.getLogger("jul");
        // 2.日志记录输出
        logger.info("jul");
    }
} 

日志的级别:

jul中定义的日志级别

  java.util.logging.Level中定义了日志的级别:
      SEVERE(最高值)
      WARNING  警告信息
      INFO (默认级别)
      CONFIG  配置信息
      FINE  debug级别信息,信息颗粒度最小
      FINER  debug级别信息
      FINEST(最低值)debug级别信息,信息颗粒度最大
    还有两个特殊的级别:
      OFF,可用来关闭日志记录。
      ALL,启用所有消息的日志记录。

日志级别案例:

@Test
public void testLogLevel() {
    // 1.获取日志对象
    Logger logger = Logger.getLogger("jul");
    // 2.日志记录输出
    logger.severe("severe");
    logger.warning("warning");
    logger.info("info");
    logger.config("config");
    logger.fine("fine");
    logger.finer("finer");
    logger.finest("finest");
}

由于默认级别是info, 所以以上日志只会打印 info以上级别的日志

修改日志级别:

@Test
public void testLogConfig() throws IOException {
    // 1.创建日志记录器对象
    Logger logger = Logger.getLogger("jul");

    // 一、自定义日志级别
    // a.关闭系统默认配置
    logger.setUseParentHandlers(false);
    // b.创建handler对象
    ConsoleHandler consoleHandler = new ConsoleHandler();
    // c.创建formatter对象(简单格式转换对象)
    SimpleFormatter simpleFormatter = new SimpleFormatter();
    // d.进行关联
    consoleHandler.setFormatter(simpleFormatter);
    logger.addHandler(consoleHandler);
    // e.设置日志级别
    logger.setLevel(Level.FINE);
    consoleHandler.setLevel(Level.FINE);

    // 二、输出到日志文件
    FileHandler fileHandler = new FileHandler("d:/jul.log");
    fileHandler.setFormatter(simpleFormatter);

    logger.addHandler(fileHandler);
    // 2.日志记录输出
    logger.severe("severe");
    logger.warning("warning");
    logger.info("info");
    logger.config("config");
    logger.fine("fine");
    logger.finer("finer");
    logger.finest("finest");
}

 

JCL:

JCL全称为Jakarta Commons Logging,是Apache提供的一个通用日志API。
  它是为 "所有的Java日志实现"提供一个统一的接口,它自身也提供一个日志的实现,但是功能非常弱(SimpleLog)。所以一般不会单独使用它。
  他允许开发人员使用不同的具体日志实现工具: Log4j, Jdk自带的日志(JUL)
  JCL 有两个基本的抽象类:Log(基本记录器)和LogFactory(负责创建Log实例)。

默认使用 jul 的实现

关于log4j、jul、jcl、slf4j等等日志组件的理解

   案例:

  1.添加依赖

  

  <dependencies>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

  2. 测试

public class JCLTest {

    @Test
    public void test() {
        // 创建日志对象
        Log log = LogFactory.getLog("jcl");
        // 日志记录输出
        log.info("info");
    }
}

JCL原理:

1. 通过LogFactory动态加载Log实现类

     关于log4j、jul、jcl、slf4j等等日志组件的理解

   2 . 日志门面支持的日志实现数组

  关于log4j、jul、jcl、slf4j等等日志组件的理解

   3 . 获取具体的日志实现

  关于log4j、jul、jcl、slf4j等等日志组件的理解

LOG4J:

Log4j是Apache下的一款开源的日志框架,通过在项目中使用 Log4J,我们可以控制日志信息输出到控制台、文件、甚至是数据库中。我们可以控制每一条日志的输出格式,通过定义日志的输出级别,可以更灵活的控制日志的输出过程。方便项目的调试

log4j.properties(最简单配置)

log4j.rootLogger=INFO,Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n

案例:

1. 添加依赖

<dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

2. 测试

@Test
public void test01() {
    // 获取日志记录器对象
    Logger logger = Logger.getLogger(Log4jTest.class);
    // 日志记录输出
    logger.info("hello log4j");

    // 日志测试
    logger.info("info");
}

日志的级别:

每个Logger都有一个日志级别(log level),用来控制日志信息的输出。日志级别从高到低分为:
    fatal 指出每个严重的错误事件将会导致应用程序的退出。
    error 指出虽然发生错误事件,但仍然不影响系统的继续运行。
    warn 表明会出现潜在的错误情形。
    info 一般和在粗粒度级别上,强调应用程序的运行全程。
    debug 一般用于细粒度级别上,对调试应用程序非常有帮助。(默认级别)
    trace 是程序追踪,可以用于输出程序运行中的变量,显示执行的流程。
  还有两个特殊的级别:
    OFF,可用来关闭日志记录。
    ALL,启用所有消息的日志记录。

注:一般只使用 4个级别,优先级从高到低为 ERROR > WARN > INFO > DEBUG

slf4j: 

简单日志门面(Simple Logging Facade For Java) SLF4J主要是为了给Java日志访问提供一套标准、规范的API框架,其主要意义在于提供接口,具体的实现可以交由其他日志框架,例如log4j和logback等。当然slf4j自己也提供了功能较为简单的实现,但是一般很少用到。对于一般的Java项目而言,日志框架会选择slf4j-api作为门面,通过绑定器绑定具体的实现框架(log4j、logback等)进行日志打印,与第三方其它框架统一日志的时候,中间使用桥接器完成桥接。
SLF4J是目前市面上最流行的日志门面。现在的项目中,基本上都是使用SLF4J作为日志系统。
SLF4J日志门面主要提供两大功能:

1. 日志框架的绑定
  2. 日志框架的桥接

入门案例:

1. 添加依赖  

<dependencies>
        <!--slf4j core 使用slf4j必須添加-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.26</version>
        </dependency>
        <!--slf4j 自带的简单日志实现 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.27</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

2. 测试

public class Slf4jTest {

    // 声明日志对象
    public final static Logger LOGGER = 
     LoggerFactory.getLogger("slf4j");

    @Test
    public void test01() {
        //打印日志信息
        LOGGER.info("info");
    }
}

绑定日志的实现(Binding):

SLF4J支持各种日志框架。SLF4J发行版附带了几个称为“SLF4J绑定”的jar文件,每个绑定对应一个受支持的框架。

使用slf4j的日志绑定流程:
    1. 添加slf4j-api的依赖
    2. 使用slf4j的API在项目中进行统一的日志记录
    3. 绑定具体的日志实现框架
      1. 绑定已经实现了slf4j的日志框架,直接添加对应依赖
      2. 绑定没有实现slf4j的日志框架,先添加日志的适配器,再添加实现类的依赖
    4. slf4j有且仅有一个日志实现框架的绑定(如果出现多个默认使用第一个依赖日志实现)

通过maven引入常见的日志实现框架:(根据实际情况选择使用,除了引入下面其中一个,还不能少了 slf4j-api 的引用)

官方绑定器API地址: http://www.slf4j.org/manual.html

1. logback

<!-- logback 日志实现 -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

2. nop

<!-- nop 日志开关(不使用日志功能) -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-nop</artifactId>
    <version>1.7.2</version>
</dependency>

3. log4j

<!-- 绑定 log4j 日志实现,需要导入适配器,还需要添加 log4j.properties 配置文件 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.26</version>
</dependency>
<!-- log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

4. jul

<!-- 绑定 jul 日志实现,需要导入适配器 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jdk14</artifactId>
    <version>1.7.25</version>
</dependency>
<!-- 因为是java原生的日志框架,已经内置了具体实现 -->

原理:

关于log4j、jul、jcl、slf4j等等日志组件的理解

关于log4j、jul、jcl、slf4j等等日志组件的理解

桥接其它框架日志的实现(Bridging):

桥接解决的是项目中日志的遗留问题,当系统中存在之前的日志API,可以通过桥接转换到slf4j的实现

  1. 先去除之前老的日志框架的依赖
    2. 添加SLF4J提供的桥接组件
    3. 为项目添加SLF4J的具体实现

  4. 统一应用和框架的日志实现

迁移的方式:

  如果我们要使用SLF4J的桥接器,替换原有的日志框架,那么我们需要做的第一件事情,就是删除掉原有项目中的日志框架的依赖。然后替换成SLF4J提供的桥接器。

官方api地址: http://www.slf4j.org/legacy.html

原理:

 关于log4j、jul、jcl、slf4j等等日志组件的理解

关于log4j、jul、jcl、slf4j等等日志组件的理解

   1. log4j

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.26</version>
</dependency>
<!-- 配置 log4j 的桥接器 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>1.7.25</version>
</dependency>

2. logback

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.26</version>
</dependency>
<!-- 配置 log4j 的桥接器 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>1.7.25</version>
</dependency>
<!-- logback 日志实现 -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

3. jcl

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.26</version>
</dependency>
<!-- 配置 jcl 的桥接器 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.7.8</version>
</dependency>

4. jul

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.26</version>
</dependency>
<!-- 配置 jul 的桥接器 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jul-to-slf4j</artifactId>
    <version>1.7.25</version>
</dependency>

注:    

  1. jcl-over-slf4j.jar(桥接)和 slf4j-jcl.jar(适配)不能同时部署。前一个jar文件将导致JCL将日志系统的选择委托给SLF4J,后一个jar文件将导致SLF4J将日志系统的选择委托给JCL,从而导致无限循环 。

    2. log4j-over-slf4j.jar和slf4j-log4j12.jar不能同时出现,原因同上

  3 . jul-to-slf4j.jar和slf4j-jdk14.jar不能同时出现,原因同上

    4. 所有的桥接都只对Logger日志记录器对象有效,如果程序中调用了内部的配置类或者是Appender,Filter等对象,将无法产生效果。

相关推荐