开发中,日志记录是不可或缺的一部分,应用日志的记录主要用于:记录操作轨迹数据、监控系统运行情况、系统故障定位问题,日志的重要性不言而喻,想要快速定位问题,日志分析是个重要的手段,Java也提供了多种日志框架来进行有效的日志管理。本文将探讨Java常用的日志框架以及使用案例。
一、发展历史
- 1996: Log4j 1.x 由瑞士程序员CeKi Gülcü 发布
- 2002: JDK 1.4 发布,包含 JUL(java.util.logging,位于java.logging模块下),是 JDK 官方自带的日志框架。JUL 性能很差,使用比较少。
- 2002: Apache推出了Jakarta Commons Logging(简称JCL)日志接口
- 2010: Slf4j 发布
- 2009: Logback 发布
- 2014: Log4j2 发布
二、日志框架
现有的一些日志框架:
- 日志实现:JUL(java.util.logging)、logback、log4j、log4j2
- 日志门面:JCL(Jakarta Commons Logging)、Slf4j(Simple Logging Facade for Java)
1.Log4j
官方网站: http://logging.apache.org/log4j/1.2
Log4j 是 Apache 的一个开源项目,创始人 Ceki Gulcu。是 Java 领域资格最老,应用最广的日志工具。Log4j 中有三个主要组件:
- loggers(记录器) - 负责接收并记录日志信息。
- appenders(输出器) - 负责发布日志信息,定义了日志信息的目的地(如控制台、文件、数据库等)。
- layouts(布局) -负责定义日志输出的格式。
这种解耦的设计使得Log4j非常灵活,可以很容易地根据项目的需求进行定制。
1.1 log4j使用:
1).添加maven依赖
<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2).resources目录下创建log4j.properties文件(log4j支持两种配置文件格式:一种是XML格式的文件,一种是properties属性文件)
log4j.rootLogger=INFO,M,C,E
log4j.additivity.monitorLogger=false
# INFO级别文件输出配置
log4j.appender.M=org.apache.log4j.DailyRollingFileAppender
log4j.appender.M.File=/logs/info.log
log4j.appender.M.ImmediateFlush=false
log4j.appender.M.BufferedIO=true
log4j.appender.M.BufferSize=16384
log4j.appender.M.Append=true
log4j.appender.M.Threshold=INFO
log4j.appender.M.DatePattern='.'yyyy-MM-dd
log4j.appender.M.layout=org.apache.log4j.PatternLayout
log4j.appender.M.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} %p %l %m %n
# ERROR级别文件输出配置
log4j.appender.E=org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File=/logs/error.log
log4j.appender.E.ImmediateFlush=true
log4j.appender.E.Append=true
log4j.appender.E.Threshold=ERROR
log4j.appender.E.DatePattern='.'yyyy-MM-dd
log4j.appender.E.layout=org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} %p %l %m %n
# 控制台输出配置
log4j.appender.C=org.apache.log4j.ConsoleAppender
log4j.appender.C.Threshold=INFO
log4j.appender.C.layout=org.apache.log4j.PatternLayout
log4j.appender.C.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %l %m %n
appender配置常使用的类如下:
org.apache.log4j.ConsoleAppender(控制台)
org.apache.log4j.FileAppender(文件)
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
layouts常用配置类:
org.apache.log4j.HTMLLayout(以HTML表格形式布局)
org.apache.log4j.PatternLayout(可以灵活地指定布局模式)
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等信息)
layout格式化打印参数:
* log4j 采用类似 C 语言的 printf 函数的打印格式格式化日志信息,具体的占位符及其含义如下:
%m 输出代码中指定的日志信息
%p 输出优先级,及 DEBUG、INFO 等
%n 换行符(Windows平台的换行符为 "\n",Unix 平台为 "\n")
%r 输出自应用启动到输出该 log 信息耗费的毫秒数
%c 输出打印语句所属的类的全名
%t 输出产生该日志的线程全名
%d 输出服务器当前时间,默认为 ISO8601,也可以指定格式,如:%d{yyyy年MM月dd日
HH:mm:ss}
%l 输出日志时间发生的位置,包括类名、线程、及在代码中的行数。如:
Test.main(Test.java:10)
%F 输出日志消息产生时所在的文件名称
%L 输出代码中的行号
%% 输出一个 "%" 字符
* 可以在 % 与字符之间加上修饰符来控制最小宽度、最大宽度和文本的对其方式。如:
%5c 输出category名称,最小宽度是5,category<5,默认的情况下右对齐
%-5c 输出category名称,最小宽度是5,category<5,"-"号指定左对齐,会有空格
%.5c 输出category名称,最大宽度是5,category>5,就会将左边多出的字符截掉,<5不
会有空格
%20.30c category名称<20补空格,并且右对齐,>30字符,就从左边交远销出的字符截掉
xml文件格式如下:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Appender>
<Filters>
<LevelRangeFilter minLevel="..." maxLevel="..." onMatch="..." onMismatch="..."/>
</Filters>
<PatternLayout pattern="..." charset="..."/>
<Policies>
<CronTriggeringPolicy schedule="..."/>
<SizeBasedTriggeringPolicy size="..."/>
<TimeBasedTriggeringPolicy />
</Policies>
</Appender>
<Appender>
...
</Appender>
</Appenders>
<Loggers>
<Logger>
<AppenderRef ref="...">
</Logger>
<Root>
<AppenderRef ref="...">
</Root>
</Loggers>
</Configuration>
3) log4j日志打印测试
import org.apache.log4j.Logger;
public class Log4jTest {
@Test
public void testLog4j(){
// 1.创建日志记录器对象,使用静态方法创建
Logger logger = Logger.getLogger("com.example.logtest.Log4jTest");
// 记录debug级别的信息
logger.debug("This is debug message.");
// 记录info级别的信息
logger.info("This is info message.");
// 记录error级别的信息
logger.error("This is error message.");
}
}
2.JUL
JUL全称Java util Logging是Java原生的日志框架,使用时不需要另外引用第三方类库,JUL主要用于小型应用程序中,其设计原理基于几个核心组件:
- Logger:记录器,是应用程序访问日志系统的入口点。应用程序通过获取Logger对象,并调用其API来发布日志信息。Logger对象通常与特定的类或代码块相关联,以便能够精确地跟踪和记录日志。
- Handler:也被称为Appenders,每个Logger都会关联一个或多个Handler。Handler负责处理Logger传递过来的日志信息,并将其发送到指定的目的地,如控制台、文件、网络上的其他日志服务或操作系统日志等。Handler的具体实现决定了日志记录的位置和方式。
- Filter:过滤器,用于根据特定条件筛选日志信息。开发者可以根据需要定制哪些信息会被记录,哪些信息会被忽略,从而实现对日志信息的精细控制。
- Level:日志的输出级别。每条日志消息都有一个关联的级别,如DEBUG、INFO、WARN、ERROR等。这些级别粗略地指导了日志消息的重要性和紧迫性。
JUL的配置相对简单,配置文件通常使用.properties或XML格式,虽然是JDK自带的日志库,JUL使用的并不广泛,原因是因为JUL早期存在性能问题,到JDK1.5上才有了不错的进步,但现在和Logback/Log4j2相比还是有所不如
2.1 测试案例
import java.util.logging.Level;
import java.util.logging.Logger;
public class JULTest {
@Test
public void testQuick(){
// 1.创建日志记录器对象,使用静态方法创建
Logger logger = Logger.getLogger("com.example.logtest.JULTest");
// 2.日志记录输出
logger.info("hello JUL");
// 通用方法输出
logger.log(Level.INFO, "info msg");
// 通过占位符输出
logger.log(Level.INFO, "name: {0},age: {1}", new Object[]{"zhangsan",20});
}
}
2.2 日志级别
java.util.logging.Level中定义了7个日志的级别
// 关闭日志记录
public static final Level OFF = new Level("OFF",Integer.MAX_VALUE, defaultBundle);
// 错误--最高的日志级别
public static final Level SEVERE = new Level("SEVERE",1000, defaultBundle);
// 警告
public static final Level WARNING = new Level("WARNING", 900, defaultBundle);
// 消息(默认级别)
public static final Level INFO = new Level("INFO", 800, defaultBundle);
// 配置
public static final Level CONFIG = new Level("CONFIG", 700, defaultBundle);
// 详细信息(少)
public static final Level FINE = new Level("FINE", 500, defaultBundle);
// 详细信息(中)
public static final Level FINER = new Level("FINER", 400, defaultBundle);
// 详细信息(多)-- 最低级的日志级别
public static final Level FINEST = new Level("FINEST", 300, defaultBundle);
// 启用所有消息日志
public static final Level ALL = new Level("ALL", Integer.MIN_VALUE, defaultBundle);
2.3 日志配置
如果我们没有添加配置,JUL默认的配置文件:JAVA_HOME/jre/lib/logging.properties
############################################################
# Default Logging Configuration File
#
# You can use a different file by specifying a filename
# with the java.util.logging.config.file system property.
# For example java -Djava.util.logging.config.file=myfile
############################################################
############################################################
# Global properties
############################################################
# "handlers" specifies a comma separated list of log Handler
# classes. These handlers will be installed during VM startup.
# Note that these classes must be on the system classpath.
# By default we only configure a ConsoleHandler, which will only
# show messages at the INFO and above levels.
## RootLogger使用的处理器
handlers= java.util.logging.ConsoleHandler
# To also add the FileHandler, use the following line instead.
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
# Default global logging level.
# This specifies which kinds of events are logged across
# all loggers. For any given facility this global level
# can be overriden by a facility specific level
# Note that the ConsoleHandler also has a separate level
# setting to limit messages printed to the console.
# RootLogger日志等级
.level= INFO
############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################
## 文件处理器
# default file output is in user's home directory.
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
## 控制台处理器
# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
# Example to customize the SimpleFormatter output format
# to print one-line log message like this:
# <level>: <log message> [<date/time>]
#
# java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n
############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################
# For example, set the com.xyz.foo logger to only log SEVERE
# messages:
com.xyz.foo.level = SEVERE
自定义日志级别及配置
@Test
public void test2() throws IOException {
// 1.获取日志记录器对象
Logger logger = Logger.getLogger("com.example.logtest.JULTest");
// 关闭系统默认配置
logger.setUseParentHandlers(false);
// 一、自定义配置日志级别
// 创建ConsoleHandler 控制台输出
ConsoleHandler consoleHandler = new ConsoleHandler();
// 创建简单格式转换对象
SimpleFormatter simpleFormatter = new SimpleFormatter();
// 进行关联
consoleHandler.setFormatter(simpleFormatter);
logger.addHandler(consoleHandler);
// 配置日志具体级别
logger.setLevel(Level.ALL);
consoleHandler.setLevel(Level.ALL);
// 二、输出到日志文件
FileHandler fileHandler = new FileHandler("d:/jul.log");
// 进行关联
fileHandler.setFormatter(simpleFormatter);
logger.addHandler(fileHandler);
// 日志记录输出
logger.severe("severe");
logger.warning("warning");
logger.info("info"); // 默认日志输出级别
logger.config("config");
logger.fine("fine");
logger.finer("finer");
logger.finest("finest");
}
2.4 日志对象Logger的父子关系
JUL中Logger对象存在父子关系,也就是父亲Logger的设置,同时能够作用于儿子,这种父子关系是通过树状结构包路径进行存储,如下:logger1的日志设置,对logger2也能生效。
@Test
public void test3() throws Exception {
// 日志记录器对象父子关系
Logger logger1 = Logger.getLogger("com.fang");
Logger logger2 = Logger.getLogger("com.fang.log");
System.out.println(logger2.getParent() == logger1);
// 所有日志记录器对象的顶级父元素 class为java.util.logging.LogManager
System.out.println("logger2 parent:" + logger2.getParent() + ",name:" + logger2.getParent().getName());
// 一、自定义日志级别
// a.关闭系统默认配置
logger1.setUseParentHandlers(false);
// b.创建handler对象
ConsoleHandler consoleHandler = new ConsoleHandler();
// c.创建formatter对象
SimpleFormatter simpleFormatter = new SimpleFormatter();
// d.进行关联
consoleHandler.setFormatter(simpleFormatter);
logger1.addHandler(consoleHandler);
// e.设置日志级别
logger1.setLevel(Level.ALL);
consoleHandler.setLevel(Level.ALL);
// 测试日志记录器对象父子关系
logger2.severe("severe");
logger2.warning("warning");
logger2.info("info");
logger2.config("config");
logger2.fine("fine");
logger2.finer("finer");
logger2.finest("finest");
}
测试结果:
true
logger2 parent:java.util.logging.Logger@6ec8211c,name:com.fang
五月 10, 2024 12:09:45 上午 com.example.logtest.JULTest testLogParent
严重: severe
五月 10, 2024 12:09:45 上午 com.example.logtest.JULTest testLogParent
警告: warning
五月 10, 2024 12:09:45 上午 com.example.logtest.JULTest testLogParent
信息: info
五月 10, 2024 12:09:45 上午 com.example.logtest.JULTest testLogParent
配置: config
五月 10, 2024 12:09:45 上午 com.example.logtest.JULTest testLogParent
详细: fine
五月 10, 2024 12:09:45 上午 com.example.logtest.JULTest testLogParent
较详细: finer
五月 10, 2024 12:09:45 上午 com.example.logtest.JULTest testLogParent
非常详细: finest
3.Slf4j
Slf4J(Simple Logging Facade for Java)是一个用于Java的简单日志门面(Facade)主要是为了给Java日志访问提供一套标准、规范的API框架,它本身并不提供具体的日志实现,具体的实现可以交由其他日志框架,例如 log4j 、 logback、java.util.logging等。当然 Slf4J 自己也提供了功能较为简单的实现 slf4j-simple,但是一般很少用到。SLF4J 的作者就是 log4j 的作者 Ceki Gülcü,他宣称 SLF4J 比 log4j 更有效率,而且比 Apache Commons Logging (JCL) 简单、稳定。
官网:https://www.slf4j.org
3.1 Slf4j的官网架构图
上面架构图中可以看到,第一层是应用层,第二层即为slf4j提供的抽象接口:slf4j-api.jar,第三层的话蓝色的(2列5列6列)是日志的实现,而且是直接实现slf4j-api.jar相关接口,湖蓝色(3列4列)是适配层,与上面的slf4j-api接口以及第4层具体日志框架(log4j、jul)的适配。从上图也可以看到logback是直接实现了slf4j的接口的,而log4j在被slf4j调用的时候需要一个适配层。
reload4j:reload4j是Apache log4j版本1.x的一个分支,由于log4j存在一些安全漏洞,Apache社区和其他开发者开始寻求解决方案,reload4j就是其中之一。通过使用slf4j-reload4j,开发者可以在不修改太多代码的情况下,将他们的应用程序从log4j 1.x迁移到reload4j,从而提高应用程序的安全性和稳定性。
slf4j的主要搭配如下:
- Slf4j+logback slf4j-api.jar+logback-classic.jar+logback-core.jar
- Slf4j+log4j slf4j-api.jar+slf4j-log4j12.jar+log4j.jar
- Slf4j+jul slf4j-api.jar+slf4j-jdk14.jar
- Slf4j无日志实现 slf4j-api.jar+slf4j-nop.jar
官网第二张图(桥接策略)
可以看到,上面含义是如果我们已经使用了其他日志框架的api,想转到另一种日志框架api,该如何使用桥接的jar包,如从logback到log4j,JUL到log4j等,本质是通过将一种框架日志交给slf4j,slf4j再通过桥接包到转给另一种框架日志输出,总的来说为以下情况:
- 在使用JCL,则可以通过:jcl-over-slf4j.jar
- 在使用log4j,则可以通过:log4j-over-slf4j.jar
- 在使用JUL,则可通过jul-to-slf4j.jar
注意: 虽然使用 log4j-over-slf4j 可以实现 Log4j 桥接到 SLF4J,也可以使用 slf4j-log4j12 实现 SLF4J 适配到 Log4j,但是它不能同时使用它们,否则就会产生死循环。jcl 和 jul 也是同样的道理,jcl-over-slf4j.jar和slf4j-jcl.jar不能同时出现,jul-over-slf4j.jar和slf4j-log4j12.jar不能同时出现。
4.Logback
官网:https://logback.qos.ch/
Logback是由Ceki Gülcü(同时也是SLF4J的作者)创建的新一代日志框架,旨在解决Log4J的部分性能瓶颈和设计局限。Logback不仅实现了SLF4J API,还具有高度优化的性能、丰富的配置选项和强大的扩展能力。SpringBoot底层也是使用slf4j+logback的方式进行日志记录。
Logback主要分为三个模块:
- logback-core :其它两个模块的基础模块
- logback-classic :它是log4j的一个改良版本,同时它完整实现了slf4j API
- logback-access :访问模块与Servlet容器集成提供通过Http来访问日志的功能
4.1 Logback 使用示例
1)添加依赖
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
实际开发中我们可以直接引入spring-boot-starter-web
依赖,因为spring-boot-starter-web
包含了spring-boot-starter 而spring-boot-starter包含了spring-boot-starter-logging
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
2)配置文件
logback会依次读取以下类型配置文件:
- logback.groovy
- logback-test.xml
- logback.xml
如果均不存在会采用默认配置
logback-spring.yml
<?xml version="1.0" encoding="utf-8"?>
<!--配置文件说明:
共有一个父标签、两种属性、三个节点:
1.一个父标签:configuration
2. 两种属性:contextName和property
3. 三个节点:appender、root、logger
主要就是appender追加到哪里:控制台/文件,然后采用哪种pattern(在property定义了pattern格式)
然后就是logger和root配置,指定日志输出级别,以及引用哪种appender
-->
<configuration>
<!--根节点<configuration>包含的属性:
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<contextName>logback-spring-demo-dev</contextName>
<property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg %n"/>
<property name="pattern-color"
value="%yellow(%d{yyyy-MM-dd HH:mm:ss.SSS}) [%thread] %highlight(%-5level) %green(%logger{50}) - %highlight(%msg) %n"/>
<!--文件路径输出说明,会自动生成文件夹及log文件,但是由于我这个是多模块,默认生成在父目录下的logs文件夹下面,所以要在子模块下生成要再加一个路径-->
<property name="LOG_HOME" value="./springboot_log/logs"/>
<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--ThresholdFilter为系统定义的拦截器,例如我们用ThresholdFilter来过滤掉ERROR级别以下的日志不输出到文件中。如果不用记得注释掉,不然你控制台会发现没日志~-->
<!--<filter class="ch.qos.logback.classic.filter.ThresholdFilter">-->
<!--<level>ERROR</level>-->
<!--</filter>-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern}</pattern>
</encoder>
</appender>
<!-- 控制台输出-带颜色 -->
<appender name="CONSOLE-WITH-COLOR" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${pattern-color}</pattern>
</encoder>
</appender>
<!-- 文件输出 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/%d.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${pattern}</pattern>
</encoder>
</appender>
<!--相当于全局的配置-->
<root level="INFO">
<appender-ref ref="CONSOLE-WITH-COLOR"/>
<appender-ref ref="FILE"/>
</root>
<!--1. root和logger是父子的关系。
Logger的appender根据参数additivity决定是否要叠加root的appender,logger的级别是其自身定义的级别,和root的级别没什么关系。
2. logger对单个包或类添加配置,相当于局部配置,root相当于全局配置
如果logger里面配置了additivity="false",就会覆盖root的,只打印一遍;
但是additivity="true",就会向上层再次传递,不会覆盖,而是打印两遍!
-->
<!--相当于局部配置:
配置特定类/包使用不同的日志输出器appender:TestControoler2的会输出两遍,additivity="true"-->
<logger name="com.apple.controller.TestController2" level="INFO" additivity="true">
<appender-ref ref="CONSOLE"/>
</logger>
</configuration>
3)测试
@Slf4j
@RestController
public class TestController {
@RequestMapping("/index")
public String index(){
log.info("==========hello logback=============");
return "hello logback";
}
}
5.JCL(Jakarta Commons Logging)
官网:https://commons.apache.org/proper/commons-logging/
JCL是Apache基金会所属的项目,是一套Java日志接口,之前叫Jakarta Commons Logging,后更名为Commons Logging, 它本身并不提供日志的具体实现,(当然,commons-logging内部有一个SimpleLog但是功能非常常弱 ,所以一般不会单独使用它),而是在运行时绑定具体的日志组件来工作(如Log4j、JUL )。
JCL两个基本抽象类:
- Log:日志记录器
- LogFactory:日志工厂(负责创建Log实例)
5.1 JCL例子
maven依赖:
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
测试
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class JCLTest {
@Test
public void testJCL(){
// 创建日志对象
Log log = LogFactory.getLog(JCLTest.class);
// 记录debug级别的信息
log.debug("This is debug message.");
// 记录info级别的信息
log.info("This is info message.");
// 记录error级别的信息
log.error("This is error message.");
}
}
6.log4j2
官网:https://logging.apache.org/log4j/2.x/
Apache Log4J曾一度是Java世界中最流行的日志框架之一,以其灵活性和模块化设计著称。然而,随着时间推移,原版Log4J暴露出了一些性能和功能上的短板。于是,Apache基金会推出了Log4J2,这是一个经过彻底重构并优化的新版本,引入了许多新特性,主要有:
- 异常处理,在 logback中,Appender中的异常不会被应用感知到,但是在log4j2中,提供了一些异 常处理机制。
- 性能提升, log4j2相较于log4j 和logback都具有很明显的性能提升,后面会有官方测试的数据。
- 自动重载配置,参考了 logback的设计,当然会提供自动刷新参数配置,最实用的就是我们在生产 上可以动态的修改日志的级别而不需要重启应用。
- 无垃圾机制, log4j2在大部分情况下,都可以使用其设计的一套无垃圾机制,避免频繁的日志收集导致的jvm gc
6.1案例实现:
1)引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>2.6.13</version>
</dependency>
2) log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" monitorInterval="5">
<properties>
<property name="LOG_HOME">D:/logs</property>
</properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] [%-5level] %c{36}:%L --- %m%n" />
</Console>
<File name="file" fileName="${LOG_HOME}/myfile.log">
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l%c{36} - %m%n" />
</File>
<RandomAccessFile name="accessFile" fileName="${LOG_HOME}/myAcclog.log">
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l%c{36} - %m%n" />
</RandomAccessFile>
<RollingFile name="rollingFile" fileName="${LOG_HOME}/myrollog.log"
filePattern="D:/logs/$${date:yyyy-MM-dd}/myrollog-%d{yyyyMM-dd-HH-mm}-%i.log">
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l%c{36} - %msg%n" />
<Policies>
<OnStartupTriggeringPolicy />
<SizeBasedTriggeringPolicy size="10 MB" />
<TimeBasedTriggeringPolicy />
</Policies>
<DefaultRolloverStrategy max="30" />
</RollingFile>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
3)JAVA代码测试
import org.slf4j.LoggerFactory;
public class LogTest {
static org.slf4j.Logger logger = LoggerFactory.getLogger(LogTest.class);
public static void main(String[] args) {
logger.trace("trace level");
logger.debug("debug level");
logger.info("info level");
logger.warn("warn level");
logger.error("error level");
}
}
参考:
- http://t.csdnimg.cn/lW60J
- https://time.geekbang.org/column/article/220307
- https://www.cnblogs.com/cxyyh/p/10633581.html