日志门面、实现框架和桥接器及实际使用

发布时间 2023-04-23 11:21:30作者: 浪迹天涯的派大星

  之前总是在项目中使用现成的日志框架,用着方便就不会去思考它的框架、发展和组成,别人怎么用我也怎么用。感觉就是很模糊不清楚,说不知道也知道点,说知道又讲不明白,看了不少文章,决定把这一块梳理一下。

1、现有日志的组成

  可能说到日志,大家都知道一部分,什么slf4j、logback等等,其实现有的日志体系经过很长时间的发展,主要呈现三部分:

  • 日志门面(只定义接口,不提供实现)
  • 日志实现(日志框架)
  • 适配器和桥接器(用于连通门面和实现)

一开始都是自己提供API接口,自己实现,如左边这种;慢慢的由于一些原因,同时方便将抽象的接口和具体的实现分离,对外的API接口是固定了,然后根据自己的需要去选择日志的具体实现,中间通过桥接器去连接适配。大致的关系图如下:

常见的日志门面如下: 

JCL停止更新,Spring5.0后由Spring-jcl接入;SLF4J目前是被使用最多的,认可度最高的日志门面

常见的日志框架如下:

log4j目前已经停止更新,结合了logback的优点重新写了log4j2;jul(java.util.logging)是JDK自带的日志实现。

2、具体搭配使用

2.1、SLF4J绑定具体日志实现

下图是SLF4J官网的日志框架图,给出了SLF4J绑定到具体日志实现时,需要引入的jar包。

图最下方给出的不同颜色的含义,分别是抽象接口、原生支持SLF4J的实现、适配层、非原生支持SLF4J的实现。

  1. 抽象接口层都是slf4j-api,很好理解,因为slf4j主要就是做日志门面。
  2. 原生支持SLF4J的实现:有logback、slf4j-simple.jar、slf4j-nop.jar。
  3. 非原生支持SLF4J的实现,有log4j和jul,因为这两个在SLF4J之前就出现了,后面SLF4j出现后,大家觉得这个日志门面很优秀,所以出现了适配SLF4J和log4j、jul的桥接包,也就是下图中的slf4j-reload4j.jar和slf4j-jdk14.jar
  4. log4j2是最后出现的,可以说吸取了前面一些日志框架的优点,它既做日志门面,也做日志实现,自成一体,所以未在下面的图中出现。当然SLF4J和log4j2也可以搭配,使用log4j-slf4j-impl的桥接包。

注:logback、slf4j-simple.jar、slf4j-nop.jar之所以能天然支持SLF4J的接口是有原因的,slf4j-simple.jar、slf4j-nop.jar都是slf4j自带的实现框架,本身就是按slf4j-api的接口开发的。logback之所以也天然适配SLF4J,有两个原因,一是出现的先后原因,log4j ->JUL->JCL-> SLF4J -> logback -> log4j2,logback在SLF4J后面出现,第二个是因为这两个都是同一个作者写的。

上面的图来源于官网:https://www.slf4j.org/manual.html

2.2、从其他的日志实现/门面到SLF4J

其实大致的实现就是两步,一是选择SLF4J和具体实现,二是兼容旧的日志实现/门面到SLF4J。

例如我之前是用的JCL的API,不可能因为要换一个日志框架,把原先的日志代码都改掉吧(API的方法不一样,入参和使用方法也不一样),这个代价太大,我希望的是,原有的日志代码可以不动,后续的代码可以用新的SLF4J的API,桥接包就是为了达到这样的效果。

具体操作就三步:

1、移除掉旧的日志依赖

2、引入SLF4J提供的桥接依赖

3、项目中引入SLF4J和新的日志实现

上图来自于SLF4J官网:https://www.slf4j.org/legacy.html

3、实际应用

下面的举两个实际使用的例子,一是Springboot中的直接引入spring-boot-starter-logging(本质也是SLF4j+logback,内部添加了相关依赖);二是SLF4J+log4j2

3.1、spring-boot-starter-logging

  • 依赖引入

如果是Springboot的项目,可以直接引入spring-boot-starter-logging依赖即可,自行选择对应的版本引入依赖,如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-logging</artifactId>
    <version>2.7.8</version>
</dependency>

也可以单独引入slf4j、logback依赖,版本自行指定,如下:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>2.0.7</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.11</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.2.11</version>
</dependency>
  • 增加日志的配置文件

