Log4j 是 Apache 的一个开源日志项目,通过 Log4j,开发人员可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是远程服务器等;开发人员也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用程序代码,大大降低了对程序代码的侵入性。在企业开发过程中,一般不直接使用 Log4J 的 API 进行日志输出,更加常见的是使用 SLF4J,即简单日志门面(Simple Logging Facade for Java)进行日志的输出操作。SLF4J 并不是具体的日志解决方案,它只服务于各种各样的日志系统。按照官方的说法,SLF4J 是一个用于日志系统的简单Facade,允许终端用户在部署其应用时使用其所选择的日志系统。
依赖引入及配置
由于 SpringBoot 默认日志框架是 logback,因此需要排除 spring-boot-starter-logging
,并且引入 spring-boot-starter-log4j2
。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
默认情况下,只要把 log4j2.xml
配置文件放在 classpath
环境变量所指定的目录即可。如果想放在其他位置,比如 resources/config
文件夹下,则需要在 application.yml
增加自定义的配置:
application.yml 示例
# 日志
logging:
config: classpath:config/log4j2.xml
log4j2.xml 示例
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="debug" monitorInterval="30">
<!-- 先定义所有的appender(附加器)-->
<appenders>
<!-- 输出控制台的配置 -->
<Console name="Console" target="SYSTEM_OUT">
<!-- 控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
<!-- 输出日志的格式 -->
<PatternLayout pattern="[%d{HH:mm:ss.SSS}] [%-5p] %l - %m%n"/>
</Console>
</appenders>
<!-- 然后定义logger,只有定义了logger并引入的appender,appender才会生效 -->
<loggers>
<!-- 过滤掉spring和mybatis的一些无用的DEBUG信息-->
<logger name="org.springframework" level="INFO"/>
<!-- 建立一个默认的root的logger -->
<root level="trace">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>
配置详解
一般企业开发中会使用一个 XML 配置文件来对 Log4j2 进行配置,一般命名为 log4j2.xml。Log4j2 的配置文件结构如下图所示的树状图。
Configuration根节点
- status 属性:指定 Log4j2 本身的日志打印级别。
- monitorinterval属性:用于指定 Log4j 自动重新配置的监测间隔时间,单位是秒,最小值是5s。
Appenders 附加器
Appenders 元素是 Configuration 元素的子节点,可以指定日志输出的路径,常见输出路径有控制台、文件和网络 Socket 等。
Appenders 元素常见子节点有:Console、File 和 RollingFile。
Console Appender
用来将日志输出到控制台
示例配置
<Console name="Console" target="SYSTEM_OUT">
<!-- 控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<!-- 输出日志的格式 -->
<PatternLayout pattern="[%d{HH:mm:ss.SSS}] [%-5p] %l - %m%n"/>
</Console>
配置介绍
属性
- name 属性:指定 Appender 的名字
- target 属性:可以为 SYSTEM_OUT 或 SYSTEM_ERR,一般使用 SYSTEM_OUT
元素
- PatternLayout 元素:设置日志输出的格式
- 根据需要
File Appender
用于设置将日志输出到指定的文件中
示例配置
<Appender type="File" name="File" fileName="${filename}">
<Layout type="PatternLayout">
<Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
</Layout>
</Appender>
配置介绍
属性
- name 属性:指定 Appender 的名字
- fileName 属性:指定输出日志的目标文件带全路径的文件名
元素
- PatternLayout 元素:设置日志输出的格式
RollingFile Appender
用于将日志输出到滚动文件中,日志输出时会判断文件是否满足封存文件的要求,若满足,则将文件封存并把日志写入到下一个滚动文件。
示例配置
<RollingFile name="app"
fileName="./app/log/app.log"
filePattern="./app/log/app.log.%d{yyyy-MM-dd}">
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="500 MB"/>
</Policies>
<DefaultRolloverStrategy max="7"/>
</RollingFile>
配置介绍
属性
- name 属性:指定Appender的名字
- fileName 属性:指定输出日志的目标文件带全路径的文件名
- filePattern 属性:用于指定新建日志文件的命名格式;
元素
- PatternLayout 元素:设置日志输出的格式
- Policies 元素:指定滚动日志的策略,即何时新建文件输出日志
- DefaultRolloverStrategy 元素:用来指定同一个目录下最多有几个日志文件时开始删除最旧的日志文件,并创建新的文件
Policies节点
- TimeBasedTriggeringPolicy:基于时间的滚动策略,interval 属性用于配置滚动一次的时间,默认是 1h;modulate=true 用于调整时间
- SizeBasedTriggeringPolicy:基于指定文件大小的滚动策略,size 属性用来定义每个日志文件的大小
PatternLayout规则
PatternLayout 是用于控制日志输出格式的,其详细配置规则如下。
PatternLayout 的属性如下表:
pattern 属性参数格式如下表:
还可以设置日志对齐:
在任何 pattern 和 “%” 之间加入一个整数,可以是正数,也可以是负数,正数表示右对齐,负数表示左对齐,如下所示:
%20 —— 右对齐,不足20个字符则在信息前面用空格补足,超过20个字符则保留原信息
%-20 —— 左对齐,不足20个字符则在信息后面用空格补足,超过20个字符则保留原信息
也可以用小数的形式控制日志的对齐方式,整数位表示输出信息最小为 n 个字符,如果输出信息不够n个字符,将用空格补齐,小数位表示输出信息的最大字符数,如果超过 n 个字符,则只保留最后 n 个字符的信息。
%.30 —— 如果信息超过30个字符,则只保留最后30个字符
%20.30 —— 右对齐,不足20个字符则在信息前用空格补足,超过30个字符则保留最后30个字符
%-20.30 —— 左对齐,不足20个字符则在信息后用空格补足,超过30个字符则保留最后30个字符
Loggers元素
Root
用于指定项目的根日志,如果没有单独指定 Logger,则会使用 Root 作为默认的日志输出。
属性
- level 属性:用于定义日志输出级别,共有 8 个,从低到高顺序为
All < Trace < Debug < Info < Warn < Error < Fatal < OFF
元素
- AppenderRef 元素:用于指定将日志输出到 Appenders 元素定义的 Appender 中
Logger
用于单独指定日志的形式。
属性
- name:用来指定该 Logger 所适用的类或者类所在的包全路径,继承自 Root 节点。一般是项目包名或者框架的包名,比如:
org.springframework
- level:日志输出级别,共有 8 个级别,按照从低到高为:
All < Trace < Debug < Info < Warn < Error < Fatal < OFF
元素
- AppenderRef 元素:用于设置将该日志输出到指定 Appender,如果没有指定,就会默认继承自 Root。如果已指定,那么在指定的 Appender 和 Root 的 Appender 中都会进行日志输出。
Filters 元素
常用过滤器
过滤器 | 说明 | 是否常用 |
---|---|---|
StringMatchFilter | 如果格式化后(即:最终)的日志信息中包含${指定的字符串},则onMatch,否则onMismatch | 是 |
LevelRangeFilter | 若${maxLevel} <= 日志级别 <= ${minLevel}, 则onMatch,否则onMismatch | 是 |
RegexFilter | 如果日志信息匹配${指定的正则表达式},则onMatch,否则onMismatch。注:可通过useRawMsg属性来控制这个日志信息是格式化处理后(即:最终)的日志信息,还是格式化处理前(即:代码中输入)的日志信息。 | 是 |
ThresholdFilter | 若日志级别 >= ${指定的日志级别}, 则onMatch,否则onMismatch | 是 |
LevelMatchFilter | 如果日志级别等于${指定的日志级别},则onMatch,否则onMismatch | 是 |
ThreadContextMapFilter | 通过context中对应的key-value值进行过滤。注:上下文默认是ThreadContext,也可以自定义使用ContextDataInjectorFactory配置ContextDataInjector来指定。 | 是 |
DynamicThresholdFilter | 若上下文中包含指定的key,则触发DynamicThresholdFilter生效;若该key对应的value值等于任意一个我们指定的值,那么针对本条日志,可记录日志级别的约束下限调整为指定的级别。注:上下文默认是ThreadContext,也可以自定义使用ContextDataInjectorFactory配置ContextDataInjector来指定。 | 是 |
CompositeFilter | 组合过滤器,即:按照 XML 配置中的配置,一个过滤器一个过滤器的走,如果在这过程中,任意一个过滤器 ACCEPT 或 DENY 了,那么就不会往后走了,直接返回对应的结果。 | 是 |
TimeFilter | 如果记录日志时的当前时间落在每天指定的时间范围[start, end]内,则onMatch,否则onMismatch | 否 |
ScriptFilter | 是否匹配取决于指定的脚本返回值是否为true | 否 |
DenyAllFilter | 拒绝全部日志 | 否 |
BurstFilter | 对低于或等于${指定日志级别}的日志,进行限流控制 | 否 |
NoMarkerFilter | 如果从对应事件对象获取(LogEvent#getMarker)到的marker为null, 则onMatch,否则onMismatch | 否 |
MarkerFilter | 如果从对应事件对象获取(LogEvent#getMarker)到的marker的name值为等于${指定的值}, 则onMatch,否则onMismatch | 否 |
作用范围
由全局到局部依次是:Context-wide、 Logger、Appender 和 AppenderReference。
匹配结果枚举
- ACCEPT:(不需要再走后面的过滤器了) 需要记录当前日志。
- NEUTRAL:需不需要记录当前日志,由后续过滤器决定。若所有过滤器返回的结果都是NEUTRAL,那么需要记录日志。
- DENY:(不需要再走后面的过滤器了) 不需要记录当前日志。