全局日志记录traceId

全局日志记录traceId

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

定义过滤器

@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定义日志文件的输出格式

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

全局响应值里增加traceId

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,重写提交任务的方法

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上下文。

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();
            }
        };
    }
}
作者:Yuyy
博客:https://yuyy.info
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