实现方案
- NDC:基于堆寨,将调用链ID存入堆寨中,但是每次调用结束后需要手动清理
- MDC:基于MAP,调用链ID放入MAP中,优点调用结束后不需要手动清理
- 扩展类PatternLayout,重写finalizeConverter方法
实现
对比之后选择通过MDC方式来实现:
- 通过spring拦截器,拦截所有请求,将自定义生成的调用链ID存入到MDC中,同时放入到线程中,后面调用别的服务的时候可以从线程中获取到,形成完整的调用链
- 设置log4j2配置文件打印格式内容为%X{调用链ID}。
<Property name="LOG_PATTERN_HEAD">%d{yyyy-MM-dd HH:mm:ss.SSS}$$[${hostName}]$$%p$$[${serviceName}]$$%t$$%M$$%c$$%X{调用链ID}$$</Property>
@Component
@Log4j2
public class AtomicInterceptor extends HandlerInterceptorAdapter {
private boolean setConsoleContext(HttpServletRequest request) {
try {
ConsoleContext context = new ConsoleContext();
context.setRequest(request);
context.setBeginMs(System.currentTimeMillis());
// 创建调用链ID的公共方法
traceID = TraceUtil.newTraceId();
context.setTraceId(traceID);
MDC.put("traceID", traceID);
if(StringUtils.isNotBlank(traceMD5)){
context.setTraceMD5(traceMD5);
MDC.put("traceMD5", traceMD5);
}
// 放入线程中,方便后面调用别的服务获取传入到别的方服务,形成完整的调用链
ThreadLocalManager.setConsoleContext(context);
} catch (Exception e) {
log.error("error in preHandle getUser. url is:"+request.getRequestURL(), e);
return false;
}
return true;
}