美文网首页Java后台程序员
(4) spring-boot+logback+log4j2+M

(4) spring-boot+logback+log4j2+M

作者: 桥头放牛娃 | 来源:发表于2018-10-31 14:07 被阅读88次

    spring boot内部使用Commons Logging来记录日志,但也保留外部接口可以让一些日志框架来进行实现,例如Java Util Logging,Log4J2还有Logback。如果你想用某一种日志框架来进行实现的话,就必须先配置,默认情况下,Spring Boot会用Logback来记录日志,并用INFO级别输出到控制台。

    1、日志配置

    1.1、默认配置

    依赖于开发者选择的日志框架,这些对应的配置文件会被加载;

    日志框架 配置文件
    Logback logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy
    Log4j log4j-spring.properties, log4j-spring.xml, log4j.properties, log4j.xml
    Log4j2 log4j2-spring.xml, log4j2.xml
    JDK(JAVA Util Logging) logging.properties

    Spring Boot官方推荐优先使用带有-spring的文件名作为你的日志配置(如使用logback-spring.xml,而不是logback.xml),命名为logback-spring.xml的日志配置文件,spring boot可以为它添加一些spring boot特有的配置项,默认的命名规则,并且放在 src/main/resources 下面即可。

    1.2、修改spring-boot日志配置

    若不想使用spring-boot的默认日志路径及名称,可以在application.properties修改日志配置,配置如下:

    logging.config=classpath:spring/log4j2.xml
    

    2、logback配置

    Logback是log4j框架的作者开发的新一代日志框架,它效率更高、能够适应诸多的运行环境,同时天然支持SLF4J。

    2.1、pom配置

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

    若项目中添加以上依赖,则spring-boot将自动使用logback作为应用的日志框架;Spring Boot启动的时候,由org.springframework.boot.logging.Logging-Application-Listener根据情况初始化并使用。但在实际的开发中无需直接添加此依赖,因为spring-boot-starter中已包含了此依赖。

    2.2、配置文件位置

    配置文件名称为logback-spring.xml并放在classpath下,即项目的resources目录下;或自定义配置文件名称和位置,并在application.properties中配置,如下所示:

    logging.config=classpath:config/logback-spring.xml
    

    2.3、配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <!--
           说明:
           1、日志级别及文件
               日志记录采用分级记录,级别与日志文件名相对应,不同级别的日志信息记录到不同的日志文件中
               例如:error级别记录到log_error_xxx.log或log_error.log(该文件为当前记录的日志文件),而log_error_xxx.log为归档日志,
               日志文件按日期记录,同一天内,若日志文件大小等于或大于100M,则按0、1、2...顺序分别命名
               例如log-level-2013-12-21.0.log
               其它级别的日志也是如此。
           2、文件路径
               若开发、测试用,在Eclipse中运行项目,则到Eclipse的安装路径查找logs文件夹,以相对路径../logs。
               若部署到Tomcat下,则在Tomcat下的logs文件中
           3、Appender
               FILEERROR对应error级别,文件名以log-error-xxx.log形式命名
               FILEWARN对应warn级别,文件名以log-warn-xxx.log形式命名
               FILEINFO对应info级别,文件名以log-info-xxx.log形式命名
               FILEDEBUG对应debug级别,文件名以log-debug-xxx.log形式命名
               FILEALL对应所有级别,文件名以log-all-xxx.log形式命名
               stdout将日志信息输出到控制上,为方便开发测试使用
        -->
        <contextName>SpringBootDemo</contextName>
        <property name="LOG_PATH" value="C:\Users\zhaozhou\Desktop\demo" />
        <!--设置系统日志目录-->
        <property name="APPDIR" value="SpringBootDemo" />
    
        <!-- 日志记录器,日期滚动记录 -->
        <appender name="FILEERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!-- 正在记录的日志文件的路径及文件名 -->
            <file>${LOG_PATH}/${APPDIR}/log_error.log</file>
            <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
                而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
                <fileNamePattern>${LOG_PATH}/${APPDIR}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,
                命名日志文件,例如log-error-2013-12-21.0.log -->
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>100MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <!-- 追加方式记录日志 -->
            <append>true</append>
            <!-- 日志文件的格式 -->
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
                <charset>utf-8</charset>
            </encoder>
            <!-- 此日志文件只记录error级别的 -->
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>error</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
        </appender>
    
        <!-- 日志记录器,日期滚动记录 -->
        <appender name="FILEWARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!-- 正在记录的日志文件的路径及文件名 -->
            <file>${LOG_PATH}/${APPDIR}/log_warn.log</file>
            <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
                而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
                <fileNamePattern>${LOG_PATH}/${APPDIR}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,
                命名日志文件,例如log-error-2013-12-21.0.log -->
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>100MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <!-- 追加方式记录日志 -->
            <append>true</append>
            <!-- 日志文件的格式 -->
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
                <charset>utf-8</charset>
            </encoder>
            <!-- 此日志文件只记录warn级别的 -->
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>warn</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
        </appender>
    
    
        <!-- 日志记录器,日期滚动记录 -->
        <appender name="FILEINFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!-- 正在记录的日志文件的路径及文件名 -->
            <file>${LOG_PATH}/${APPDIR}/log_info.log</file>
            <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
                而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
                <fileNamePattern>${LOG_PATH}/${APPDIR}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,
                命名日志文件,例如log-error-2013-12-21.0.log -->
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>100MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <!-- 追加方式记录日志 -->
            <append>true</append>
            <!-- 日志文件的格式 -->
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
                <charset>utf-8</charset>
            </encoder>
            <!-- 此日志文件只记录info级别的 -->
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>info</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
        </appender>
    
    
        <!-- 日志记录器,日期滚动记录 -->
        <appender name="FILEALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!-- 正在记录的日志文件的路径及文件名 -->
            <file>${LOG_PATH}/${APPDIR}/log_all.log</file>
            <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
                而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
                <fileNamePattern>${LOG_PATH}/${APPDIR}/all/log-all-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,
                命名日志文件,例如log-error-2013-12-21.0.log -->
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>100MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <!-- 追加方式记录日志 -->
            <append>true</append>
            <!-- 日志文件的格式 -->
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
                <charset>utf-8</charset>
            </encoder>
            <!-- 此日志文件只记录info级别的 -->
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>trace</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>ACCEPT</onMismatch>
            </filter>
        </appender>
    
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <!--encoder 默认配置为PatternLayoutEncoder-->
            <encoder>
                <pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
                <charset>utf-8</charset>
            </encoder>
            <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
            <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                <level>debug</level>
            </filter>
        </appender>
    
        <logger name="org.springframework" level="WARN" />
        <logger name="org.mybatis" level="DEBUG" />
        <logger name="com.springboot" level="INFO"/>
    
        <!-- 生产环境下,将此级别配置为适合的级别,以免日志文件太多或影响程序性能 -->
        <root level="DEBUG">
            <appender-ref ref="FILEERROR" />
            <appender-ref ref="FILEWARN" />
            <appender-ref ref="FILEINFO" />
            <appender-ref ref="FILEALL" />
    
            <!-- 生产环境将请stdout,testfile去掉 -->
            <appender-ref ref="STDOUT" />
        </root>
    </configuration>
    

    2.3.1、设置上下文名称<contextName>

    每个logger都关联到logger上下文,默认上下文名称为“default”。但可以使用设置成其他名字,用于区分不同应用程序的记录。一旦设置,不能修改,可以通过%contextName来打印日志上下文名称。

    <contextName>SpringBootDemo</contextName>
    

    2.3.2、设置变量<property>

    用来定义变量值的标签, 有两个属性,name和value;其中name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。

    <property name="LOG_PATH" value="C:\Users\zhaozhou\Desktop\demo" />
    <!--设置系统日志目录-->
    <property name="APPDIR" value="SpringBootDemo" />
    

    此处设置系统日志的path和应用日志的目录;

    2.3.3、输出到RollingFileAppender

    随着应用的运行时间越来越长,日志也会增长的越来越多,将他们输出到同一个文件并非一个好办法。RollingFileAppender用于切分文件日志,配置如下:

        <!-- 日志记录器,日期滚动记录 -->
        <appender name="FILEERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!-- 正在记录的日志文件的路径及文件名 -->
            <file>${LOG_PATH}/${APPDIR}/log_error.log</file>
            <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
                而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
                <fileNamePattern>${LOG_PATH}/${APPDIR}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,
                命名日志文件,例如log-error-2013-12-21.0.log -->
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>100MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <!-- 追加方式记录日志 -->
            <append>true</append>
            <!-- 日志文件的格式 -->
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
                <charset>utf-8</charset>
            </encoder>
            <!-- 此日志文件只记录error级别的 -->
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>error</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
        </appender>
    
    • 此处配置日志类型为RollingFileAppender,<rollingPolicy>配置滚动存储的策略,一天一个文件,当文件大于100M时,按文件大小分文件存储。
    • <encoder>配置日志文件的格式,<pattern>定义了格式;
    • <filter>定义日志过滤器,本文件的日志级别为error,当日志级别为error时进行存储,不符合时不处理;

    2.3.4、配置说明

    本日志配置了五个处理器,分别处理error、warn、info、all及debug日志;

    • error处理器只处理并存储error级别的日志;
    • warn处理器只处理并存储warn级别的日志;
    • info处理器只处理并存储info级别的日志;
    • all处理器处理所有级别的日志;
    • debug及以上的日志级别都会在标准输出中输出;

    最终的日志文件会包含4个:

    • log_all.log:存储所有debug及以上级别的日志;
    • log_error.log:存储error级别的日志;
    • log_warn.log:存储warn级别的日志;
    • log_info.log:存储info级别的日志;

    3、log4j2配置

    由于spring-boot的所有starter的默认日志框架为logback,所以在配置log4j2时,需要将logback的包给排除,以免日志包冲突;

    3.1、pom配置

        <dependencies>
            <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-test</artifactId>
                <scope>test</scope>
                <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-thymeleaf</artifactId>
            </dependency>
    
           <!-- <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </dependency>-->
    
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            <!--<dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.0.25</version>
            </dependency>-->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
    
    
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.2</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-logging</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>1.1.8</version>
                <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>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
            </dependency>
        </dependencies>
    

    将所有会包含spring-boot-starter-logging的包给去除,并添加spring-boot-starter-log4j2的依赖包;

    3.1、配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="info" name="defaultLogConfig"
                   packages="">
        <properties>
            <property name="LOG_HOME">C:\Users\zhaozhou\Desktop\demo</property>
            <property name="patternlayout">%-d{yyyy-MM-dd HH:mm:ss}[ %t:%r ]- [%X{userName}] - [%X{reqId}] - [%-5p] %c-%M:%L - %m%n%throwable{full}</property>
        </properties>
        <Appenders>
            <!--这个输出控制台的配置-->
            <!--follow 不知道干嘛的-->
            <Console name="Console" target="SYSTEM_OUT">
                <PatternLayout pattern="${patternlayout}" />
            </Console>
            <RollingFile name="LOGERROR" fileName="${LOG_HOME}/error_log.log" filePattern="${LOG_HOME}/error/log-error-%d{yyyy-MM-dd}.%i.log">
                <ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
                <PatternLayout pattern="${patternlayout}"/>
                <SizeBasedTriggeringPolicy size="100MB"/>
                <DefaultRolloverStrategy max="10"/>
            </RollingFile>
    
            <RollingFile name="LOGWARN" fileName="${LOG_HOME}/warn_log.log" filePattern="${LOG_HOME}/warn/log-warn-%d{yyyy-MM-dd}.%i.log">
                <ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
                <PatternLayout pattern="${patternlayout}"/>
                <SizeBasedTriggeringPolicy size="100MB"/>
                <DefaultRolloverStrategy max="10"/>
            </RollingFile>
    
            <RollingFile name="LOGALL" fileName="${LOG_HOME}/all_log.log" filePattern="${LOG_HOME}/all/log-all-%d{yyyy-MM-dd}.%i.log">
                <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="ACCEPT"/>
                <PatternLayout pattern="${patternlayout}"/>
                <SizeBasedTriggeringPolicy size="100MB"/>
                <DefaultRolloverStrategy max="10"/>
            </RollingFile>
    
        </Appenders>
        <Loggers>
    
            <!-- spring log -->
            <AsyncLogger name="org.springframework" level="warn"/>
    
            <!-- activiti log -->
            <AsyncLogger name="org.activiti" level="info" />
    
    
            <AsyncLogger name="org.mybatis" level="debug" />
    
            <AsyncLogger name="org.apache" level="info" />
    
            <AsyncLogger name="com.springboot.demo" level="debug"/>
    
    
            <Root level="debug">
                <AppenderRef ref="LOGERROR" />
                <AppenderRef ref="LOGWARN"/>
                <AppenderRef ref="LOGALL"/>
                <AppenderRef ref="Console" />
            </Root>
        </Loggers>
    </Configuration>
    

    配置文件大体和上面logback的配置差不多,在此不多赘述;

    4、MDC配置

    4.1、MDC简介

    MDC 是 Mapped Diagnostic Context 的缩写,“映射诊断上下文”看起来高大上的样子,其实是非常简单的,就是一个临时存放k-v对的容器。和普通Map的区别是它是基于ThreadLocal实现的,所以不存在资源竞争问题,可以放心的往里面放东西。其主要用于打LOG时跟踪一个“会话“、一个”事务“。举例,有一个web controller,在同一时间可能收到来自多个客户端的请求,如果一个请求发生了错误,我们要跟踪这个请求从controller开始一步步都执行到了哪些代码、有哪些log的输出。这时我们可以看log文件,但是log文件是多个请求同时记录的,基本无法分辨哪行是哪个请求产生的,虽然我们可以看线程,但线程可能被复用,也是很难分辨出,这时MDC就派上用场了。

    4.2、主要api

    public class MDC {
        public static void put(String key, String val) //设置k-v
        public static String get(String key) //获取value
        public static void remove(String key) //移除k-v
        public static void clear() //clearMDC
        public static Map<String, String> getCopyOfContextMap() //获取MDC的备份map
        public static void setContextMap(Map<String, String> contextMap) //设置MDC的map
    }
    
    • put()和setContextMap()主要进行属性设置;
    • get()和getCopyOfContextMap()主要进行属性获取;
    • remove()移除属性信息,主要在线程结束时处理设置的属性;

    4.3、基于spring的HandlerInterceptorAdapter

    此种方法主要适用场景为跟踪http请求,通过拦截http请求,设置MDC,并在日志中打印设置参数,即可通过日志跟踪请求链;

    4.3.1、HandlerInterceptorAdapter拦截器配置

    登录拦截器:

    public class LoginInterceptor extends HandlerInterceptorAdapter {
    
        private static String MDC_KEY_USER_NAME = "userName";
        private static String MDC_KEY_REQ_ID = "reqId";
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            MDC.put(MDC_KEY_USER_NAME,"zhaozhou");
            MDC.put(MDC_KEY_REQ_ID, UUID.randomUUID().toString());
            return super.preHandle(request, response, handler);
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    
            super.postHandle(request, response, handler, modelAndView);
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
            MDC.remove(MDC_KEY_USER_NAME);
            MDC.remove(MDC_KEY_REQ_ID);
            super.afterCompletion(request, response, handler, ex);
        }
    
        @Override
        public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            super.afterConcurrentHandlingStarted(request, response, handler);
        }
    }
    
    

    注册拦截器:

    @Component
    public class MvcLoginInterceptor implements WebMvcConfigurer {
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            // 注册拦截器
            InterceptorRegistration ir = registry.addInterceptor(new LoginInterceptor());
            // 配置拦截的路径
            ir.addPathPatterns("/**");
            // 配置不拦截的路径
            ir.excludePathPatterns("/static/**","/templates/**");
        }
    }
    

    4.3.2、log4j2的pattern配置

    在log4j2-spring.xml的配置做如下修改:

    <properties>
        <property name="LOG_HOME">C:\Users\zhaozhou\Desktop\demo</property>
        <property name="patternlayout">%-d{yyyy-MM-dd HH:mm:ss}[ %t:%r ]- [%X{userName}] - [%X{reqId}] - [%-5p] %c-%M:%L - %m%n%throwable{full}</property>
    </properties>
    

    在patternlayout属性中添加userName和reqId的打印;

    对于logback日志的配置同此处一样;

    4.3.2、输出结果

    浏览器请求:http://localhost:8888/

    2018-10-31 12:11:06[ http-nio-8888-exec-8:17662 ]- [] - [] - [DEBUG] org.springframework.beans.factory.support.DefaultListableBeanFactory-doGetBean:254 - Returning cached instance of singleton bean 'testController'
    2018-10-31 12:11:06[ http-nio-8888-exec-8:17662 ]- [] - [] - [DEBUG] org.springframework.web.servlet.DispatcherServlet-doDispatch:979 - Last-Modified value for [/] is: -1
    2018-10-31 12:11:06[ http-nio-8888-exec-8:17663 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.mybatis.spring.SqlSessionUtils-getSqlSession:97 - Creating a new SqlSession
    2018-10-31 12:11:06[ http-nio-8888-exec-8:17664 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.mybatis.spring.SqlSessionUtils-registerSessionHolder:148 - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1366610e] was not registered for synchronization because synchronization is not active
    2018-10-31 12:11:06[ http-nio-8888-exec-8:17665 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.springframework.jdbc.datasource.DataSourceUtils-doGetConnection:114 - Fetching JDBC Connection from DataSource
    2018-10-31 12:11:06[ http-nio-8888-exec-8:17665 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.mybatis.spring.transaction.SpringManagedTransaction-openConnection:87 - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@2c6224d7] will not be managed by Spring
    2018-10-31 12:11:06[ http-nio-8888-exec-8:17666 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] com.springboot.demo.dao.UserDao.getUserById-debug:159 - ==> Preparing: select id, name, tel, email, create_time from t_user WHERE id = ?
    2018-10-31 12:11:06[ http-nio-8888-exec-8:17667 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] com.springboot.demo.dao.UserDao.getUserById-debug:159 - ==> Parameters: 1(Long)
    2018-10-31 12:11:06[ http-nio-8888-exec-8:17673 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] com.springboot.demo.dao.UserDao.getUserById-debug:159 - <== Total: 1
    2018-10-31 12:11:06[ http-nio-8888-exec-8:17674 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.mybatis.spring.SqlSessionUtils-closeSqlSession:191 - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1366610e]
    2018-10-31 12:11:06[ http-nio-8888-exec-8:17674 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.springframework.jdbc.datasource.DataSourceUtils-doReleaseConnection:340 - Returning JDBC Connection to DataSource
    2018-10-31 12:11:06[ http-nio-8888-exec-8:17675 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.springframework.web.servlet.view.ContentNegotiatingViewResolver-getMediaTypes:269 - Requested media types are [text/html, application/xhtml+xml, image/webp, application/xml;q=0.9, */*;q=0.8] based on Accept header types and producible media types [*/*])
    2018-10-31 12:11:06[ http-nio-8888-exec-8:17675 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.springframework.web.servlet.view.BeanNameViewResolver-resolveViewName:81 - No matching bean found for view name '/index.html'
    2018-10-31 12:11:06[ http-nio-8888-exec-8:17675 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.springframework.web.servlet.view.ContentNegotiatingViewResolver-getBestView:348 - Returning [org.thymeleaf.spring5.view.ThymeleafView@199e0a7e] based on requested media type 'text/html'
    2018-10-31 12:11:06[ http-nio-8888-exec-8:17675 ]- [zhaozhou] - [d3b60c00-7946-4d5d-bf15-016d286c110c] - [DEBUG] org.springframework.web.servlet.DispatcherServlet-render:1319 - Rendering view [org.thymeleaf.spring5.view.ThymeleafView@199e0a7e] in DispatcherServlet with name 'dispatcherServlet'
    2018-10-31 12:11:06[ http-nio-8888-exec-8:17678 ]- [] - [] - [DEBUG] org.springframework.web.servlet.DispatcherServlet-processRequest:1000 - Successfully completed request
    2018-10-31 12:11:06[ http-nio-8888-exec-8:17678 ]- [] - [] - [DEBUG] org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter-doFilterInternal:104 - Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@4b2bca43
    2018-10-31 12:11:06[ http-nio-8888-exec-1:17767 ]- [] - [] - [DEBUG] org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter-initContextHolders:114 - Bound request context to thread: org.apache.catalina.connector.RequestFacade@4b2bca43
    2018-10-31 12:11:06[ http-nio-8888-exec-1:17767 ]- [] - [] - [DEBUG] org.springframework.web.servlet.DispatcherServlet-doService:891 - DispatcherServlet with name 'dispatcherServlet' processing GET request for [/favicon.ico]
    

    可以看到,开始系统启动过程中是无userName喝reqId打印的,当进行http请求时,MDC配置的两个参数都打印出来,且reqId一直不变,通过此id即可追踪调用链;

    4.4、基于AOP设置MDC

    此种方法所有类型的调用请求的调用跟踪,例如http、基于tcp的RPC调用等;

    4.4.1、pom配置

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    

    4.4.2、切面定义

    @Aspect
    @Component
    public class LoginAop {
    
        private static String MDC_KEY_USER_NAME = "userName";
        private static String MDC_KEY_REQ_ID = "reqId";
    
        @Pointcut("execution(public * com.springboot.demo.controller..*.*(..))")
        public void webLog(){}
    
        @Before("webLog()")
        public void before(JoinPoint joinPoint){
            MDC.put(MDC_KEY_USER_NAME,"zhaozhou");
            MDC.put(MDC_KEY_REQ_ID, UUID.randomUUID().toString());
        }
    
        @AfterReturning(pointcut = "webLog()", returning = "ret")
        public void afterReturning(Object ret){
            MDC.remove(MDC_KEY_USER_NAME);
            MDC.remove(MDC_KEY_REQ_ID);
        }
    }
    
    

    MDC参数与4.3.1配置相同;

    4.4.3、输出结果

    浏览器请求:http://localhost:8888/

    2018-10-31 12:46:24[ http-nio-8888-exec-6:24774 ]- [] - [] - [DEBUG] org.springframework.beans.factory.support.DefaultListableBeanFactory-doGetBean:254 - Returning cached instance of singleton bean 'testController'
    2018-10-31 12:46:24[ http-nio-8888-exec-6:24774 ]- [] - [] - [DEBUG] org.springframework.web.servlet.DispatcherServlet-doDispatch:979 - Last-Modified value for [/] is: -1
    2018-10-31 12:46:24[ http-nio-8888-exec-6:24774 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] org.mybatis.spring.SqlSessionUtils-getSqlSession:97 - Creating a new SqlSession
    2018-10-31 12:46:24[ http-nio-8888-exec-6:24774 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] org.mybatis.spring.SqlSessionUtils-registerSessionHolder:148 - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@675b44f3] was not registered for synchronization because synchronization is not active
    2018-10-31 12:46:24[ http-nio-8888-exec-6:24775 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] org.springframework.jdbc.datasource.DataSourceUtils-doGetConnection:114 - Fetching JDBC Connection from DataSource
    2018-10-31 12:46:24[ http-nio-8888-exec-6:24775 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] org.mybatis.spring.transaction.SpringManagedTransaction-openConnection:87 - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@121b39d5] will not be managed by Spring
    2018-10-31 12:46:24[ http-nio-8888-exec-6:24776 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] com.springboot.demo.dao.UserDao.getUserById-debug:159 - ==> Preparing: select id, name, tel, email, create_time from t_user WHERE id = ?
    2018-10-31 12:46:24[ http-nio-8888-exec-6:24776 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] com.springboot.demo.dao.UserDao.getUserById-debug:159 - ==> Parameters: 1(Long)
    2018-10-31 12:46:24[ http-nio-8888-exec-6:24782 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] com.springboot.demo.dao.UserDao.getUserById-debug:159 - <== Total: 1
    2018-10-31 12:46:24[ http-nio-8888-exec-6:24783 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] org.mybatis.spring.SqlSessionUtils-closeSqlSession:191 - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@675b44f3]
    2018-10-31 12:46:24[ http-nio-8888-exec-6:24783 ]- [zhaozhou] - [519e55f8-45be-4923-a2cc-1b5181eb3050] - [DEBUG] org.springframework.jdbc.datasource.DataSourceUtils-doReleaseConnection:340 - Returning JDBC Connection to DataSource
    2018-10-31 12:46:24[ http-nio-8888-exec-6:24784 ]- [] - [] - [DEBUG] org.springframework.web.servlet.view.ContentNegotiatingViewResolver-getMediaTypes:269 - Requested media types are [text/html, application/xhtml+xml, image/webp, application/xml;q=0.9, */*;q=0.8] based on Accept header types and producible media types [*/*])
    2018-10-31 12:46:24[ http-nio-8888-exec-6:24784 ]- [] - [] - [DEBUG] org.springframework.web.servlet.view.BeanNameViewResolver-resolveViewName:81 - No matching bean found for view name '/index.html'
    

    可以看到,输出与4.3.2基本相同;

    参考源码:https://github.com/zhaozhou11/spring-boot-demo.git

    相关阅读:
    spring-boot基础环境搭建 【https://www.jianshu.com/p/ee36bb9faa10
    spring-boot配置详解【https://www.jianshu.com/p/1d037ab638ef
    spring-boot+druid+mybatis环境搭建【https://www.jianshu.com/p/e6c9e9945e45

    参考博客:

    http://blog.51cto.com/11931236/2058708
    http://tengj.top/2017/04/05/springboot7/
    https://juejin.im/post/5a1f86f0f265da4326529c61
    https://juejin.im/post/5b128f326fb9a01e8b7814c4
    https://blog.csdn.net/Evankaka/article/details/50637994
    https://blog.csdn.net/wohaqiyi/article/details/72853962
    https://blog.csdn.net/wohaqiyi/article/details/72853962
    https://my.oschina.net/gmd/blog/615849
    https://www.jianshu.com/p/44640b298c45
    https://blog.csdn.net/u012050154/article/details/77370297

    相关文章

      网友评论

        本文标题:(4) spring-boot+logback+log4j2+M

        本文链接:https://www.haomeiwen.com/subject/pjkatqtx.html