前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >全局日志记录traceId

全局日志记录traceId

作者头像
Yuyy
发布2022-09-21 10:11:56
7940
发布2022-09-21 10:11:56
举报

全局日志记录traceId

单体应用为了更方便的排查问题,使用过滤器+日志框架的MDC功能,实现每个请求产生的日志,都包含一个UUID。

定义过滤器

代码语言:javascript
复制
@Component
@Order(1)
public class TraceFilter extends OncePerRequestFilter {

    public static final String TRACE_ID = "traceId";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        MDC.put(TRACE_ID, getTraceId());
        filterChain.doFilter(request, response);
    }

    public static String getTraceId() {
        return IdUtil.simpleUUID();
    }

}
  • 在以线程为维度的上下文中,放入traceId

logback定义日志文件的输出格式

代码语言:javascript
复制
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} | traceId=%X{traceId} | [%thread] %-5level %logger{50} - %msg%n" />

全局响应值里增加traceId

代码语言:javascript
复制
public ResponseDTO(Integer code,String msg,T data) {
    this.code = code;
    this.msg = msg;
    this.data=data;
    this.timestamp = new Date();
    this.traceId = MDC.get(TraceFilter.TRACE_ID);
}

问题

如果项目里使用了异步、并发处理多任务,就会产生子线程。子线程需要继承父线程的MDC上下文才能使用traceId。

手动创建线程

这种不考虑,本来就是不推荐的写法。

使用线程池

继承ThreadPoolTaskExecutor,重写提交任务的方法

代码语言:javascript
复制
public class ThreadPoolExecutorMdcWrapper extends ThreadPoolTaskExecutor {

    @Override
    public void execute(Runnable task) {
        super.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
    }

    @Override
    public void execute(Runnable task, long startTimeout) {
        super.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()), startTimeout);
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
    }

    @Override
    public Future<?> submit(Runnable task) {
        return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
    }
}

执行提交的任务前后都处理下,继承父线程的MDC上下文。

代码语言:javascript
复制
public class ThreadMdcUtil {
    public static void setTraceIdIfAbsent() {
        if (MDC.get(TraceFilter.TRACE_ID) == null) {
            MDC.put(TraceFilter.TRACE_ID, TraceFilter.getTraceId());
        }
    }

    public static <T> Callable<T> wrap(final Callable<T> callable, final Map<String, String> context) {
        return () -> {
            if (context == null) {
                MDC.clear();
            } else {
                MDC.setContextMap(context);
            }
            setTraceIdIfAbsent();
            try {
                return callable.call();
            } finally {
                MDC.clear();
            }
        };
    }

    public static Runnable wrap(final Runnable runnable, final Map<String, String> context) {
        return () -> {
            if (context == null) {
                MDC.clear();
            } else {
                MDC.setContextMap(context);
            }
            setTraceIdIfAbsent();
            try {
                runnable.run();
            } finally {
                MDC.clear();
            }
        };
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-1-03 2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 全局日志记录traceId
    • 定义过滤器
      • logback定义日志文件的输出格式
        • 全局响应值里增加traceId
          • 问题
            • 手动创建线程
            • 使用线程池
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档