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

一、前言

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

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

二、切面模式输出线程ID

通过自定义切面,拦截有注解@LogId的请求,附加会话ID输出到日志。

  1. 加入POM引用
    
        org.springframework.boot
        spring-boot-starter-aop
        
            
                ch.qos.logback
                logback-classic
            
        
    

     

  2. 自定义切点
    package cn.wuhg.climbing.service.design.patterns.sessionid.aspect;
    
    import java.lang.annotation.*;
    
    /**
     * 自定义日志注解
     */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface LogId {
        String value() default "";
    }
    

     

  3. 自定义日志切面
    package cn.wuhg.climbing.service.design.patterns.sessionid.aspect;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.slf4j.MDC;
    import org.springframework.stereotype.Component;
    
    import java.util.UUID;
    
    /**
     * 自定义日志切面
     */
    @Aspect
    @Component
    public class LogAspect {
        private final static String SESSION_ID = "sessionId";
    
        /**
         * 自定义切点
         */
        @Pointcut("@annotation(cn.wuhg.climbing.service.design.patterns.sessionid.aspect.LogId)")
        public void pointCut() {
        }
    
        /**
         *  前置通知-记录请求信息
         * @param joinPoint
         */
        @Before("pointCut()")
        public void doBeforeAdvice(JoinPoint joinPoint) {
            // MDC容器增加requestId
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            MDC.put(SESSION_ID, uuid);
    
        }
    
        /**
         * 后置通知-记录返回信息
         * @param joinPoint
         * @param result
         */
        @AfterReturning(pointcut = "pointCut()", returning = "result")
        public void doAfterReturningAdvice(JoinPoint joinPoint, Object result) {
            MDC.remove(SESSION_ID);
        }
    
        /**
         * 后置异常通知-记录返回出现异
         * @param joinPoint
         * @param exception
         */
        @AfterThrowing(value = "pointCut()", throwing = "exception")
        public void doAfterThrowingAdvice(JoinPoint joinPoint, Throwable exception) {
            MDC.remove(SESSION_ID);
        }
    
    }
    
    

     

  4. logback配置
    
    
        SpringBootDemo
        
        
        
        
        
            ${LOG_PATH}/${APPDIR}/logs.log
            
            
                
                ${LOG_PATH}/${APPDIR}/logs-%d{yyyy-MM-dd}.%i.log
    			
                
                
                    20MB
                
            
            
            true
            
            
                %d{yyyy-MM-dd HH:mm:ss.SSS} [%X{sessionId}] %-5level %class.%method Line:%-3L - %msg%n
                utf-8
            
        
        
            
            
                %d{yyyy-MM-dd HH:mm:ss.SSS} [%X{sessionId}] %-5level %class.%method Line:%-3L - %msg%n
                utf-8
            
            
            
                debug
            
        
        
        
            
            
        
    

     

  5. Controller接口
    @LogId
    @GetMapping("/log")
        public void logId(){
        log.info("测试slf4j日志线程ID");
    }
  6. 日志截图,红框处是会话ID
  7. 整体切面过滤
    可以通过制定路径范围,来整体过滤,去除了@LogId注解的限制,仅需将自定义切面替换即可
    @Pointcut("execution(public * cn.wuhg.climbing.service.design.patterns..*(..))")
        public void pointCut() {
    }

三、往期推荐

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

 

作者:Smile潇洒Tel 

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

你可能感兴趣的:(logback,slf4j,logback,slf4j,java,aop,线程ID)