SpringBoot项目traceId生成/日志打印

本文介绍了如何在SpringBoot项目中实现traceId,以解决多线程日志难以关联的问题。通过使用MDC(Mapped Diagnostic Context),在请求开始时设置traceId,结束时清除,确保每个请求都有唯一的标识。文中提供了Filter和Interceptor两种实现方式,并展示了如何将traceId添加到日志打印中,以及处理异步方法时保持traceId的一致性。此外,还讨论了如何在响应DTO中返回traceId,便于前端展示和追踪请求。
摘要由CSDN通过智能技术生成

参考文章 : W3C_0101博文链接

前言
查看服务日志时,当服务被调过于频繁,日志刷新太快,会影响到联调、测试、线上问题的排查效率,能不能为每一个请求的日志打一个唯一标识呢?后面使用该表示去匹配,直接检索出该请求的日志?引入本文的正题,“traceId”。

image
MDC
MDC定义 Mapped Diagnostic Context,即:映射诊断环境。

MDC是 log4j 和 logback 提供的一种方便在多线程条件下记录日志的功能。

MDC 可以看成是一个与当前线程绑定的哈希表,可以往其中添加键值对。

MDC的使用方法

​ 向MDC设置值:MDC.put(key, value);

​ 从MDC中取值:MDC.get(key);

​ 将MDC中的内容打印到日志中:%X{key};

初始化TraceId并向MDC设置值
这里主要是利用切面,方法执行前设置MDC,方法执行后擦除MDC。具体实现方式有很多,如过滤器、拦截器、AOP等等。个人比较推荐Filter实现,因为Filter是请求最先碰到的,也是响应给前端前最后一个碰到的。

过滤器实现
@Slf4j
@WebFilter(filterName = “traceIdFilter”, urlPatterns = “/*”)
@Order(0)
@Component
public class TraceIdFilter implements Filter {
/**
* 日志跟踪标识
*/
public static final String TRACE_ID = “TRACE_ID”;

@Override
public void init(FilterConfig filterConfig) {
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
        throws IOException, ServletException {
    MDC.put(TRACE_ID, UUID.randomUUID().toString());
    filterChain.doFilter(servletRequest, servletResponse);
}

@Override
public void destroy() {
    MDC.clear();
}

}
拦截器实现
@Component
public class TraceIdInterceptor extends HandlerInterceptorAdapter {
private static final String TRACE_ID = “TRACE_ID”;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    MDC.put(TRACE_ID, UUID.randomUUID().toString());
    return true;
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) {
    MDC.clear();
}

}

@Configuration
public class WebConfig implements WebMvcConfigurer {

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new TraceIdInterceptor());
}

}
日志打印配置pattern中配置traceId
与之前的相比只是添加了[%X{TRACE_ID}], [%X{***}]是一个模板,中间属性名是我们使用MDC put进去的。

%d{yyyy-MM-dd} [%thread] %-5level %logger{50} - [%X{TRACE_ID}] - %msg%n
异步方法的日志打印traceId
异步方法会开启一个新线程,我们想要是异步方法和主线程共用同一个traceId,首先先新建一个任务适配器MdcTaskDecorator。

public class MdcTaskDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
Map<String, String> map = MDC.getCopyOfContextMap();
return () -> {
try {
MDC.setContextMap(map);
String traceId = MDC.get(TRACE_ID);
if (StringUtils.isBlank(traceId)) {
traceId = UUID.randomUUID().toString();
MDC.put(TRACE_ID, traceId);
}
runnable.run();
} finally {
MDC.clear();
}
};
}
}
在线程池配置中增加executor.setTaskDecorator(new MdcTaskDecorator())的设置

@EnableAsync
@Configuration
public class ThreadPoolConfig {
private int corePoolSize = Runtime.getRuntime().availableProcessors() + 1;
private int maxPoolSize = corePoolSize * 2;
private static final int queueCapacity = 50;
private static final int keepAliveSeconds = 30;

@Bean(name = "threadPoolTaskExecutor")
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setMaxPoolSize(maxPoolSize);
    executor.setCorePoolSize(corePoolSize);
    executor.setQueueCapacity(queueCapacity);
    executor.setKeepAliveSeconds(keepAliveSeconds);
    executor.setTaskDecorator(new MdcTaskDecorator());
    executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    return executor;
}

}
使用指定的线程池执行业务代码

@Async(“threadPoolTaskExecutor”)
public void testThreadPoolTaskExecutor(){
log.info(“Async 测试一下”);
}
在响应DTO中返回traceId

