美文网首页
Java日志体系

Java日志体系

作者: 贪睡的企鹅 | 来源:发表于2019-08-19 17:43 被阅读0次

1 日志系统

在应用程序的开发中,通常会使用日志记录监视代码中变量的变化情况,输出到控制台,文件系统或者网络。记录日志目的在于线上问题追踪,作为其他系统进行统计分析的"数据".

2 Java常用日志框架

Java 的日志框架有很多,比如:JUL(Java Util Logging)、Log4j、Logback、Log4j2、Tinylog 等。除此之外,还有 JCL(Apache Commons Logging)和 SLF4J 这样的“门面日志”

2.1 门面日志

什么是“门面日志”。“门面日志”利用了设计模式中的门面模式思想,对外提供一套通用的日志记录的 API,而不提供具体的日志输出服务,如果要实现日志输出,需要集成其他的日志框架,比如 Log4j、Logback、Log4j2 等。

这种门面模式的好处在于,记录日志的 API 和日志输出的服务分离开,代码里面只需要关注记录日志的 API,通过 SLF4J 指定的接口记录日志;而日志输出通过引入 JAR 包的方式即可指定其他的日志框架。当我们需要改变系统的日志输出服务时,不用修改代码,只需要改变引入日志输出框架 JAR 包。

2.2 日志框架的历史
  • 1996年早期,欧洲安全电子市场项目组决定编写它自己的程序跟踪API(Tracing API)。经过不断的完善,这个API终于成为一个十分受欢迎的Java日志软件包,即Log4j(作者Ceki Gülcü)。后来Log4j成为Apache基金会项目中的一员。
  • 期间Log4j近乎成了Java社区的日志标准。据说Apache基金会还曾经建议Sun引入Log4j到java的标准库中,但Sun拒绝了.
  • 2002年Java1.4发布,Sun推出了自己的日志库JUL(Java Util Logging),其实现基本模仿了Log4j的实现。但是如果有人想换成其他日志组件,如log4j换成JUL,因为api完全不同,就需要改动代码。
  • Apache见此,开发了JCL(Jakarta Commons Logging),即commons-logging-xx.jar。它只提供一套通用的日志接口api,并不提供日志的实现。很好的设计原则嘛,依赖抽象而非实现。这样应用程序可以在运行时选择自己想要的日志实现组件。
  • 这样看上去也挺美好的,但是log4j的作者觉得JCL不好用,自己开发出slf4j,它跟JCL类似,本身不替供日志具体实现,只对外提供接口或门面。目的就是为了替代JCL。同时,还开发出logback,一个比log4j拥有更高性能的组件,目的是为了替代log4j。
  • Apache参考了logback,并做了一系列优化,推出了log4j2

3 commons-logging

3.1 概述

Apache Commons Logging是一个门面日。代码里面只需要关注记录日志的 API,通过JCL指定的接口记录日志;而日志输出通过引入 JAR 包的方式实现。如果没有引入日志框架,Apache Commons Logging会使用内部默认实现 SimpleLog

JUL最后更新于2014年7月,现以停止更新。

image

3.2 包结构

image
  • Log:日志对象接口,封装了操作日志的方法,定义了日志操作的5个级别:trace < debug < info < warn < error
  • LogFactory:抽象类,日志工厂,获取日志类;
  • LogFactoryImpl:LogFactory的实现类,真正获取日志对象的地方;
  • Log4JLogger:对log4j的日志对象封装;
  • Jdk14Logger:对JDK1.4的日志对象封装;
  • Jdk13LumberjackLogger:对JDK1.3以及以前版本的日志对象封装;
  • SimpleLog:commons-logging自带日志对象;

3.2 日志框架加载

jcl可以通过在ClassPath下创建commons-logging.properties配置文件指定加载日志实现框架。

#指定日志对象:
org.apache.commons.logging.Log = org.apache.commons.logging.impl.Jdk14Logger
#指定日志工厂:
org.apache.commons.logging.LogFactory = org.apache.commons.logging.impl.LogFactoryImpl

jcl如果没有指定日志实现框架则默认加载时按照顺序log4j>jul> simpleLog依次加载,如果查找到log4j包则使用log4j,如果没有依次类推。

3.3 JCL使用

引用JCL依赖包

    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.2</version>
    </dependency>

测试代码

此时由于项目也没有放入其他日志框架依赖包,会按照顺序log4j>jul> simpleLog加载,因此此时会使用jdk自带jul实现日志打印。

public class commons_loggingDemo {
    Log log= LogFactory.getLog(commons_loggingDemo.class);
    @Test
    public void test() throws IOException {
        log.debug("Debug info.");
        log.info("Info info");
        log.warn("Warn info");
        log.error("Error info");
        log.fatal("Fatal info");
    }
}

引用log4j依赖包

在不修改代码的前提下,引入log4j依赖包。在次调用测试代码,此时会使用log4j实现日志打印。

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.16</version>
</dependency>

4 SLF4J

4.1 概述

SLF4J同样是一个门面日志。代码里面只需要关注记录日志的 API,通过SLF4J指定的接口记录日志;而日志输出通过引入 JAR 包的方式实现。

image
  • slf4j-api.jar 表示SLF4J提供的日志接口相关的jar包

  • natvie implementation of slf4j-api: 表示SLF4J本地底层日志框架,其中包括logback-classic.jar + logback-core.jar作为logback日志框架底层实现,SLF4J-Simple作为SLF4J简单日志框架实现,slf4j-nop.jar表示空实现。

  • none-natvie implementation of slf4j-api :表示非本地,外部日志框架。其中包括lo4j.jar表示log4j日志框架,JUL表示JDK自带日志框架,log4j-core.jar表示log4j2日志框架(图中没画)

  • Adaptation layer:表示外部日志框架的适配器

