背景:
在日常开发代码的过程中,涉及到跨服务的请求时,追踪日志往往成为一件很麻烦的事,使用traceId可将全部的日志都串联起来,方便排查问题。
实现步骤:
1.首先在前台或者管理后台通过自定义拦截器,从header中获取一个traceID,没有则设置一个uuid为traceId,把traceID放在MDC中
/**
* 注入自定义拦截器
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Resource
private LogInterceptor logInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(logInterceptor).addPathPatterns("/**");
}
}
/**
* 实现拦截器内容
* 这里简单的设置一个traceID
*/
@Service
public class LogInterceptor extends HandlerInterceptorAdapter {
private static final String TRACE_ID = "traceId";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String traceId = request.getHeader(TRACE_ID);
if (StringUtils.isEmpty(traceId)) {
traceId = UUID.randomUUID().toString();
MDC.put(TRACE_ID, traceId);
} else {
MDC.put(TRACE_ID, traceId);
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//防止内存泄露
MDC.remove(TRACE_ID);
}
}
2.使用feign实现远程调用时,可以通过实现RequestInterceptor接口的apply方法在请求中设置traceID,这样前台的traceID就可以传递到中台,实现前中台的traceId都是同一个,达到串联日志的效果。
/**
* 调用前从 MDC中获取上一步骤设置的traceId,放置到 header中,供下一个服务从header中获取traceId
*/
@Configuration
public class FeignInterceptor implements RequestInterceptor {
private static final String TRACE_ID = "traceId";
@Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header(TRACE_ID, (String) MDC.get(TRACE_ID));
}
}
注:很多服务中在logback.xml打印日志时都是用了彩色的日志格式,使用这个格式后必须在格式中设置traceId的打印 %boldYellow(traceId - %X{traceId}) ,否则无法打印traceID。
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN"
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %boldYellow(traceId - %X{traceId}) %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>