@Data
@AllArgsConstructor
public class RetResult {

private Integer code;

private String msg;

private T data;

private String traceId;

public RetResult(Integer code, String msg, T data) {
    this.code = code;
    this.msg = msg;
    this.data = data;
    this.traceId = MDC.get(TRACE_ID);
}

public static <T> RetResult<T> success(T t) {
    return new RetResult<>(RetCode.SUCCESS.getCode(), "ok", t);
}

public static <T> RetResult<T> success() {
    return new RetResult<>(RetCode.SUCCESS.getCode(), "ok", null);
}

public static <T> RetResult<T> fail() {
    return new RetResult<>(RetCode.FAIL.getCode(), "fail", null);
}

public static <T> RetResult<T> fail(String msg) {
    return new RetResult<>(RetCode.FAIL.getCode(), msg, null);
}

public static <T> RetResult<T> fail(Integer code, String msg) {
    return new RetResult<>(code, msg, null);
}

}
http://www.gzslpzx.com/poser.php?175517.html
http://nd.fjmj.org.cn/uploadfile/2020/poser.php?175517.html
http://sz.fjmj.org.cn/uploadfile/2020/poser.php?175517.html
http://na.fjmj.org.cn/uploadfile/2020/poser.php?175517.html
http://zz.fjmj.org.cn/uploadfile/2020/poser.php?175517.html
http://np.fjmj.org.cn/uploadfile/2020/poser.php?175517.html
http://mdzz.itlun.cn/poser.php?175517.html
http://www.xalsh.com/poser.php?175517.html
http://www.gjtuofa.com/uploads/poser.php?175517.html
http://www.yqyy.net/poser.php?175517.html
http://www.bxysg.com/poser.asp?175517.html
http://www.linkcard.cn/poser.asp?175517.html
http://www.airber.com.cn/poser.asp?175517.html
http://www.milient.com/poser.asp?175517.html
http://www.moswe.com/poser.asp?175517.html
http://1798.rongbiz.net/poser.php?175517.html
http://bbs.6y.com.cn/poser.php?175517.html
http://game.6y.com.cn/poser.php?175517.html
http://www.hnalizs.com/poser.php?175517.html
http://www.hnhcnet.com/poser.php?175517.html
http://dxkj.designboom.cn/poser.php?175517.html
http://www.designboom.cn/poser.php?175517.html
http://www.zhjswhw.com/poser.php?175517.html
http://www.gdnhec.com/poser.php?175517.html
http://www.qqql.com.cn/poser.asp?175517.html
http://www.ogood.cn/poser.php?175517.html
http://www.lygwb.com/poser.php?175517.html
http://mzhihui.mulangcm.com/fw/poser.php?175517.html
http://www.ceht.com.cn/default.php?175517.html
http://www.aselock.com.cn/poser.asp?175517.html
http://www.spark-lock.com/poser.asp?175517.html
http://www.fsruijian.net/poser.php?175517.html
http://www.whbts.com/poser.asp?175517.html
http://www.xdmonitor.com/poser.asp?175517.html
http://m.cquedp.com/175517.html
http://cquedp.com/175517.html
http://mdzz.itlun.cn/175517.html
http://m.cntricycle.com/175517.html
http://www.cquedp.com/poser.php?175517.html
http://szgc.glodon.com/poser.php?175517.html
http://sz.glodon.com/poser.php?175517.html
http://www.gzslpzx.com/poser.php?084082.html
http://nd.fjmj.org.cn/uploadfile/2020/poser.php?084082.html
http://sz.fjmj.org.cn/uploadfile/2020/poser.php?084082.html
http://na.fjmj.org.cn/uploadfile/2020/poser.php?084082.html
http://zz.fjmj.org.cn/uploadfile/2020/poser.php?084082.html
http://np.fjmj.org.cn/uploadfile/2020/poser.php?084082.html
http://mdzz.itlun.cn/poser.php?084082.html
http://www.xalsh.com/poser.php?084082.html
http://www.gjtuofa.com/uploads/poser.php?084082.html
http://www.yqyy.net/poser.php?084082.html
http://www.bxysg.com/poser.asp?084082.html
http://www.linkcard.cn/poser.asp?084082.html
http://www.airber.com.cn/poser.asp?084082.html
http://www.milient.com/poser.asp?084082.html
http://www.moswe.com/poser.asp?084082.html
http://1798.rongbiz.net/poser.php?084082.html
http://bbs.6y.com.cn/poser.php?084082.html
http://game.6y.com.cn/poser.php?084082.html
http://www.hnalizs.com/poser.php?084082.html
http://www.hnhcnet.com/poser.php?084082.html
http://dxkj.designboom.cn/poser.php?084082.html
http://www.designboom.cn/poser.php?084082.html
http://www.zhjswhw.com/poser.php?084082.html
http://www.gdnhec.com/poser.php?084082.html
http://www.qqql.com.cn/poser.asp?084082.html
http://www.ogood.cn/poser.php?084082.html
http://www.lygwb.com/poser.php?084082.html
http://mzhihui.mulangcm.com/fw/poser.php?084082.html
http://www.ceht.com.cn/default.php?084082.html
http://www.aselock.com.cn/poser.asp?084082.html
http://www.spark-lock.com/poser.asp?084082.html
http://www.fsruijian.net/poser.php?084082.html
http://www.whbts.com/poser.asp?084082.html
http://www.xdmonitor.com/poser.asp?084082.html
http://m.cquedp.com/084082.html
http://cquedp.com/084082.html
http://mdzz.itlun.cn/084082.html
http://m.cntricycle.com/084082.html
http://www.cquedp.com/poser.php?084082.html
http://szgc.glodon.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值