Log4j2的使用
概述
Apache Log4j 2是对Log4j的升级版,参考了logback的一些优秀的设计,并且修复了一些问题,因此带来了一些重大的提升,主要有:
- 异常处理,在logback中,Appender中的异常不会被应用感知到,但是在log4j2中,提供了一些异常处理机制。
- 性能提升, log4j2相较于log4j 和logback都具有很明显的性能提升,后面会有官方测试的数据。
- 自动重载配置,参考了logback的设计,当然会提供自动刷新参数配置,最实用的就是我们在生产上可以动态的修改日志的级别而不需要重启应用。
- 无垃圾机制,log4j2在大部分情况下,都可以使用其设计的一套无垃圾机制,避免频繁的日志收集导致的jvm gc。
官网https://logging.apache.org/log4j/2.x/
使用
- 导入依赖
<!-- Log4j2 门面API-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.1</version>
</dependency>
<!-- Log4j2 日志实现 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
</dependency>
</dependencies>
- Java 代码
首先是获取Logger对象
private static Logger logger = LogManager.getLogger(xxx.class);
接下来直接使用即可,来演示一下没有配置文件的硬编码程序
Logger logger = LogManager.getLogger(testLog4j2.class);
logger.trace("我是TRACE级别的日志");
logger.debug("我是DEBUG级别的日志");
logger.info("我是INFO级别的日志");
logger.warn("我是WARN级别的日志");
logger.error("我是ERROR级别的日志");
logger.fatal("我是FATAL级别的日志");
这样运行之后,会看到只有error和fatal的日志信息输出出来了,Log4j2默认的日志级别是ERROR(因为缺省配置文件的优先级默认为Error)
日志级别
在Log4j2中,定义了6个日志级别
级别有小到大排序为:trace<debug<info<warn<error<fatal
- trace: 程序追踪级别,一般不用
- debug: 调试的日志信息,一般作为最低级别的日志信息使用
- info: 输出一下你感兴趣的或者重要的信息,这个用的最多了。
- warn: 警告日志信息,警告不是错误,程序依然能正常运行。
- error: 错误信息,程序仍然会继续运行
- fatal: 级别最高的日志信息,这种级别的日志应当终止停止程序了
日志级别只起信息一个标识作用,真正的处理需要视情况而定。
配置文件
log4j2的配置文件名称是log4j2.xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration status="warn" monitorInterval="5">
<!--定义Log4j2的组件-->
<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="D:/LOGS/myfile.log">
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n"/>
</File>
<!-- 定义一个文件输出日志组件-->
<RandomAccessFile name="accessFile" fileName="D:/LOGS/myAcclog.log">
<PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %l %c{36} - %m%n"/>
</RandomAccessFile>
<!-- 定义一个可滚动的文件输出日志组件-->
<RollingFile name="rollingFile" fileName="D:/LOGS/myrollog.log"
filePattern="D:/LOGS/$${date:yyyy-MM-dd}/myrollog-%d{yyyy-MM-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>
<!-- 设置日志级别是TRACE,等于以及高于此级别的日志才会输出-->
<Root level="trace">
<AppenderRef ref="Console"/>
<AppenderRef ref="file"/>
<AppenderRef ref="accessFile"/>
<AppenderRef ref="rollingFile"/>
</Root>
</Loggers>
</configuration>
导入配置文件后,再运行上面的测试程序,会看到控制台输出
还可以看到文件日志
配置文件详解
参考文章:https://juejin.cn/post/6972538940855173151
Log4j 2.x版本不再支持像1.x中的.properties后缀的文件配置方式,2.x版本配置文件后缀名只能为".xml",“.json"或者”.jsn"。
常用的是XML格式的配置文件。
我们在日常开发中,使用XML类型的配置文件,注意log4j2的配置文件名必须是log4j2.xml
<configuration>
根标签,有两个属性,有两个子节点<Appenders>
和<Loggers>
- status,用来指定log4j本身的打印日志的级别,不是我们自定义的程序中的日志级别,是log4j本身日志的级别。
- monitorInterval,用于指定log4j自动重新配置的检测间隔时间,单位是s,最小是5s。每隔几秒去检测配置文件是否更改,如果更改了就自动重新配置
<Appenders>
这个标签下放的都是日志组件,常见的有三种子节点
<Console>
- 用来定义日志输出到控制台的组件标签
- name属性,用来指定标签的名称,方便后面引用
- target属性,用来指定控制台输出的方式,
- SYSTEM_OUT是控制台常规输出
- SYSTEM_ERR是控制台输出报错信息的一种方式,信息显示为红色
- 子节点
<PatternLayout>
设置日志信息的输出格式,此标签中使用pattern属性来设置日志的打印格式,需要按照格式化符的规范。关于格式化符,可以看这篇文章https://blog.csdn.net/snail_bi/article/details/103496697
<File>
- 此标签是用来定义日志文件输出的组件标签
- name属性
- fileName属性,设置日志文件的名称(日志文件的路径)
- 子节点
<PatternLayout>
设置日志信息格式的标签,使用此标签中的pattern属性来格式化,按照格式化符的规范
<RollingFile>
- 此标签用来定义滚动日志文件的标签,当日志文件超出某个规则后会自动创建新的日志文件,常用来限制日志文件的大小,当日志文件达到或超过某个大小,自动创建新的日志文件
- name属性
- fileName属性:用来指定日志文件名称(带路径名称)
- filePattern属性:新建的日志文件的名称(带路径名称)
- 子节点**
<PatternLayout>
标签**,设置日志信息的格式化 - 子节点**
<Policies>
**,滚动日志的策略,当达到什么条件时新建日志文件<Policies>
子节点<TimeBasedTriggeringPolicy>
标签,基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1h,modulate=true用来调整时间<Policies>
子节点<SizeBasedTriggeringPolicy>
,基于指定文件大小的滚动策略,size属性用来定义每个日志文件的大小<Policies>
子节点<OnStartupTriggeringPolicy>
,每次重新启动时触发滚转,但仅当文件大小大于零时才触发。
- 子节点
<DefaultRolloverStrategy>
,用来指定同一个文件夹下最多有几个日志文件时开始删除最旧的,创建新的(通过max属性) - 子节点
<ThresholdFilter>
标签:level属性表示匹配的日志级别,onMatch属性表示匹配设定的日志级别后是DENY还是ACCEPT,onMismatch属性表示不匹配设定的日志级别是DENY还是ACCEPT还是NEUTRAL。DENY时就会不记录此日志,ACCEPT表示记录此日志,NEUTRAL表示中立。
<Loggers>
常见的子节点有两种:<Root>
和<Logger>
.
<Root>
<Root>
节点用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出
- level属性:设置项目的日志输出级别,共有8个级别,按照从低到高为:Trace < Debug < Info < Warn < Error < Fatal,ALL表示输出所有级别的日志信息都输出,OFF表示关闭项目日志输出功能。
<Logger>
Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。
- level属性:日志输出级别,共有8个级别,按照从低到高为:Trace < Debug < Info < Warn < Error < Fatal,ALL表示输出所有级别的日志信息都输出,OFF表示关闭项目日志输出功能。
- name:用来指定该Logger所适用的类或者类所在的包全路径,继承自Root节点.
<AppenderRef>
- AppenderRef节点:Root或Logger的子节点,用来指定该日志输出引用哪一个自定义的Appender组件,如果没有指定,就会默认继承自Root。
优化
实际开发中,通常会使用 slf4j + log4j2 进行日志管理;
此时就需要导入slf4j 日志门面、log4j2 适配器、log4j,然后使用 slf4j 方法接口名称来输出日志
<!-- Log4j2 门面API-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.1</version>
</dependency>
<!-- Log4j2 日志实现 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
</dependency>
<!-- 使用slf4j 作为日志门面 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<!-- 使用 log4j2 的适配器进行绑定 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
接下来的SLF4j是一个面向接口的框架,接下来我们在使用时,直接使用SLF4j的接口规范来调用,log4j2是真正底层的实现。
获取Logger对象,使用SLF4j中的工厂
private static final Logger LOGGER = LoggerFactory.getLogger(testSlf4Log4j2.class);
配置文件不用改,仍然是log4j2的配置文件
private static final Logger LOGGER = LoggerFactory.getLogger(testSlf4Log4j2.class);
@Test
public void test(){
// 接下来正常使用即可
LOGGER.trace("我是一条TRACE级别的日志信息");
LOGGER.debug("我是一条DEBUG级别的日志信息");
LOGGER.info("我是一条INFO级别的日志信息");
LOGGER.warn("我是一条WARN级别的日志信息");
LOGGER.error("我是一条ERROR级别的日志信息");
}
注意:引入了SLF4J门面后,所有的规范都是按照SLF4J来的,log4j2才是真正的实现,但是在调用时需要按照SLF4J的规范中的方法来调用,在SLF4J中,日志级别是5个,取消了log4j2中的FATAL级别