日志链路跟踪

方案

链路跟踪有几个方面的问题需要考虑

  1. 应用内跟踪(MDC)
  2. 服务调用跟踪(HTTP)

实现

日志拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class LogInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//如果有上层调用就用上层的ID
String traceId = request.getHeader(Constants.TRACE_ID);
if (traceId == null) {
traceId = TraceIdUtil.getTraceId();
}

MDC.put(Constants.TRACE_ID, traceId);
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
//调用结束后删除
MDC.remove(Constants.TRACE_ID);
}
}
1
2
3
4
5
6
7
8
9
@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
//实现拦截器 要拦截的路径以及不拦截的路径
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册自定义拦截器,添加拦截路径和排除拦截路径
registry.addInterceptor(new LogInterceptor()).addPathPatterns("/**");
}
}

HttpClient拦截器

1
2
3
4
5
6
7
8
9
10
11
public class HttpClientTraceIdInterceptor implements HttpRequestInterceptor {
@Override
public void process(HttpRequest httpRequest, HttpContext httpContext) throws HttpException, IOException {
String traceId = MDC.get(Constants.TRACE_ID);
//当前线程调用中有traceId,则将该traceId进行透传
if (traceId != null) {
//添加请求体
httpRequest.addHeader(Constants.TRACE_ID, traceId);
}
}
}
1
2
3
private static CloseableHttpClient httpClient = HttpClientBuilder.create()
.addInterceptorFirst(new HttpClientTraceIdInterceptor())
.build();

OkHttp拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class OkHttpTraceIdInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
String traceId = MDC.get(Constants.TRACE_ID);
Request request = null;
if (traceId != null) {
//添加请求体
request = chain.request().newBuilder().addHeader(Constants.TRACE_ID, traceId).build();
}
Response originResponse = chain.proceed(request);

return originResponse;
}
}
1
2
3
private static OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new OkHttpTraceIdInterceptor())
.build();

RestTemplate拦截器

1
2
3
4
5
6
7
8
9
10
11
public class RestTemplateTraceIdInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
String traceId = MDC.get(Constants.TRACE_ID);
if (traceId != null) {
httpRequest.getHeaders().add(Constants.TRACE_ID, traceId);
}

return clientHttpRequestExecution.execute(httpRequest, bytes);
}
}
1
restTemplate.setInterceptors(Arrays.asList(new RestTemplateTraceIdInterceptor()));

参考