组合如下

  • 使用logback作为日志框架
    • slf4j-api.jar + logback-classic.jar + logback-core.jar
  • 使用log4j作为日志框架
    • slf4j-api.jar + slf4j-log4j12.jar + log4j.jar
  • 使用jul作为日志框架
    • slf4j-api.jar + slf4j-jdk14.jar
  • 使用log4j2作为日志框架
    • slf4j-api.jar + +log4j-slf4j-impl+log4j-core
  • 只用slf4j无日志实现
    • slf4j-api.jar + slf4j-nop.jar
4.2 桥接器

在实际开发过程中通常会遇到下面的问题,项目中旧模块使用的是log4j来打印日志的话,而新模块想用logback来统一打印日志的话,由于两者并不兼容,如果直接修改业务代码会存在一定风险。那么该如何解决呢?

SLFJ提供了各种日志框架的桥接器,我们只需要引用对应适配器的实现包,并去掉原始的依赖包,SLFJ会自动帮我们完成日志框架的统一。上面案例中可以去掉log4j包log4j.jar引入log4j-over-slf4j包(这个包使之前代码使用log4j不会因为找不到而报错,并会将打印日志桥接给slf4j-api.jar),并同时引入slf4j-api.jar + logback-classic.jar + logback-core.jar。

image

SLFJ提供的桥接器

image
  • JCL桥接器
    • 使用jcl-over-slf4j.jar
  • log4j桥接器
    • 使用log4j-over-slf4j.jar
  • JUL桥接器
    • 使用jul-to-slf4j.jar
4.3 小结
image
4.4 使用

springBoot默认使用logback作为日志框架,使用slf4j作为门面日志。

使用springBoot+slf4j+logback

<dependencyManagement>
    <dependencies>
      <dependency>
        <!-- Import dependency management from Spring Boot -->
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>1.5.18.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <exclusions>
        <exclusion>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-logging</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
  </dependencies>
springbootSJ4J默认Logback.jpg

这里已经帮助我们添加各种类型日志桥接器,如果我们我们向将原来项目中日志框架去掉,并使用Logback框架时。只需要去掉原先依赖。

使用springBoot+slf4j+log4j

这里需要添加spring-boot-starter-log4j依赖,并将spring-boot-starter-logging从依赖中排除。

<dependencyManagement>
    <dependencies>
      <dependency>
        <!-- Import dependency management from Spring Boot -->
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>1.5.18.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <exclusions>
        <exclusion>
          <artifactId>spring-boot-starter-logging</artifactId>
          <groupId>org.springframework.boot</groupId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-log4j</artifactId>
      <version>1.3.8.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
  </dependencies>
image

同样这里已经帮助我们添加各种类型日志桥接器,如果我们我们向将原来项目中日志框架去掉,并使用logb4j框架时。只需要去掉原先依赖。

使用springBoot+slf4j+log4j2

这里需要添加spring-boot-starter-log4j2依赖,并将spring-boot-starter-logging从依赖中排除。

<dependencyManagement>
    <dependencies>
      <dependency>
        <!-- Import dependency management from Spring Boot -->
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>1.5.18.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <exclusions>
        <exclusion>
          <artifactId>spring-boot-starter-logging</artifactId>
          <groupId>org.springframework.boot</groupId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
  </dependencies>
image

同样这里已经帮助我们添加各种类型日志桥接器,如果我们我们向将原来项目中日志框架去掉,并使用logb4j框架时。只需要去掉原先依赖。

关于其他使用日志框架可以排除spring-boot-starter-logging后自行添加就不再详诉。

测试代码

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

public class Sj4jTest {

    Logger logger = LoggerFactory.getLogger("Sj4jTest");
    
    @Test
    public void test() throws IOException {
        logger.debug("Debug info.");
        logger.info("Info info");
        logger.warn("Warn info");
        logger.error("Error info");
    }
}

相关文章

  • 2018-01-14 Java应用日志

    java日志体系 java日志体系很混乱。在日志实现框架在有log4j,log4j2,java.util.log,...

  • Log

    混乱的 Java 日志体系 正确的打日志姿势

  • 复杂Spring项目中SLF4J最佳使用姿势

    一、Java日志体系概述 图1-1 展示了Java日志体系的三个主要部分: 日志门面接口(SLF4J、JCL) 一...

  • java日志体系

    1、Java 日志体系发展历程 在实际开发过程中,Java的日志框架体系之所以会给编程人员带来一种混乱的感觉,根本...

  • Java日志体系整体梳理

    一、Java日志体系的发展历程 Log4j:在JDK 1.3及以前,Java打日志依赖System.out.pri...

  • java 日志体系

    日志使用最佳实践:slf4j+log4j2添加依赖 配置log4j2.xml — 日志工具会读取名为log4j2....

  • Java日志体系

    对于任何一个编程语言或者框架来说,在编写代码时,日志都是必不可少的内容。日志不仅可以帮助开发者了解系统中出现的问题...

  • Java日志体系

    1 日志系统 在应用程序的开发中,通常会使用日志记录监视代码中变量的变化情况,输出到控制台,文件系统或者网络。记录...

  • java日志体系

    为什么要使用日志 刚开始接触java时都使用过System.out来调试,通过它我们能打印出一些关注的信息到控制台...

  • java日志体系

    JDK Logging由jdk提供的日志打印类:java.util.logging.Logger配置需要启动时指定...

网友评论

      本文标题:Java日志体系

      本文链接:https://www.haomeiwen.com/subject/mtuesctx.html