SpringBoot MDC

SpringBoot MDC

在程序中,日志一直是一个至关重要的部分,排查问题、统计数据…

解决问题

SpringBoot添加全局自定义日志链路信息。

1.过滤器,拦截指定请求,可取出参数、请求头等信息,可根据业务自定义添加进日志进程(MDC)

2.时间拦截器,根据注解进行拦截,向进程日志(MDC)中,注入方法执行时间。

3.具体业务,可自行向进程日志(MDC)中注入所需信息。

1.MDCFilter

请求过滤器,用于向MDC中添加请求头等信息。


/**
 * 拦截请求信息,添加到日志
 *
 * @author litong
 * @date 2020/7/23 10:46
 */
@Component
@Log4j2
@Order(2)
@AllArgsConstructor
public class MDCFilter extends OncePerRequestFilter {
    
    

    private MDCLogProperties mdcLogProperties;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
    
    
        try {
    
    
            MDC.put(mdcLogProperties.getHeaderSessionKey(),
                    request.getHeader(mdcLogProperties.getHeaderSessionKey())
            );
            MDC.put("url", request.getRequestURI());
            chain.doFilter(request, response);
        } finally {
    
    
            MDC.clear();
        }
    }
}

2.ApiTimerLog

注解,用于标注需要打印方法执行时间的标识。

/**
 * 时间记录annotation
 * 标注需要记录时间消耗的方法
 *
 * @author litong
 * @date 2020/7/23 15:30
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiTimerLog {
    
    
}

3.TimeAspect

时间切片

/**
 * @author litong
 * @date 2020/7/23 15:31
 */
@Aspect
@Component
@Slf4j
public class TimeAspect {
    
    

    // 修正Timer注解的全局唯一限定符
    @Pointcut("@annotation(com.ltz.ltzg.common.log.annotation.ApiTimerLog)")
    private void pointcut() {
    
    
    }

    // 按包注入
//    @Around("execution(* com.ltz.ltzg.auth.controller.*.*(..))" +
//            "|| execution(* com.ltz.ltzg.api.controller.*.*(..))")

    // 按注解注入
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    
    

        // 开始时间
        long start = System.currentTimeMillis();

        // 调用目标方法
        Object result = R.err(ErrorEnums.SHOW_FAIL);
        try {
    
    
            result = joinPoint.proceed();
        } catch (Throwable throwable) {
    
    
            throw throwable;
        } finally {
    
    
            // 获取执行时间
            long end = System.currentTimeMillis();
            long time = end - start;
            MDC.put("executionTime", time + "");

            R result1 = new R();
            try {
    
    
                result1 = (R) result;
            } catch (Exception e) {
    
    
            }
            MDC.put("errcode", result1.getCode() + "");
            log.info("Api-Link");
        }

        return result;
    }
}

4.logback-local.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--该日志将日志级别不同的log信息保存到不同的文件中 -->
<configuration>
   <include resource="org/springframework/boot/logging/logback/defaults.xml" />
   <include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
   <include resource="org/springframework/boot/logging/logback/file-appender.xml"/>

   <springProperty scope="context" name="springAppName"
      source="spring.application.name" />

   <!-- 日志在工程中的输出位置 -->
   <property name="LOG_FILE" value="C:/data/logs/${springAppName}" />
   <!--<property name="LOG_FILE" value="/data/ltz/logs/${springAppName}" />-->

   <!-- 控制台的日志输出样式 -->
   <property name="CONSOLE_LOG_PATTERN"
      value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- })[%thread] [url=%X{url};ltz-token=%X{ltz-token};executionTime=%X{executionTime};errcode=%X{errcode}] {magenta} %clr(---){faint} %clr([%15.15t]){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" />

   <!-- 控制台输出 -->
   <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
      <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
         <level>INFO</level>
      </filter>
      <!-- 日志输出编码 -->
      <encoder>
         <pattern>${CONSOLE_LOG_PATTERN}</pattern>
         <charset>utf8</charset>
      </encoder>
   </appender>

   <!-- 文件输出 -->
   <appender name="localfile" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <file>${LOG_FILE}.json</file>
      <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
         <fileNamePattern>${LOG_FILE}.json.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
         <maxFileSize>${LOG_FILE_MAX_SIZE:-1000MB}</maxFileSize>
         <maxHistory>${LOG_FILE_MAX_HISTORY:-7}</maxHistory>
      </rollingPolicy>
      <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
         <level>INFO</level>
      </filter>
    <encoder>
      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [url=%X{url};ltz-token=%X{ltz-token};executionTime=%X{executionTime};errcode=%X{errcode}]  %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>
   <!-- sql文件输出 -->
   <appender name="sqlfile" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <file>${LOG_FILE}.sqllog</file>
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.sqlLog</fileNamePattern>
      <maxHistory>3</maxHistory>
      </rollingPolicy>
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>

   <!-- 日志输出级别 -->
   <root level="INFO">
      <appender-ref ref="console" />
      <appender-ref ref="localfile"/>
   </root>

   <logger name="dao" level="debug" additivity="false">
        <appender-ref ref="sqlfile" />
   </logger>
</configuration>

5.日志模板说明

MDC中添加的key,需要在日志模板中,用%X{url}的方式,打印。

使用案例

/**
 * @author litong
 * @date 2020/6/1 17:10
 */
@RequestMapping("/test")
@RestController
public class TestController {
    
    


    @ApiTimerLog
    @GetMapping("/a")
    public R a() {
    
    
        return R.ok("a");
    }
}

日志输出

2020-07-27 13:41:16.960  INFO 24052[http-nio-18989-exec-5] [url=/test/a;ltz-token=123;executionTime=0;errcode=1000]{magenta} --- [io-18989-exec-5] Api-Link

猜你喜欢

转载自blog.csdn.net/LitongZero/article/details/107610129