在了解日志框架时总会列出一系列框架: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 的官方升级版。
综上:
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 提供了多个内置的输出目标,如控制台、文件、数据库等。开发人员可以根据需要配置一个或多个输出目标来将日志消息输出到不同的位置。
常使用的类如下:
日志格式化器(Layout):日志格式化器定义了日志消息的输出格式。Log4j 提供了多个内置的格式化器,如简单文本格式、HTML格式、XML格式、自由指定样式等。开发人员可以根据需要选择适当的格式化器来控制日志消息的输出样式。
常使用的类如下:
Log4j 配置文件
Log4j 使用一个配置文件来指定日志记录器、输出目标、格式化器等的配置信息。在实际应用中,在 使用 Log4j 之前先设置配置文件。配置文件事实上也就是对 Logger、Appender 及 Layout 进行相应设置。Log4j 支持两种配置文件格式,一种是 XML 格式的文件,一种是 properties 属性文件。下面是以 xml 属性文件的配置示例:
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>
<root>
<priority value="info" />
<appender-ref ref="ConsoleAppender" />
root>
log4j:configuration>
Log4j 使用示例
引入依赖
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.12version>
dependency>
按照上面 Log4j 设置配置文件
代码示例
import 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 介绍
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 代码示例
import 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 介绍
JCL(Jakarta Commons Logging,一个简单的日志门面技术),它提供了一套统一的日志接口,通过集成不同的日志实现框架来处理日志记录。JCL 是 Apache 中的项目。
前面介绍了 Log4j 和 JUL 日志实现框架,使用两种框架需要分别定义不同框架下的类,随着框架或者业务发展,有时需要使用或替换不同的日志实现框架,这时业务代码中的日志实现是深度耦合的,开发人员修改替换使用的日志类非常麻烦。于是出现了日志门面框架,就是提供一系列通用接口(规范),在业务代码中统一使用日志门面框架提供的接口,日志处理操作交由引入的具体日志实现框架来实现。这就好比 JDBC 数据库驱动,统一调用 JDBC 的接口,具体处理方式由引入的具体驱动包来实现。这样在更换日志实现框架时不需要修改业务代码,解耦特定的日志实现。
JCL 使用示例
JCL 是 Apache 中的项目,所以需要引入依赖包
<dependency>
<groupId>commons-logginggroupId>
<artifactId>commons-loggingartifactId>
<version>1.2version>
dependency>
若没有引入其他日志实现框架,默认使用 Java 1.4 自带的日志框架(JUL),若使用 Log4j 日志实现框架,引入相关依赖,配置 log4j.xml。
代码使用示例,可以看到业务代码使用日志门面框架中的接口类,具体日志处理交由对应的日志实现框架处理,这样在更换日志实现框架时,不需要修改业务代码,只需要对相关日志实现框架进行相应配置即可。
import 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 使用示例
引入依赖,这个包依赖了 slf4j-api,所以是 slf4j + logback 的形式。
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.12version>
dependency>
配置 logback.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%npattern>
encoder>
appender>
<root level="info">
<appender-ref ref="CONSOLE" />
root>
configuration>
代码使用示例
import 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 介绍
SLF4J 也是一个日志门面框架,即简单日志门面(Simple Logging Facade For Java),主要是为了提供一套标准、规范的日志接口,具体的实现交由其他日志实现框架。
参考官网,SLF4J 可以集成使用以下不同的日志实现框架:
SLF4J 使用示例
引入 SLF4J 依赖
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.36version>
dependency>
需要引入日志实现框架依赖包,否则默认使用 slf4j-nop,slf4j 本地的日志实现。
使用 slf4j-nop 日志实现,不输出任何日志,即忽略日志
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-nopartifactId>
<version>1.7.36version>
dependency>
使用 reload4j 日志实现,需要引入桥接器,配置 log4j.xml
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-reload4jartifactId>
<version>1.7.36version>
dependency>
<dependency>
<groupId>ch.qos.reload4jgroupId>
<artifactId>reload4jartifactId>
<version>1.2.25version>
dependency>
使用 jul 日志实现,jul java 自带,不需要引入包,但需要引入桥接器
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-jdk14artifactId>
<version>1.7.36version>
dependency>
使用 logback 日志实现,配置 logback.xml
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.12version>
dependency>
使用 log4j2 日志实现,配置 log4j2.xml
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-coreartifactId>
<version>2.17.1version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-slf4j-implartifactId>
<version>2.17.1version>
dependency>
代码使用示例
import 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 是 Log4j 的升级版。
logback 使用示例
引入依赖,这个包依赖了 slf4j-api,所以是 slf4j + logback 的形式。
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-coreartifactId>
<version>2.17.1version>
dependency>
配置 logback.xml
<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>
代码使用示例
import 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)