首页 > 其他分享 >跨线程(线程池)日志链路追踪

跨线程(线程池)日志链路追踪

时间:2022-09-06 14:35:32浏览次数:73  
标签:task MDC submit 线程 链路 日志 super public

不跨线程的业务日志链路我们可以通过日志框架如Logback  使用MDC对象放入一个traceId,再在日志配置文件配置即可 但如跨线程的话traceid无法传递(MDC 底层使用的 TreadLocal)

对于线上业务存在大量的跨线程业务操作,实际线上日志输出海量且相当复杂,故研究跨线程的日志链路追踪,形成业务日志链路记录,方便高效的排查线上问题

        在此有一种方案为重写线程池,将线程池重新封装,在线程执行将前一个线程的日志traceId传递给将要执行的线程日志MDC

       对于直接new创建线程的情况不考略【实际应用中应该避免这种用法】

在此基础上我们可以通过复写线程池ThreadPoolExecutor 来实现traceid的传递

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
 
public class ThreadMdcUtil {
    public static void setTraceIdIfAbsent() {
        if (MDC.get(MDCGenerator.REQUEST_ID_HEADER_NAME) == null) {
            MDC.put(MDCGenerator.REQUEST_ID_HEADER_NAME, UUID.randomUUID().toString());
        }
    }
 
    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();
            }
        };
    }
}

  jdk线程池

/**
 * @author lyh
 */
public class ThreadPoolExecutorMdcWrapper extends ThreadPoolExecutor {
    public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }
 
    public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }
 
    public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }
 
    public ThreadPoolExecutorMdcWrapper(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    }
 
    @Override
    public void execute(Runnable task) {
        super.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
    }
 
    @Override
    public <T> Future<T> submit(Runnable task, T result) {
        return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()), result);
    }
 
    @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()));
    }
 
}

spring  ThreadPoolExecutor

public class ThreadPoolTaskExecutorMdcWrapper extends ThreadPoolTaskExecutor {
    @Override
    public void execute(Runnable task) {
        super.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
    }
 
 
    @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()));
    }
 
}

 

标签:task,MDC,submit,线程,链路,日志,super,public
From: https://www.cnblogs.com/lyhc/p/16661650.html

相关文章

  • 面试~线程池-三大方法、七个参数、四种拒绝策略、实际应用
    池化技术程序的运行,本质:占用系统的资源!优化资源的使用!=>池化技术线程池、连接池、内存池、对象池///.....创建、销毁。十分浪费资源池化技术:事先准备好一些资源,有......
  • MySQL教程 - 日志(Logging)
    更新记录转载请注明出处。2022年9月6日发布。2022年9月6日从笔记迁移到博客。日志MySQL中日志分类二进制日志以二进制形式记录所有更改数据的语句,不包含查......
  • linux线程同步简单示例
    #include<stdio.h>#include<pthread.h>#include<stdlib.h>//intpthread_create(pthread_t*thread,constpthread_attr_t*attr,void*(*start_routine)(void*),v......
  • Java---线程入门
    前置知识什么是进程,什么又是线程?咱不是讲系统,简单说下,知道个大概就好了。进程:一个可执行文件执行的过程。线程:操作系统能够进行运算调度的最小单位。它被包含在进程之......
  • JAVA线程
    01、基本概念:程序、进程、线程程序(program):为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。进程(process):程序的一次执行过程,或是正在运行......
  • JAVA进阶--日志框架、阶段项目实战--2022年9月5日
    第一节 日志框架1、什么是日志用来记录程序运行过程中的信息,并且可以进行永久存储  2、输出语句存在哪些问题,日志结束应该具备哪些特点......
  • 线程
    1、什么是线程?进程?两者区别?线程:是操作系统能够进⾏运算调度的最⼩单位,由进程创建的,是进程的一个实体,线程也可以创建线程;进程:正在运行的一个程序,一个进程可以拥有多个线......
  • MSE 支持 Apache Shenyu 网关实现全链路灰度
    作者:卜比什么是全链路灰度微服务体系架构中,服务之间的依赖关系错综复杂,有时某个功能发版依赖多个服务同时升级上线。我们希望可以对这些服务的新版本同时进行小流量灰度......
  • CentOS7.9安装rsyslog+loganalyzer日志服务器详细配置
    1、CentOS7.9安装rsyslog+loganalyzer日志服务器详细配置 一、简介:随着机房内的服务器和网络设备增加,日志管理和查询就成了让系统管理员头疼的事。系统管理员遇到的常见......
  • 集合线程安全问题:第一章:集合类不安全之并发修改异常
    直接上ArrayList线程不安全代码:packagecom.javaliao.backstage;importjava.util.ArrayList;importjava.util.UUID;publicclassDemo{publicstaticvoid......