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