使用Mdc解决链路追踪

用aop 拦截所有controller 的请求 生成全局traceId

@Pointcut("execution(* *.*.controller..*.*(..))")

public void cutOffPoint() {

}

@Before("cutOffPoint()")

public void doBefore(JoinPoint joinPoint)throws Throwable {

 MDC.put("traceId", "生成全局traceid"); 

}

在logback.xml中配置 

            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %X{TRACEID}- %msg%n

到此可以满足大部分的需求

需要注意的部分就是如果用到线程池需要特殊处理

可以参考

https://blog.csdn.net/yangcheng33/article/details/80796129

下面说下我的实现 

项目中主要使用ThreadPoolTaskExecutor因此对他进行改造

复制public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport

implements AsyncListenableTaskExecutor, SchedulingTaskExecutor {

//内容为ThreadPoolTaskExecutor  类中的内容 我这里从新写了一下几个方法

initializeExecutor 方法中  super.execute(new MDCRunnable(decorated))

submitListenable方法中 

ListenableFutureTask future =new ListenableFutureTask<>(new MDCCallable<>(task));

//住所有执行的方法都要改为MDCRunnable MDCCallable

}

MDCRunnable类 为

public class MDCRunnable implements Runnable {

private final Runnable runnable;

    private transient final Map_cm = MDC.getCopyOfContextMap();

    public MDCRunnable(Runnable runnable) {

        this.runnable = runnable;

    }

@Override

    public void run() {

if (_cm !=null) {

             MDC.setContextMap(_cm);

        }

try {

runnable.run();

        }finally {

MDC.clear();

        }}}

public class MDCCallable implements Callable {

private final Callablecallable;

    private transient final Map_cm = MDC.getCopyOfContextMap();

    public MDCCallable(Callable callable) {

this.callable = callable;

    }

@Override

    public V call()throws Exception {

if (_cm !=null) {

MDC.setContextMap(_cm);

        }

try {

return callable.call();

        }finally {

MDC.clear();

        }}}

至此我们项目中就完美解决了traceId在本项目中传递

如果是在微服务中传递则 我们微服务之间的调用使用的restTemplate

所有增加一个拦截器

@Configuration

public class RestTemplateConfiguration {

@Bean

@LoadBalanced

    public RestTemplateloadbalancedRestTemplate() {

SimpleClientHttpRequestFactory requestFactory =new SimpleClientHttpRequestFactory();

        // 超时时间,单位毫秒

        requestFactory.setConnectTimeout(3 *1000);

        requestFactory.setReadTimeout(3 *60 *1000);

        RestTemplate restTemplate =new RestTemplate(requestFactory);

        restTemplate.getInterceptors().add(new TraceIdInterceptor());

        return restTemplate;

    }


public class TraceIdInterceptorimplements ClientHttpRequestInterceptor {

@Override

    public ClientHttpResponseintercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)throws IOException {

HttpHeaders headers = request.getHeaders();

        traceId= MDC.get("traceId");

        if(StringUtils.isNotBlank(traceId)){

headers.add("traceId",traceId);

        }

return execution.execute(request,body);

    }}}


然后在下游服务器写一个拦截器就可在request head中可以获取traceidl 

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

String traceId = request.getHeader("traceId");


至此就完成了所有的traceid 本项目 线程 项目之间 都可以用了

你可能感兴趣的:(使用Mdc解决链路追踪)