配置文件放到resource目录下,文件名称为logback-spring.xml,则springboot来加载,如果是logback.xml,则由日志框架来加载,完整的日志文件配置如下,按日志级别分为多个文件,配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
    <!-- 引入spirng boot默认的logback配置文件 -->

    <contextName>logback</contextName>
    <!--日志输出路径-->
    <property name="logDir" value="logs/test"/>
    <!--日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN"
              value="%d{HH:mm:ss.SSS} [%highlight(%thread)] %highlight(%-5level) %logger{20} - [%blue(%method),%line] - %msg%n"/>


    <!--输出到控制台-->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- 时间滚动输出 level为 DEBUG 日志 -->
    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <!--先将今天的日志保存在这个文件中-->
        <file>${logDir}/log_debug.log</file>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${logDir}/debug/log-debug-%d{yyyy-MM-dd_HH-mm}.%i.log</fileNamePattern>
            <!--单个日志文件最大15M-->
            <maxFileSize>15MB</maxFileSize>
            <!--日志文件保留天数-->
            <maxHistory>30</maxHistory>
            <!--所有的日志文件最大100MB,超过就会删除旧的日志-->
            <totalSizeCap>100MB</totalSizeCap>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>debug</level>
            <onMatch>NEUTRAL</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>


    <!-- 时间滚动输出 level为 INFO 日志 -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${logDir}/log_info.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${logDir}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!--单个日志文件最大15M-->
            <maxFileSize>15MB</maxFileSize>
            <!--日志文件保留天数-->
            <maxHistory>30</maxHistory>
            <!--所有的日志文件最大100MB,超过就会删除旧的日志-->
            <totalSizeCap>100MB</totalSizeCap>
        </rollingPolicy>
        <!-- 此日志文件只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>


    <!-- 时间滚动输出 level为 WARN 日志 -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${logDir}/log_warn.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${logDir}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!--单个日志文件最大15M-->
            <maxFileSize>15MB</maxFileSize>
            <!--日志文件保留天数-->
            <maxHistory>30</maxHistory>
            <!--所有的日志文件最大100MB,超过就会删除旧的日志-->
            <totalSizeCap>100MB</totalSizeCap>
        </rollingPolicy>
        <!-- 此日志文件只记录warn级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>


    <!-- 时间滚动输出 level为 ERROR 日志 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${logDir}/log_error.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${logDir}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!--单个日志文件最大15M-->
            <maxFileSize>15MB</maxFileSize>
            <!--日志文件保留天数-->
            <maxHistory>30</maxHistory>
            <!--所有的日志文件最大100MB,超过就会删除旧的日志-->
            <totalSizeCap>100MB</totalSizeCap>
        </rollingPolicy>
        <!-- 此日志文件只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>


    <!--root配置必须在appender下边-->
    <!--root节点是对所有appender的管理,添加哪个appender就会打印哪个appender的日志-->
    <!--root节点的level是总的日志级别控制,如果appender的日志级别设定比root的高,会按照appender的日志级别打印日志,-->
    <!--如果appender的日志级别比root的低,会按照root设定的日志级别进行打印日志-->
    <!--也就是说root设定的日志级别是最低限制,如果root设定级别为最高ERROR,那么所有appender只能打印最高级别的日志-->
    <root level="debug">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="DEBUG_FILE"/>
        <appender-ref ref="INFO_FILE"/>
        <appender-ref ref="WARN_FILE"/>
        <appender-ref ref="ERROR_FILE"/>
    </root>

    <!--配置多环境日志输出  可以在application.properties中配置选择哪个profiles : spring.profiles.active=dev-->
    <!--生产环境:输出到文件,多个环境用英文逗号隔开-->
    <springProfile name="prod">
        <root level="info">
            <appender-ref ref="DEBUG_FILE"/>
            <appender-ref ref="INFO_FILE"/>
            <appender-ref ref="ERROR_FILE"/>
            <appender-ref ref="WARN_FILE"/>
        </root>
    </springProfile>


    <!--开发环境:打印控制台-->
    <springProfile name="local">
        <root level="debug">
            <appender-ref ref="STDOUT"/>
        </root>
    </springProfile>

</configuration>

