logback打印日志输出线程ID:mvc拦截器模式

一、前言

经常处理业务问题的同仁,一定都经常与日志打交道。当并发量高、多线程编程时,日志往往是一大堆,为了快速精确的定位、处理问题,我们需要区分各个用户的不同会话请求,需要从一坨坨日志中做链路追踪。

思路:在输出日志的时候,将每个线程的ID同时输出,当然前提是保证每个线程的ID是唯一的。sl4j 提供的一个工具类MDC,支持 logback和log4j,作用就是扩展变量值到日志中并输出。

二、MVC拦截器模式输出线程ID

  1. 加入POM引用
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

     

  2. 自定义日志拦截器
    package cn.wuhg.climbing.service.design.patterns.sessionid.mvcfilter;
    
    import lombok.extern.slf4j.Slf4j;
    import org.slf4j.MDC;
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.UUID;
    
    /**
     * 日志拦截器
     */
    @Slf4j
    @Component
    public class LogInterceptor implements HandlerInterceptor {
        // 会话ID
        private final static String SESSION_ID = "sessionId";
    
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) {
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            MDC.put(SESSION_ID, uuid);
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) {
            MDC.remove(SESSION_ID);
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        }
    }
    

     

  3. 重写MCV过滤器
    package cn.wuhg.climbing.service.design.patterns.sessionid.mvcfilter;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    @Configuration
    public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
        @Autowired
        private LogInterceptor logInterceptor;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(logInterceptor);
            super.addInterceptors(registry);
        }
    }
    

     

  4. logback配置
    ​
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <contextName>SpringBootDemo</contextName>
        <property name="LOG_PATH" value="ToolLogs" />
        <!--设置系统日志目录 -->
        <property name="APPDIR" value="design-patterns" />
        <!-- 日志记录器,日期滚动记录 -->
        <appender name="FILEALL"
    		class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${LOG_PATH}/${APPDIR}/logs.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}/logs-%d{yyyy-MM-dd}.%i.log
    			</fileNamePattern>
                <!-- 除按日志记录之外,还配置了日志文件不能超过20M,若超过20M,日志文件会以索引0开始, 命名日志文件,例如log-error-2013-12-21.0.log -->
                <timeBasedFileNamingAndTriggeringPolicy
    				class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>20MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <!-- 追加方式记录日志 -->
            <append>true</append>
            <!-- 日志文件的格式 -->
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{sessionId}] %-5level %class.%method Line:%-3L - %msg%n</pattern>
                <charset>utf-8</charset>
            </encoder>
        </appender>
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <!--encoder 默认配置为PatternLayoutEncoder -->
            <encoder>
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{sessionId}] %-5level %class.%method Line:%-3L - %msg%n</pattern>
                <charset>utf-8</charset>
            </encoder>
            <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息 -->
            <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                <level>debug</level>
            </filter>
        </appender>
        <!-- 生产环境下,将此级别配置为适合的级别,以免日志文件太多或影响程序性能 -->
        <root level="INFO">
            <appender-ref ref="FILEALL" />
            <appender-ref ref="STDOUT" />
        </root>
    </configuration>
    
    ​

     

  5. Controller接口
    ​
    @LogId
    @GetMapping("/log")
        public void logId(){
        log.info("测试slf4j日志线程ID");
    }
    
    ​

     

  6. 日志截图

三、往期推荐

logback打印日志输出线程ID:切面模式

 

作者:Smile潇洒Tel 

转载请注明出处,谢谢合作!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章