文章目录
Log4j2 轻松入门
Log4j2 简介
Log4j2是Apache基金会主持开发的Java日志框架,它的前身是Log4j 1.x(一般就被简单的称为Log4j)。1.x版本在2015年被Apache废弃,已经停止开发维护,现在正在开发的是2.x版本,即Log4j2。
Log4j2 架构概览
Log4j2的实际架构较为复杂,而本文的目的是帮助读者入门和快速上手,所以不会深入探究它的底层架构,而是简单的做一个说明。
可以将Log4j2的底层架构简化为:Logger, LoggerManager, Appender, Layout四个部分。
Logger 是日志记录器,我们调用Logger的info(), warn(), error() 等方法来实现日志的记录
LoggerManager 是Logger的管理者,我们通过LoggerManager来获取Logger
Appender 指定了日志的输出位置,如控制台、文件等
Layout 指定了日志的输出格式,如时间日期的显示方式等
他们的关系如图:
当我们需要输出一条日志时,首先通过LoggerManager获取Logger对象,调用Logger对象的info(), warn(), error()等方法来输出日志,输出的位置由与Logger关联的Appdender对象决定(一个Logger可以关联多个Appdender对象),输出的格式由与Appender关联的Layout对象决定(一个Appender只能关联一个Layout对象)。
Log4j2的具体使用
要在项目中使用Log4j2只需要三步:
1. 引入Log4j2的Jar库:log4j-api.jar和log4j-core.jar
可以手动添加,也可以使用Maven,Graddle等工具
下面是使用Maven时需要加入的dependency:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.0</version>
</dependency>
手动下载jar包的位置为:http://mirror.bit.edu.cn/apache/logging/log4j/2.13.0/apache-log4j-2.13.0-bin.zip
2. 创建配置文件
Logger, Appender, Layout对象都在配置文件中被配置。配置文件的格式可以是.xml, .yml 或 .properties,配置文件的名字必须是log4j2(即log4j2.xml或log4j2.yml等等),配置文件需要放在JVM的classpath下(不太清楚classpath的可以看一下这篇文章:https://www.liaoxuefeng.com/wiki/1252599548343744/1260466914339296),在IDEA中,将配置文件放在resources目录下即可:
下面我们以.xml格式的配置文件为例,结合上文中说到的Log4j2的架构,学习如何看懂和编写Log4j2的配置文件。
首先看一下一个简单的log4j2.xml全文:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="LogToConsole" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<File name="LogToFile" fileName="log/test.log">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</File>
</Appenders>
<Loggers>
<Logger name="com.fforkboat" level="error">
<AppenderRef ref="LogToConsole"/>
</Logger>
<Logger name="com.fforkboat.Test" level="debug" additivity="false">
<AppenderRef ref="LogToConsole"/>
<AppenderRef ref="LogToFile"/>
</Logger>
<Root level="error">
<AppenderRef ref="LogToConsole"/>
</Root>
</Loggers>
</Configuration>
可以看到这个xml文件在根元素Configuration中定义了两个子元素,Appenders和Loggers,分别代表Appender和Logger的集合。
首先看到Appenders,我们在其中定义了两个子元素Console和File。Console代表了输出位置是控制台的Appender, 我们将其命名为LogToConsole,并且指定了具体输出位置是标准输出SYSTEM_OUT(还可以是标准错误输出SYSTEM_ERR);File代表了输出位置是文件的Appender,我们将其命名为LogToFile, 并且指定了具体输出位置是log/test.log。在每个Appender内部,我们还定义了PatternLayout子元素,它指定了输出格式,%d代表时间,%msg表示具体的日志内容,%n表示换行,具体的格式说明请看此处:http://logging.apache.org/log4j/2.x/manual/layouts.html。
接下来我们看到Loggers,我们在其中定义了三个子元素:两个Logger和一个Root,这些子元素就是我们将要通过LoggerManger获取的Logger对象,我们需要为每个Logger指定名字(name),日志级别(level),唯一的例外是根记录器Root,它不需要名字。我们通过Logger的子元素AppenderRef来定义与Logger关联的Appender。
Log4j2一共有八个日志级别,下图是这八个日志级别以及他们对应的权重,可以发现,日志的严重级别越高,它的权值越低(除了OFF)。想要让一条日志被输出,要保证该日志事件的权值小于等于Logger配置中指定级别的权值。比如,如果Logger的level被配置为warn,那么只有warn, error, fatal级别的日志事件会被输出;当Logger的level被配置为off,所有的日志事件都不会被输出:
另外值得一说的是第二个Logger有一个additivity属性, 并被设定为false,这代表什么意思呢?首先,我们可以先关注一下Logger的名字,我们可以发现Logger的名字和Java的包名、类名很像,都是点分的多级格式。实际上,他们不光在格式上相似,他们还具有相似的层级关系,即com是com.fforkboat的上级,com.fforkboat是com.fforkboat.Test的上级。那么Logger的层级关系有什么用呢?这就要说到Log4j2在日志记录时的往上级抛规则,即如果我通过com.fforkboat.Test这个Logger做出了一条日志记录,那么名为com.fforkboat、名为com的Logger以及root Logger都会再次做出记录。而且向上级抛时不考虑Logger的level属性,只要Logger存在上级,就往上抛,直到抛到Root Logger,即使上级Logger的level比下级Logger的level的严重级别更高,这条日志也会被抛上去。有时候我们不希望这种“往上级抛”的行为,就可以通过指定additivity="false"来阻止。现在来举两个例子帮助理解:
- 三个Logger,名字分别为root,com,com.fforkboat,日志级别分别为error,warn,info,三个Logger的Appender都为控制台,并且三个Logger都没有指定additivity=“false”。那么当我们使用名为com.fforkboat的Logger记录info级别的日志时,控制台总共会输出三条一模一样的记录,分别由以上三个Logger产生。
- 条件和上述相同,除了com.fforkboat这个Logger指定了additivity=“false”。那么控制台只会输出一条记录,由com.fforkboat这个Logger产生。
3. 在Java代码中获取Logger,并通过该Logger做出日志记录。
先放代码:
package com.fforkboat;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test {
private static final Logger logger = LogManager.getLogger("com.fforkboat.Test");
public static void main( String[] args ) {
logger.debug("Hello from Log4j 2");
}
}
简单解释:
通过LogManager的getLogger方法拿到Logger对象,Logger对象在上文中的配置文件中被定义。getLogger()方法的参数是Logger的名字,Log4j2会从配置文件中寻找该名字的Logger,如果找不到完全匹配的,就会寻找该Logger的上级,如果还是找不到,就再上一级,直到root logger, Logger的上下级关系在上文中有介绍。举个例子,当参数为"com.fforkboat.Test"时,Log4j2首先会去寻找名为com.fforkboat.Test的Logger,如果这个Logger没有被定义,就去寻找名为com.fforkboat的Logger,如果还是没有被定义,就去寻找名为com的Logger,如果仍然没有,就返回root logger。另外要说明一点,即使没有在配置文件中显示地定义root logger,root logger仍然会被创建,在这种情况下,它的level默认为error, appender默认为控制台。
参考文献
https://www.journaldev.com/7128/log4j2-example-tutorial-configuration-levels-appenders
如果有帮助麻烦点个赞呀 ORZ