log4j2日志使用
1、log4j2介绍
Apache Log4j2是对Log4j的升级版,
log4j2借鉴了logback的一些优秀的设计,并且修复了一些问题,因此带来了一些重大的提升,主要有:
1、异常处理:在logback中,Appender中的异常不会被应用感知到,但是在log4j2中,提供了一些异常处理机制。
2、性能提升:log4j2相较于log4j 1和logback都具有很明显的性能提升,在异步配置下是logback的10倍左右。
3、自动重载配置:参考了logback的设计,提供自动刷新参数配置,可以动态的修改日志的级别而不需要重启应用。
4、无垃圾机制,log4j2在大部分情况下,都可以使用其设计的一套无垃圾机制,避免频繁的日志收集导致的jvm gc。
详情可参考其官方文档:http://logging.apache.org/log4j/2.x/manual/configuration.html
log4j2既可以作为日志实现,也可以作为日志门面来使用,不过在日常开发中,习惯于将log4j2作为日志实现,slf4j作为日志门面来结合使用。
2、实践
2.1 pom依赖
-
若为本地maven工程的测试:
在2.9之后,新增了对进程号的显示格式:
%processId
log4j2作为日志门面和 实现****所需导入如下依赖:
<dependencies> <!--log4j依赖:api和core--> <!--log4j日志门面--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.13.3</version> </dependency> <!--log4j日志实现--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.13.3</version> </dependency> </dependencies>
slf4j作为日志门面,log4j2作为日志实现所需导入依赖:
<dependencies> <!--使用slf4j作为日志门面--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.28</version> </dependency> <!--使用log4j的适配器进行绑定--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.9.1</version> </dependency> <!--log4j日志实现--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.13.3 </version> </dependency> </dependencies>
-
若为Springboot工程,则需要引用如下依赖:
如项目中有导入spring-boot-starter-web依赖包, 记得去掉spring自带的日志依赖spring-boot-starter-logging,如下:
<dependencies> <!--springboot工程需要使用的log4j2的依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <!--如果引用由web的依赖,需要排除掉spring自带的logging日志依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
2.2 配置文件
添加上述依赖后,需要添加配置文件log4j2.xml
,放置在resources
目录下:
<?xml version="1.0" encoding="UTF-8"?>
<!-- status表示设置的日志级别,高于该级别的日志显示,monitorInterval配置成一个正整数,则每隔指定的时间(秒),
log4j2会刷新一次配置。如果不配置则不会动态刷新 -->
<configuration status="info" monitorInterval="600" >
<properties>
<property name="LOG_HOME">./logs</property>
<!--info日志的标准输出文件名字-->
<property name="FILE_NAME_INFO">std</property>
<!--error日志的标准输出文件名字-->
<property name="FILE_NAME_ERROR">error</property>
<!--日志输出的格式-->
<!--日期时间|日志级别|所属类的全类名|线程名|进程号|方法名|日志信息-->
<property name="PATTERN_LAYOUT">%d{yyyy-MM-dd HH:mm:ss}|%-5level|%c{5}|%t|%processId|%M|%m%n</property>
</properties>
<!--先定义所有的appender -->
<Appenders>
<!--这个输出控制台的配置 -->
<Console name="Console" target="SYSTEM_OUT">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
<!--输出日志的格式 引用定义的格式-->
<PatternLayout pattern="${PATTERN_LAYOUT}"/>
</Console>
<!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用 -->
<!--append为true表示消息追加到指定文件中,false表示消息覆盖指定的文件内容,默认值是true -->
<RollingRandomAccessFile name="info" fileName="${LOG_HOME}/${FILE_NAME_INFO}.log" append="true"
filePattern="${LOG_HOME}/${FILE_NAME_INFO}.log.%d{yyyy-MM-dd}">
<Policies>
<!--TimeBasedTriggeringPolicy :时间滚动策略,默认0点小时产生新的文件, modulate="true" : 产生文件是否以0点偏移时间-->
<TimeBasedTriggeringPolicy/>
</Policies>
<!-- 日志输出格式 -->
<PatternLayout pattern="${PATTERN_LAYOUT}"/>
</RollingRandomAccessFile >
<!--添加过滤器Filters,可以有选择的输出某个级别以上的类别 onMatch="ACCEPT" onMismatch="DENY"意思是匹配就接受,否则直接拒绝 -->
<RollingRandomAccessFile name="error" fileName="${LOG_HOME}/${FILE_NAME_ERROR}.log"
filePattern="${LOG_HOME}/${FILE_NAME_ERROR}.log.%d{yyyy-MM-dd}">
<Policies>
<!--TimeBasedTriggeringPolicy :时间滚动策略,默认0点小时产生新的文件, modulate="true" : 产生文件是否以0点偏移时间-->
<TimeBasedTriggeringPolicy/>
</Policies>
<Filters>
<!--记录error级别信息 -->
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
<!--输出日志的格式 -->
<PatternLayout pattern="${PATTERN_LAYOUT}"/>
</RollingRandomAccessFile >
</Appenders>
<!--然后定义logger,只有定义了logger并引入的appender,appender才会生效 -->
<loggers>
<root level="info">
<appender-ref ref="Console"/>
<appender-ref ref="error" />
<appender-ref ref="info"/>
</root>
<!--向root上报这个包下的debug级别的日志-->
<logger name = "com.kevin" level="debug" />
</loggers>
</configuration>
2.3 测试代码
package com.kevin.log4j;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.Test;
/**
* @Author Kevin
* @Date 22:04 2023/4/18
* @Description
*/
public class Log4j2Demo {
private static Logger log = LogManager.getLogger();
@Test
public void log4j2DemoTest1(){
System.out.println("===========显示打印Debug日志信息=============");
log.debug("log level is DEBUG:{}","this is DEBUG log...");
System.out.println("===========显示打印Info日志信息=============");
log.info("log level is INFO:{}","this is INFO log...");
System.out.println("===========显示打印Warn日志信息=============");
log.warn("log level is WARN:{}","this is WARN log...");
System.out.println("===========显示打印Error日志信息=============");
log.error("log level is ERROR:{}","this is ERROR log...");
}
}
控制台输出结果:
日志文件中的结果:
配置文件的格式: log2j配置文件可以是xml格式的,也可以是json格式的,
配置文件的位置: log4j2默认会在classpath目录下寻找log4j2.xml、log4j.json、log4j.jsn等名称的文件,如果都没有找到,则会按默认配置输出,也就是输出到控制台,也可以对配置文件自定义位置(需要在web.xml中配置),一般放置在src/main/resources根目录下即可
配置文件的名称: 必须为log4j2字样
个人踩坑: 将log4j2.xml配置成了log4j.xml,结果log4j2没有找到对应的xml配置,按照默认配置输出到控制台上:只显示error级别的日志信息:
2.4 配置文件详解
log4j2.xml文件的配置大致如下:
- Configuration
- properties
- Appenders
- Console
- PatternLayout
- File
- RollingRandomAccessFile
- Async
- Console
- Loggers
- Logger
- Root
- AppenderRef
1、Configuration: 为根节点,有status和monitorInterval等多个属性
- status:用于表示控制log4j2的日志级别,其值的级别从小到大依次有: “trace”, “debug”, “info”, “warn”, “error” and “fatal”,只会显示高于status值级别的日志会显示。
- monitorInterval:每隔多长时间重新读取配置文件,可以不重启应用的情况下修改配置,时间单位:秒;
2、 Appenders: 输出源,用于定义日志输出的地方
log4j2支持的输出源有很多,有控制台Console、文件File、RollingRandomAccessFile、MongoDB、Flume 等
-
Console: 控制台输出源,是将日志打印到控制台上,开发的时候一般都会配置,以便进行调试
-
File: 文件输出源,将日志写入到指定的文件,需要配置输入到哪个位置(例如:./app/logs)
-
RollingRandomAccessFile: 该输出源也是写入到文件,不同的是比File更加强大,可以指定当文件达到一定大小(如20MB)时,另起一个文件继续写入日志,另起一个文件就涉及到新文件的名字命名规则,因此需要配置文件命名规则;这种方式更加实用,因为你不可能一直往一个文件中写,如果一直写,文件过大,打开就会卡死,也不便于查找日志。
RollingRandomAccseeFile:中有如下常用属性:
- fileName 指定当前日志文件的位置和文件名称
- filePattern 指定当发生Rolling时,文件的转移和重命名规则,大多用.log.时间进rolling:
filePattern="${LOG_HOME}/${FILE_NAME_INFO}.log.%d{yyyy-MM-dd}">
- SizeBasedTriggeringPolicy 指定当文件体积大于size指定的值时,触发Rolling
- DefaultRolloverStrategy 指定最多保存的文件个数
- TimeBasedTriggeringPolicy 这个配置需要和filePattern结合使用,注意filePattern中配置的文件重命名规则是${FILE_NAME}-%d{yyyy-MM-dd HH-mm}-%i,最小的时间粒度是mm,即分钟;若指定的size是1,结合起来就是每1分钟生成一个新文件。如果改成%d{yyyy-MM-dd HH},则最小粒度为小时,就会每一个小时生成一个文件
3、PatternLayout: 日志输出的格式
-
控制台或文件输出源(Console、File、RollingRandomAccessFile)都必须包含一个PatternLayout节点,用于指定输出文件的格式(如 日志输出的时间 文件 方法 行数 等格式)
-
例如
%d{yyyy-MM-dd HH:mm:ss}|%-5level|%c{5}|%t|%processId|%M|%m%n
-
日期时间|日志级别|所属类的全类名|线程名|进程号|方法名|日志信息
# 日志常用的显示格式含义: %c 输出所属类的全名,可写为 %c{Num} ,Num类名输出的范围 如:"com.kevin.study.DemoClass",%C{2}将使日志输出输出范围为:study.DemoClass %d 输出日志时间其格式为 可指定格式 如 %d{yyyy-MM-dd HH:mm:ss}等 %l 输出日志事件发生位置,包括类目名、发生线程,在代码中的行数 %n 换行符 %m输出代码指定信息,如info(“message”),输出message 一般输出:%m%n放在最后 %msg 显示日志文本 %-5level 输出日志级别,-5表示左对齐并且固定输出5个字符,如果不足在右边补0 %-5p 输出日志的优先级,即 FATAL ,ERROR 等; 与-5level效果一样 %r 输出从启动到显示该条日志信息所耗费的时间(毫秒数) %t 输出产生该日志事件的线程名 %processId 输出进程号,2.9之后新增 %M 显示方法名
4、Loggers: 日志器
日志器分为:根日志器Root和自定义日志器,当根据日志名字获取不到指定的日志器时,就使用Root作为默认的日志器,自定义时需要指定每个Logger的名称name(对于命名可以以包名作为日志的名字,不同的包配置不同的级别等),日志级别level,相加性additivity(是否继承下面配置的日志器), 对于一般的日志器(如Console、File、RollingRandomAccessFile)一般需要配置一个或多个输出源AppenderRef;
每个logger可以指定一个level(TRACE, DEBUG, INFO, WARN, ERROR, ALL or OFF),不指定时level默认为ERROR
additivity指定是否同时输出log到父类的appender,缺省为true。
5、properties: 属性
使用来定义常量,以便在其他配置的时候引用,该配置是可选的,譬如:
- 定义日志的存放位置 ,当前目录下的logs文件夹下:
<property name="LOG_HOME">./logs</property>
- 定义日志的输出格式:
<property name="PATTERN_LAYOUT">%d{yyyy-MM-dd HH:mm:ss}|%5p|%c{5}|%t|%processId|%M|%m%n</properties>