首页 > 其他分享 >MDC (Mapped Diagnostic Context)

MDC (Mapped Diagnostic Context)

时间:2023-10-09 13:57:14浏览次数:34  
标签:traceId MdcUtil request Diagnostic 线程 Context MDC public

MDCorg.slf4j包下的一个类,它的全称是Mapped Diagnostic Context,我们可以认为它是一个线程安全的存放诊断日志的容器。

MDC的底层是用了ThreadLocal来保存数据的。

我们可以用它传递参数。

例如现在有这样一种场景:我们使用RestTemplate调用远程接口时,有时需要在header中传递信息,比如:traceId,source等,便于在查询日志时能够串联一次完整的请求链路,快速定位问题。

这种业务场景就能通过ClientHttpRequestInterceptor接口实现,具体做法如下:

第一步,定义一个LogFilter拦截所有接口请求,在MDC中设置traceId:

public class LogFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        MdcUtil.add(UUID.randomUUID().toString());
        System.out.println("记录请求日志");
        chain.doFilter(request, response);
        System.out.println("记录响应日志");
    }

    @Override
    public void destroy() {
    }
}

第二步,实现ClientHttpRequestInterceptor接口,MDC中获取当前请求的traceId,然后设置到header中:

public class RestTemplateInterceptor implements ClientHttpRequestInterceptor {

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        request.getHeaders().set("traceId", MdcUtil.get());
        return execution.execute(request, body);
    }
}

第三步,定义配置类,配置上面定义的RestTemplateInterceptor类:

@Configuration
public class RestTemplateConfiguration {

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.setInterceptors(Collections.singletonList(restTemplateInterceptor()));
        return restTemplate;
    }

    @Bean
    public RestTemplateInterceptor restTemplateInterceptor() {
        return new RestTemplateInterceptor();
    }
}

其中MdcUtil其实是利用MDC工具在ThreadLocal中存储和获取traceId

public class MdcUtil {

    private static final String TRACE_ID = "TRACE_ID";

    public static String get() {
        return MDC.get(TRACE_ID);
    }

    public static void add(String value) {
        MDC.put(TRACE_ID, value);
    }
}

在filter中执行接口方法之前,生成traceId,调用MdcUtil类的add方法添加到MDC中,然后在同一个请求的其他地方就能通过MdcUtil类的get方法获取到该traceId。

能使用MDC保存traceId等参数的根本原因是,用户请求到应用服务器,Tomcat会从线程池中分配一个线程去处理该请求。

那么该请求的整个过程中,保存到MDC的ThreadLocal中的参数,也是该线程独享的,所以不会有线程安全问题。

 

标签:traceId,MdcUtil,request,Diagnostic,线程,Context,MDC,public
From: https://www.cnblogs.com/ooo0/p/17751545.html

相关文章

  • ${pageContext.request.contextPath}不能识别的问题
    ${pageContext.request.contextPath}是通过 get方法去取的,先pageContext.getRequest()得到HttpServletRequest对象,再调用 HttpServletRequest的getContextPath方法作用是取出部署的应用程序名,这样不管如何部署,所用路径都是正确的。 El表达式的写法:${pageContext.request.......
  • Spring ApplicationContext 是如何被注入的
     //ERRORNoqualifyingbeanoftype'org.springframework.context.ApplicationContext'availableapplicationContext.getBean(ApplicationContext.class);//SUCCESS@ComponentpublicclassSimpleBean3{@AutowiredprivateApplicationContexta......
  • Springboot中的context-path作用
    首先context-path用于构成url,我们在配置文件的时候server:servlet:context-path:/test之后在本地访问端口8080时(此处拿knife4j举列)本来要访问的是:localhost:8080/doc.html但是现在由于加了context-path,该路径便变为了:localhost:8080/tset/doc.html......
  • GoLang context包
    初始化一个context如果确定是开头则用Background,如果不确定则用ToDocontext包核心API有四个1.context.WithValue设置键值对,并且返回一个新的context实例2.context.WithCancel3.context.WithDeadline4.context.WithTimeout三者都返回一个可取消的context实例和取消函数,WithTi......
  • 11 ServletContext 的应用
    实际上就是讲解servletcontext对象的方法。。。。经典白学,过时的,不会被用到的技术1.资源共享2.转发requestdispather().forward();3.读取资源文件......
  • 10 ServletContext 对象
    ServletContext对象:一个模板中只定义一个,可以使得不同的页面之间进行数据交流执行三部曲:1.SetServletContext.java2.GetServletContext.java3.web.xmlimportjavax.servlet.ServletContext;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServle......
  • Wpf经验技巧-使用 d:DataContext 指定 DataContext 的类型.
    VM代码:V代码(版本1):没有指定DataContext的类型,所以下面的绑定并不知道P1和P3到底是什么,也就无法在代码编辑时检测出绑定是否正确.如果写错了,只能等到程序运行并打开这个窗口时报错才能知道.V代码(版本2):通过d:DataContext指定了DataContext的类型,所以下面的绑定......
  • 【学到一个小技巧】context.WithValue 中的 key 可以是个空对象
    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!cnblogs博客zhihuGithub公众号:一本正经的瞎扯从netpoll库看到这段代码:typeconnkeystruct{}varctxkeyconnkeyfuncprepare(connnetpoll.Connection)context.Context{ mc:=newSvrMuxConn(conn) ct......
  • 编程语言mojo报错:error: cannot call function that may raise in a context that can
    代码:frompythonimportPythonfnmain():#fnmain()raises:#ThisisequivalenttoPython's`importnumpyasnp`letnp=Python.import_module("numpy")leta=np.array([1,2,3])print(a) 运行报错:[02:19:48](mojo)dev......
  • golang Context应用举例
     Context本质golang标准库里Context实际上是一个接口(即一种编程规范、一种约定)。typeContextinterface{Deadline()(deadlinetime.Time,okbool)Done()<-chanstruct{}Err()errorValue(keyany)any} 通过查看源码里的注释,我们得到......