原文链接
日志框架发展历程
在了解日志框架时总会列出一系列框架:Log4j,Reload4j,JUL,JCL,SLF4J,Logback,Log4j2,这么多框架让人感到混乱,该怎么选取、该怎么用。接下来,让我们逐步理清这些框架及之间的关系。
首先来了解日志框架的发展历程,就能大致清楚这些框架之间的关联和区别。
-
1996 年,Log4j 开始出现,并成为一个流行的 Java 日志记录包,后来贡献给 Apache 基金会,但在 2015 年宣布不在维护了。
reload4j 是 Apache log4j 版本 1.2.17 的一个分支,旨在解决 log4j 的安全问题。Reload4j 是log4j 版本 1.2.17 的直接替代品,所以想继续使用 log4j 1.x 的框架,推荐使用 slf4j-reload4j 进行替代。
-
2002 年 Java 1.4 发布,同时推出自己的日志库 JUL(Java Util Logging)。Apache 曾建议 sun 公司 将 Log4j 引入到 jdk 中,但被拒绝了,sun 公司仿照 Log4j,实现一套自己的日志实现框架,即 JUL。
-
同时,Apache 推出了 JCL(Jakarta Commons Logging,一个简单的日志门面框架),它提供了一套统一的日志接口,解决 Java 应用程序中使用不同日志框架导致的代码依赖问题,其内部提供了一个 Simple Log 简单日志实现,支持集成使用 Log4j、jdk 1.4(JUL)等具体日志实现。
JCL最初是由Apache软件基金会的Jakarta 项目组开发的,当时它是 Apache Jakarta 项目的一部分。在2011年,Jakarta 项目组重新组织并成为 Apache Commons 项目。因此,JCL 目前被称为 Apache Commons Logging。
-
2006年,log4j 的作者又发布了 SLF4J(Simple Logging Facade for Java,是一个简单的日志门面框架),旨在提供统一的日志API,解决 Java 应用程序中使用不同日志框架导致的代码依赖问题。它比 Apache Commons Logging(JCL)见简单、稳定,支持集成各种日志实现框架(Jul、log4j 1.x、reload4j 和 Logback)。
-
同时,SLF4J 的作者顺带推出了 Logback 日志实现框架。
-
2014年,Apache 发布了 Log4j2,是 log4j 的官方升级版。
综上:
- 日志门面技术(规范):JCL、SLF4J
- 日志实现框架:Log4j 、JUL、Logback、Log4j2。
Log4j
Log4j 介绍
Log4j 有三个主要的组件:日志记录器(Logger),日志输出目标(Appenders)和日志格式化器(Layouts)。
-
日志记录器(Logger):Logger 组件在此系统中被分为五个级别:DEBUG、INFO、WARN、ERROR 和 FATAL。这五个级别是有顺序的,DEBUG < INFO < WARN < ERROR < FATAL,分别用来指定这条日志信息的重要程度,只输出级别不低于设定级别的日志信息,假设 Logger 级别设定为 INFO,则INFO、WlARN、 ERROR 和 FATAL 级别的日志信息都会输出,而级别比 INFO 低的 DEBUG 则不会输出。
-
日志输出目标(Appender):日志输出目标定义了日志消息的输出位置。Log4j 提供了多个内置的输出目标,如控制台、文件、数据库等。开发人员可以根据需要配置一个或多个输出目标来将日志消息输出到不同的位置。
常使用的类如下:
- org.apache.log4j.ConsoleAppender(输出到控制台)
- org.apache.log4j.FileAppender(输出到文件)
- org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
- org.apache.log4j.RollingFileAppender(日志文件到达指定大小的时候产生一个新的日志文件)
- org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
-
日志格式化器(Layout):日志格式化器定义了日志消息的输出格式。Log4j 提供了多个内置的格式化器,如简单文本格式、HTML格式、XML格式、自由指定样式等。开发人员可以根据需要选择适当的格式化器来控制日志消息的输出样式。
常使用的类如下:
- org.apache.log4j.HTMLLayout(以HTML表格形式布局)
- org.apache.log4j.PatternLayout(可以灵活地指定布局模式)
- org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
- org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等信息)
Log4j 配置文件
Log4j 使用一个配置文件来指定日志记录器、输出目标、格式化器等的配置信息。在实际应用中,在 使用 Log4j 之前先设置配置文件。配置文件事实上也就是对 Logger、Appender 及 Layout 进行相应设置。Log4j 支持两种配置文件格式,一种是 XML 格式的文件,一种是 properties 属性文件。下面是以 xml 属性文件的配置示例:
xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">
<!-- 设置日志输出位置 -->
<param name="Target" value="System.out" />
<!-- 设置日志输出格式 -->
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5p %c{1} : %m%n" />
</layout>
</appender>
<!-- 指定包下的日志输出级别 -->
<!-- <logger name="com.jcl.demo">-->
<!-- <level value="error"/>-->
<!-- </logger>-->
<!-- 配置所有包下的日志输出级别, 除了 logger 指定的包>-->
<root>
<priority value="info" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4j:configuration>
Log4j 使用示例
-
引入依赖
xml<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency>
-
按照上面 Log4j 设置配置文件
-
代码示例
javaimport org.apache.log4j.Logger; import org.junit.Test; public class Log4jTest { @Test public void Log4jTest() { Logger log = Logger.getLogger(Log4jTest.class); log.info("info日志打印"); log.error("error日志打印"); } }
JUL(Java Util Logging)
JUL 介绍
JUL 是 Java 1.4 版本自带的日志框架,JUL的核心组件是java.util.logging
包中的类和接口。Logger
是最重要的类,用于创建和管理日志记录器。Handler
用于定义日志消息的输出目的地,如控制台、文件等。Formatter
定义了日志消息的格式。Level
表示日志的级别,JUL定义了七个日志级别,从低到高分别是:ALL、FINEST、FINER、FINE、CONFIG、INFO、WARNING、SEVERE、OFF。
JUL的默认配置是通过配置文件logging.properties
进行的。
JUL 使用示例
-
Java 核心包,所以无需引入其他依赖
-
配置 logging.properties 文件设置日志相关信息,不配置取默认设置。
-
Java 代码示例
javaimport org.junit.Test; import java.util.logging.Logger; public class JulTest { @Test public void testLog(){ Logger log = Logger.getLogger("com.jcl.demo.JulTest"); log.info("info日志打印"); } }
JCL(Jakarta Commons Logging)
JCL 介绍
JCL(Jakarta Commons Logging,一个简单的日志门面技术),它提供了一套统一的日志接口,通过集成不同的日志实现框架来处理日志记录。JCL 是 Apache 中的项目。
前面介绍了 Log4j 和 JUL 日志实现框架,使用两种框架需要分别定义不同框架下的类,随着框架或者业务发展,有时需要使用或替换不同的日志实现框架,这时业务代码中的日志实现是深度耦合的,开发人员修改替换使用的日志类非常麻烦。于是出现了日志门面框架,就是提供一系列通用接口(规范),在业务代码中统一使用日志门面框架提供的接口,日志处理操作交由引入的具体日志实现框架来实现。这就好比 JDBC 数据库驱动,统一调用 JDBC 的接口,具体处理方式由引入的具体驱动包来实现。这样在更换日志实现框架时不需要修改业务代码,解耦特定的日志实现。
JCL 使用示例
-
JCL 是 Apache 中的项目,所以需要引入依赖包
xml<dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency>
-
若没有引入其他日志实现框架,默认使用 Java 1.4 自带的日志框架(JUL),若使用 Log4j 日志实现框架,引入相关依赖,配置 log4j.xml。
-
代码使用示例,可以看到业务代码使用日志门面框架中的接口类,具体日志处理交由对应的日志实现框架处理,这样在更换日志实现框架时,不需要修改业务代码,只需要对相关日志实现框架进行相应配置即可。
javaimport org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.Test; public class JclTest { @Test public void testLog(){ Log log = LogFactory.getLog(JclTest.class); log.info("info日志打印"); log.error("error日志打印"); } }
Logback
logback 使用示例
-
引入依赖,这个包依赖了 slf4j-api,所以是 slf4j + logback 的形式。
xml<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.12</version> </dependency>
-
配置 logback.xml
xml<configuration> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} === %msg%n</pattern> </encoder> </appender> <root level="info"> <appender-ref ref="CONSOLE" /> </root> </configuration>
-
代码使用示例
javaimport org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LogbackTest { @Test public void Log4jTest() { Logger log = LoggerFactory.getLogger(LogbackTest.class); log.info("info日志打印"); log.error("error日志打印"); } }
SLF4J(Simple Logging Facade For Java)
SLF4J 介绍
SLF4J 也是一个日志门面框架,即简单日志门面(Simple Logging Facade For Java),主要是为了提供一套标准、规范的日志接口,具体的实现交由其他日志实现框架。
参考官网,SLF4J 可以集成使用以下不同的日志实现框架:
- slf4j-api.jar 包,这是使用 SLF4J 接口需要使用的 jar 包,只引入该 jar 包,使用时会提示没有提供日志实现,默认会去使用 slf4j-nop 日志实现框架,一种无操作的日志记录机制。
- slf4j-nop.jar 包,这是 SLF4J 的一个日志实现,它实际上是一个空操作的日志记录器。当应用程序使用slf4j-nop作为日志框架时,所有的日志操作都将被忽略,不会有任何实际的日志输出。
- slf4j-simple.jar 包,这是 SLF4J 的一个简单日志实现,它提供了一个轻量级的日志记录器,适用于简单的应用程序和测试环境。
- logback-classic.jar + logback-core.jar 包,logback-core是Logback框架的一个核心模块,作为logback-classic的基础组件之一,它提供了Logback框架的核心功能和基本组件;logback-classic 是 Logback 框架的一个核心模块,它建立在logback-core之上,提供了与log4j兼容的API,并且是log4j的继任者。实际引入 logback-classic 包即可,该包中引入了 logback-core 包。
- reload4j.jar + slf4j-reload4j.jar 包,reload4j 是 log4j 的一个扩展版本,slf4j 需要使用这个三方日志实现框架,需要使用 slf4j-reload4j 适配器(桥接器),即 slf4j ------> slf4j-reload4j ------> reload4j。
- JUL + slf4j-jdk14.jar 包,JUL 是 Java 1.4 自带的的日志实现框架,slf4j 集成这个日志实现框架使用,同样需要引入 slf4j-jdk14 适配器(桥接器),即 slf4j ------> slf4j-jdk14 ------> JUL。
- 深灰色框表示需要引入的 jar 包(如:slf4j-api.jar);
- 浅蓝色框表示slf4j日志门面框架;
- 深蓝色框表示slf4j本地的日志实现框架;
- 绿色框表示需要使用的适配器;
- 浅灰色框表示其他的日志实现框架;
SLF4J 使用示例
-
引入 SLF4J 依赖
xml<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.36</version> </dependency>
-
需要引入日志实现框架依赖包,否则默认使用 slf4j-nop,slf4j 本地的日志实现。
使用 slf4j-nop 日志实现,不输出任何日志,即忽略日志
xml<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-nop</artifactId> <version>1.7.36</version> </dependency>
使用 reload4j 日志实现,需要引入桥接器,配置 log4j.xml
xml<!-- 桥接器 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-reload4j</artifactId> <version>1.7.36</version> </dependency> <!-- reload4j 日志实现框架 --> <dependency> <groupId>ch.qos.reload4j</groupId> <artifactId>reload4j</artifactId> <version>1.2.25</version> </dependency>
使用 jul 日志实现,jul java 自带,不需要引入包,但需要引入桥接器
xml<!-- jul 日志实现需要引入的桥接器 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>1.7.36</version> </dependency>
使用 logback 日志实现,配置 logback.xml
xml<!-- logback 日志实现, slf4j 本地的日志实现, logback-classic 包中包含 logback-core --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.12</version> </dependency>
使用 log4j2 日志实现,配置 log4j2.xml
xml<!-- 使用 Log4j2 日志实现框架 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.17.1</version> </dependency> <!-- 桥接器 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.17.1</version> </dependency>
-
代码使用示例
javaimport org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Slf4jTest { @Test public void Log4jTest() { Logger log = LoggerFactory.getLogger(Slf4jTest.class); log.info("info日志打印"); log.error("error日志打印"); } }
Log4j2
Log4j2 是 Log4j 的升级版。
logback 使用示例
-
引入依赖,这个包依赖了 slf4j-api,所以是 slf4j + logback 的形式。
xml<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.17.1</version> </dependency>
-
配置 logback.xml
xml<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} == %msg%n" /> </Console> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="Console" /> </Root> </Loggers> </Configuration>
-
代码使用示例
javaimport org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.Test; public class Log4j2Test { @Test public void Log4jTest() { Logger log = LogManager.getLogger(Log4j2Test.class); log.info("info日志打印"); log.error("error日志打印"); } }
日志框架梳理(Log4j,Reload4j,
JUL,JCL,SLF4J,Logback,Log4j2)