专栏名称: ImportNew
伯乐在线旗下账号,专注Java技术分享,包括Java基础技术、进阶技能、架构设计和Java技术领域动态等。
目录
相关文章推荐
51好读  ›  专栏  ›  ImportNew

使用 MDC 实现日志链路跟踪

ImportNew  · 公众号  · Java  · 2024-05-25 11:30

正文

请到「今天看啥」查看全文



@Override public void afterCompletion (HttpServletRequest request, HttpServletResponse response, Object handler, Exception arg3) throws Exception { }
@Override public void postHandle (HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView arg3) throws Exception { }
@Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String traceId = request.getHeader(TRACE_ID); if (StringUtils.isEmpty(traceId)) { MDC.put(TRACE_ID, UUID.randomUUID().toString()); } else { MDC.put(TRACE_ID, traceId); } return true ; } }



3)配置拦截器



@Configurationpublic class WebConfig implements WebMvcConfigurer {    @Resource    private LogInterceptor logInterceptor;
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(logInterceptor).addPathPatterns("/**"); }}


4.3 traceId 如何在服务间传递


封装 HTTP 工具类,把 traceId 加入头中,带到下一个服务。



@Slf4jpublic class HttpUtils {    public static String get(String url) throws URISyntaxException {        RestTemplate restTemplate = new RestTemplate();        MultiValueMap<String, String> headers = new HttpHeaders();        headers.add("traceId", MDC.get("traceId"));        URI uri = new URI(url);        RequestEntity> requestEntity = new RequestEntity<>(headers, HttpMethod.GET, uri);        ResponseEntity exchange = restTemplate.exchange(requestEntity, String.class);        if (exchange.getStatusCode().equals(HttpStatus.OK)) {            log.info("send http request success");        }        return exchange.getBody();    }}


4.4 traceId 如何在多线程中传递?


Spring 项目也使用到了很多线程池,比如 @Async 异步调用,Zookeeper 线程池、 Kafka 线程池等。不管是哪种线程池都大都支持传入指定的线程池实现, @Async 举例:


原理为:


MDC 底层使用 Thread Local 来实现,那根据 Thread Local 的特点,它是可以让我们在同一个线程中共享数据的,但是往往我们在业务方法中,会开启多线程来执行程序,这样的话 MDC 就无法传递到其他子线程了。这时,我们需要使用额外的方法来传递存在 Thread Local 里的值。


MDC 提供了一个叫 getCopyOfContextMap 的方法,很显然,该方法就是把当前线程 Thread Local 绑定的Map获取出来,之后就是把该 Map 绑定到子线程中的ThreadLocal 中了。


改造 Spring 的异步线程池,包装提交的任务。



@Slf4j@Componentpublic class TraceAsyncConfigurer implements AsyncConfigurer {    @Override    public Executor getAsyncExecutor() {        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();        executor.setCorePoolSize(8);        executor.setMaxPoolSize(16);        executor.setQueueCapacity(100);        executor.setThreadNamePrefix("async-pool-");        executor.setTaskDecorator(new MdcTaskDecorator());        executor.setWaitForTasksToCompleteOnShutdown(true);        executor.initialize();






请到「今天看啥」查看全文