log4j2 将特定级别 INFO 日志打印到文件

时间:2025-03-23 07:37:05

本文要解决的是如何将 mybatis 的 sql 日志打印到特定文件问题。

业务场景

在使用 mybatis-plus 的时候,我们有时需要将 SQL 打印到控制台,便于排查代码问题。

Mybatis-plus 需要通过下面的方式开启控制台 SQL 日志打印:

mybatis-plus:
  configuration:
    log-impl: 

看起来确实没问题,但是,日志只能打印到控制台,而在项目上线初期,我们是希望线上环境也打印 sql 的。

不过,线上环境错综复杂,日志刷新飞快,我们当然只希望打印关键的信息,像 sql 日志这种刷屏的 log 显然是要禁止打印到控制台的。

日志配置

mybatis-plus 开启与关闭 SQL 日志打印 中,已经介绍过,mybatis 有多种日志实现方式。

下面这种配置是基于 log4j2 的日志配置:

mybatis-plus:
	configuration:
		log-impl: .log4j2.Log4j2Impl

注意,为了让上面的配置生效,还要在 文件中配置如下片段:

        <Logger name="" level="DEBUG">
            <AppenderRef ref="SQL-APPENDER"/>
        </Logger>
  • name 是当前项目 mapper 文件的包路径,
  • level 是固定值 DEBUG ,
  • appendref 需要我们定义一个 appender.

自定义的 appender 如下:

        <RollingFile name="SQL-APPENDER"
                     fileName="logs/"
                     filePattern="logs/.%d{yyyy-MM-dd}"
                     append="true">
            <PatternLayout
                    pattern="%d %-5p %c{2} - %m%n%throwable"
                    charset="UTF-8"/>
            <TimeBasedTriggeringPolicy/>
            <DefaultRolloverStrategy/>
        </RollingFile>

配置结束,启动项目后,触发业务请求,然后打开 文件,看到执行的 sql 确实存在。

效果达到了,但是不完美,日志文件里多了很多 mybatis 其他的启动日志,通过观察,发现他们基本都是 INFO 级别的。

日志过滤

我们在上面设置日志的级别为 DEBUG,怎么把 INFO 也输出了呢?

这就得从 log 的 日志级别 说起了。

日志级别

日志级别是按严重(重要)程度来分的:

  • OFF ↓
  • FATAL ↓
  • ERROR ↓
  • WARN ↓
  • INFO ↓
  • DEBUG ↓
  • TRACE ↓
  • ALL ↓

从上到下,日志级别依次降低,打印的日志内容也越来越详细。

打印日志的规则:

levelP>=levelQ,则levelP会打印在levelQ的log里。

即:低级别的日志会包含高级别的日志内容。

举个例子:如果设置的日志级别是 debug,则会包括debug、info、error等高级别的日志。

ThresholdFilter

在 log4j2 中,ThresholdFilter 用来过滤日志相对应的日志级别。

它的三个重要参数:

  • level: 标识需要过滤的日志级别,取值同上 日志级别
    • INFO: info 日志级别
    • DEBUG: debug 日志级别
  • onMatch:
    • ACCEPT: 表示匹配该级别及以上
    • DENY:表示不匹配该级别及以上
    • NEUTRAL:表示该级别及以上的,由下一个filter处理;如果当前是最后一个,则同 ACCEPT
  • onMismatch:
    • ACCEPT:表示匹配该级别以下
    • DENY:表示不匹配该级别以下的
    • NEUTRAL:表示该级别及以下的,由下一个filter处理,如果当前是最后一个,则同 DENY

基于上面的规则,很容易想到的方式来打印 DEBUG 级别日志:

<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>

打开 发现,并没有如你所愿,除了 debug 级别的日志, info 日志也打印了。

实际上,上面的配置是说:debug 及以上级别日志,包含 info 、warn、error等都接受,其他级别如 trace 丢弃。

于是,想办法把 info 级别的日志去除:

<ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/>

上面的配置表示: info 级别包含该级别及以上,如 warn、error 日志拒绝,debug、trace 级别日志由下一个 filter 处理。

经典实用场景

要打印错误日志

项目中,经常会留一个文件只存放错误日志,然后监控错误日志的变化来感知项目健康状态。

<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>

上面的配置相当于取日志中的 ERROR 和 FATAL 级别内容,可以将其输出到 文件。

上面的配置也可以做如下简化:

<ThresholdFilter level="ERROR"/>

只打印 DEBUG 级别到文件

开头的问题,如果希望只打印 sql 到对应的文件,应该如下配置:

    <ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/>
    <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>

这里使用了组合 filter ,组合可以让场景更为复杂,也嫩更为精准地控制日志内容。

组合需要注意一点:先定义日志级别 level 高的Filter。

总结

完整的 文件:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>

    <!--定义appender -->
    <Appenders>
		...
        <RollingFile name="SQL-APPENDER"
                     fileName="logs/"
                     filePattern="logs/.%d{yyyy-MM-dd}"
                     append="true">
            <PatternLayout
                    pattern="%d %-5p %c{2} - %m%n%throwable"
                    charset="UTF-8"/>
            <TimeBasedTriggeringPolicy/>
            <DefaultRolloverStrategy/>
            <ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/>
            <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
        </RollingFile>
		<RollingFile name="ERROR-APPENDER"
					 fileName="logs/"
					 filePattern="logs/.%d{yyyy-MM-dd}"
					 append="true">
			<PatternLayout
					pattern="%d %-5p %c{2} - %m%n%throwable"
					charset="UTF-8"/>
			<TimeBasedTriggeringPolicy/>
			<DefaultRolloverStrategy/>
			<ThresholdFilter level="ERROR"/>
		</RollingFile>
		...
    </Appenders>
	
	<Loggers>
        <Root level="info">
            <AppenderRef ref="SQL-APPENDER"/>
			<AppenderRef ref="ERROR-APPENDER"/>
        </Root>

		...
        <Logger name=""  level="DEBUG">
            <AppenderRef ref="SQL-APPENDER"/>
        </Logger>
    </Loggers>
</Configuration>

上面的配置,可以让 文件中仅仅存在 debug 级别的 sql 日志,在 error 中包含系统错误日志。