如果想要所有的日志打在一个文件里面,可以只增加一个RollingFileAppender,配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
    <!-- 引入spirng boot默认的logback配置文件 -->

    <contextName>logback</contextName>
    <!--日志输出路径-->
    <property name="logDir" value="logs/test"/>
    <!--日志输出格式-->
    <property name="CONSOLE_LOG_PATTERN"
              value="%d{HH:mm:ss.SSS} [%highlight(%thread)] %highlight(%-5level) %logger{20} - [%blue(%method),%line] - %msg%n"/>


    <!--输出到控制台-->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- 时间滚动输出 level为 DEBUG 日志 -->
    <appender name="LOG_ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <!--先将今天的日志保存在这个文件中-->
        <file>${logDir}/log_all.log</file>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${logDir}/debug/log-debug-%d{yyyy-MM-dd_HH-mm}.%i.log</fileNamePattern>
            <!--单个日志文件最大15M-->
            <maxFileSize>50MB</maxFileSize>
            <!--日志文件保留天数-->
            <maxHistory>30</maxHistory>
            <!--所有的日志文件最大100MB,超过就会删除旧的日志-->
            <totalSizeCap>100MB</totalSizeCap>
        </rollingPolicy>
    </appender>

    <!--root配置必须在appender下边-->
    <!--root节点是对所有appender的管理,添加哪个appender就会打印哪个appender的日志-->
    <!--root节点的level是总的日志级别控制,如果appender的日志级别设定比root的高,会按照appender的日志级别打印日志,-->
    <!--如果appender的日志级别比root的低,会按照root设定的日志级别进行打印日志-->
    <!--也就是说root设定的日志级别是最低限制,如果root设定级别为最高ERROR,那么所有appender只能打印最高级别的日志-->
    <root level="debug">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="LOG_ALL"/>
    </root>

    <!--配置多环境日志输出  可以在application.properties中配置选择哪个profiles : spring.profiles.active=dev-->
    <!--生产环境:输出到文件,多个环境用英文逗号隔开-->
    <springProfile name="dev">
        <!--单独指定包路径下的日志级别,和Root的日志级别取高者,即Root配置的日志级别是error,此处配置info,也是按error生效-->
        <logger name="org.springframework.web" level="ERROR"/>
        
        <root level="info">
            <appender-ref ref="LOG_ALL"/>
        </root>
        
    </springProfile>


    <!--开发环境:打印控制台-->
    <springProfile name="local">
        <root level="debug">
            <appender-ref ref="STDOUT"/>
        </root>
    </springProfile>

</configuration>
  • 两种方式使用,一种是类上加@Slf4j注解的方式,一种是通过日志工厂的方式,如下

@Slf4j注解的方式,这种方式需要配合Lombok插件使用:

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@Slf4j
@SpringBootApplication(scanBasePackages = {"org.example.*"})
public class Main {

    public static void main(String[] args) {
        log.info("这是info日志");
        log.debug("这是debug日志");
        log.warn("这是warn日志");
        log.error("这是error日志");
        log.trace("这是trace日志");
        try {
            SpringApplication.run(Main.class, args);
        } catch (Exception e) {
            log.error("errorInfo", e);
        }
        System.out.println("Hello world!");
    }
}

日志工厂的方式:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication(scanBasePackages = {"org.example.*"})
public class Main {

    final static Logger logger = LoggerFactory.getLogger(Main.class);

    public static void main(String[] args) {
        logger.info("这是info日志");
        logger.debug("这是debug日志");
        logger.warn("这是warn日志");
        logger.error("这是error日志");
        logger.trace("这是trace日志");
        try {
            SpringApplication.run(Main.class, args);
        } catch (Exception e) {
            logger.error("errorInfo", e);
        }
        System.out.println("Hello world!");
    }
}

3.2、Slf4j+Log4j2

  • 依赖引入

最新的log4j-slf4j2-impl已经引了slf4j-api、log4j-api、log4j-core依赖,不需要重复引入。(此处引入jul-to-slf4j的目的是将日志统一,因为可能部分日志打印还是走的JUL)

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j2-impl</artifactId>
    <version>2.20.0</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jul-to-slf4j</artifactId>
    <version>2.0.7</version>
</dependency>
  • 配置文件

配置文件可以灵活设置存储位置、日志格式、日志文件存储、删除以及指定包路径下的日志级别等等

<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL,每60秒自动刷新读取配置-->
<Configuration status="WARN" monitorInterval="60">
    <!-- 自定义一些变量 -->
    <Properties>
        <!-- 日志存储路径,注意路径开头加斜线,会无法输出日志文件-->
        <Property name="log_base_dir">logs/test</Property>
        <!-- 日志格式化配置-->
        <Property name="log_pattern">[%d{yyyy-MM-dd HH:mm:ss.SSS}][%-5p][%T][%c.%M:%L] %msg%xEx%n</Property>
        <!-- 单个日志文件最大大小,单位可以是KB, MB or GB -->
        <Property name="max_single_file_size">10MB</Property>
    </Properties>

    <Appenders>
        <!-- Console Appender常用于将日志输出到System.out,一般用在开发环境 -->
        <Console name="Console" target="SYSTEM_OUT">
            <!-- 只接受程序中DEBUG级别的日志进行处理-->
            <filters>
                <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
            </filters>
            <!-- 在大多数情况下,Appender将格式化LogEvent的责任委托给Layout -->
            <PatternLayout pattern="${log_pattern}"/>
        </Console>

        <!-- 输出日志到DEBUG文件 -->
        <RollingFile name="DebugLogRollingFile" fileName="${log_base_dir}/debug.log"
                     filePattern="${log_base_dir}/$${date:yyyy_MM_dd}/debug_%d{yyyy_MM_dd_HH}_%i.log.gz">
            <!--第一个过滤器,丢掉INFO及以上的日志,INFO以下的日志进入下一个过滤器,第二个过滤器保存DEBUG及以上的日志,Debug以下的日志丢掉,所以只保存debug级别的日志-->
            <filters>
                <ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/>
                <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
            </filters>
            <PatternLayout pattern="${log_pattern}" charset="UTF-8"/>
            <!-- Policies内部的任意一个TriggeringPolicy满足触发条件,都会滚动日志 -->
            <Policies>
                <!-- 用于按时间滚动日志-->
                <TimeBasedTriggeringPolicy interval="1" modulate="false"/>
                <!-- 用于按文件大小滚动日志 -->
                <SizeBasedTriggeringPolicy size="${max_single_file_size}"/>
            </Policies>
            <!-- 同一天内的日志文件序号返回,超过就会删除 -->
            <DefaultRolloverStrategy min="1" max="10"/>
        </RollingFile>

        <!-- 输出日志到INFO文件 -->
        <RollingFile name="InfoLogRollingFile" fileName="${log_base_dir}/info.log"
                     filePattern="${log_base_dir}/$${date:yyyy_MM_dd}/info_%d{yyyy_MM_dd_HH}_%i.log.gz">
            <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${log_pattern}"/>
            <Policies>
                <!-- 用于按时间滚动日志-->
                <TimeBasedTriggeringPolicy interval="1" modulate="false"/>
                <!-- 用于按文件大小滚动日志 -->
                <SizeBasedTriggeringPolicy size="${max_single_file_size}"/>
            </Policies>
            <!-- 同一天内的日志文件序号返回,超过就会删除 -->
            <DefaultRolloverStrategy min="1" max="50" fileIndex="nomax"/>
        </RollingFile>

        <!-- 输出日志到WARN文件 -->
        <RollingFile name="WarnLogRollingFile" fileName="${log_base_dir}/warn.log"
                     filePattern="${log_base_dir}/$${date:yyyy_MM_dd}/warn_%d{yyyy_MM_dd_HH}_%i.log.gz">
            <ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${log_pattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="${max_single_file_size}"/>
            </Policies>
            <!-- 同一天内的日志文件序号返回,超过就会删除 -->
            <DefaultRolloverStrategy min="1" max="50" fileIndex="nomax"/>
        </RollingFile>

        <!-- 输出日志到ERROR文件 -->
        <RollingFile name="ErrorLogRollingFile" fileName="${log_base_dir}/error.log"
                     filePattern="${log_base_dir}/$${date:yyyy_MM_dd}/error_%d{yyyy_MM_dd_HH}_%i.log.gz">
            <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
            <PatternLayout pattern="${log_pattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="${max_single_file_size}"/>
            </Policies>
            <!-- 同一天内的日志文件序号返回,超过就会删除 -->
            <DefaultRolloverStrategy min="1" max="50" fileIndex="nomax"/>
        </RollingFile>

        <!-- 记录druid的SQL语句 -->
        <RollingFile name="DruidSqlRollingFile" fileName="${log_base_dir}/druid.log"
                     filePattern="${log_base_dir}/$${date:yyyy_MM_dd}/druid_%d{yyyy_MM_dd_HH}_%i.log.gz">
            <PatternLayout pattern="${log_pattern}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="${max_single_file_size}"/>
            </Policies>
            <DefaultRolloverStrategy fileIndex="nomax">
                <Delete basePath="${log_base_dir}" maxDepth="2" testMode="true">
                    <IfFileName glob="*/druid_*.log.gz">
                        <IfAny>
                            <IfAccumulatedFileSize exceeds="300M"/>
                            <IfAccumulatedFileCount exceeds="100"/>
                            <IfLastModified age="30d"/>
                        </IfAny>
                    </IfFileName>
                </Delete>
            </DefaultRolloverStrategy>
        </RollingFile>
    </Appenders>

    <!--定义logger,只有定义了logger并引入的appender,appender才会生效-->
    <Loggers>
        <Root level="ALL">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="InfoLogRollingFile"/>
            <AppenderRef ref="WarnLogRollingFile"/>
            <AppenderRef ref="DebugLogRollingFile"/>
            <AppenderRef ref="ErrorLogRollingFile"/>
        </Root>


        <!--记录druid-sql的记录-->
        <Logger name="druid.sql.Statement" level="debug" additivity="false">
            <appender-ref ref="DruidSqlRollingFile"/>
        </Logger>

        <!--指定不同包名下的日志级别,用于过滤不重要的日志-->
        <Logger name="org.springframework" level="INFO"/>
        <Logger name="org.mybatis" level="INFO"/>

        <!--log4j2 自带过滤日志-->
        <Logger name="org.apache.catalina.startup.DigesterFactory" level="error"/>
        <Logger name="org.apache.catalina.util.LifecycleBase" level="error"/>
        <Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn"/>
        <Logger name="org.apache.sshd.common.util.SecurityUtils" level="warn"/>
        <Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn"/>
        <Logger name="org.crsh.plugin" level="warn"/>
        <Logger name="org.crsh.ssh" level="warn"/>
        <Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error"/>
        <Logger name="org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration" level="warn"/>
        <Logger name="org.springframework.boot.actuate.endpoint.jmx" level="warn"/>
        <Logger name="org.thymeleaf" level="warn"/>
        <Logger name="org.hibernate.validator" level="warn"/>
    </Loggers>
</Configuration>

 Tips:

1、onMatch表示匹配当前级别日志和更高级别日志,onMismatch表示匹配低于当前级别的日志。

2、onMatch和onMismatch可以设置三个值:ACCEPT,DENY,NEUTRAL,依次表示接受(在当前过滤器处理)、拒绝(当前过滤器直接拒绝,不会到达下一个过滤器)和中立(表示当前过滤器不做处理,交由下一个过滤器处理)

3、应用多个过滤器需要加<fliters/>标签,只应用单个过滤器,可以直接使用<ThresholdFilter/>即可,这两种当时在上面完整的配置文件中均有使用。

4、灵活的采用多个过滤器,可以达到处理指定一个或几个日志级别的目的。

举个例子,加入我只想处理DEBUG级别的日志,可以如下配置:

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

第一个过滤器,onMatch="DENY"表示:对于INFO及以上的日志直接拒绝;onMismatch="NEUTRAL":只有DEBUG和更低级别的日志可以到下一个过滤器处理

第二个过滤器,onMatch="ACCEPT"表示:接受DEBUG及以上的日志; onMismatch="DENY":DEBUG级别以下的日志直接拒绝。

经过了第一个过滤器的处理,达到第二个过滤器的只有DEBUG及以下的日志,而第二个过滤器又只接受DEBUG及以上的日志,两者取交集,所以达到的效果就是只处理DEBUG级别的日志。

当然也可以如下配置:

第一个过滤器让DEBUG及以上的日志到达下一个过滤器,然后第二个过滤器只处理DEBUG及以下的日志,两者取交集,所以也可以达到只处理DEBUG日志的目的。

<filters>
    <ThresholdFilter level="DEBUG" onMatch="NEUTRAL" onMismatch="DENY"/>
    <ThresholdFilter level="INFO" onMatch="DENY" onMismatch="ACCEPT"/>
</filters>
  • 使用方式

由于门面都是slf4j,所以使用方式和上面相同,一种是类上加@Slf4j注解的方式,一种是通过日志工厂的方式,不再赘述。