日志排查问题困难?分布式日志链路跟踪来帮你

  

一、背景

  

开发排查系统问题用得最多的手段就是查看系统日志,在分布式环境中一般使用<代码>麋鹿>   

  

二,解决思路

  
      <李>每个请求都使用一个<代码>唯一标识>   <李>使用Logback的MDC <代码> 机制日志模板中加入<代码> traceId> % {traceId}   
      

    MDC(诊断上下文映射,映射调试上下文)是log4j和logback提供的一种方便在多线程条件下记录日志的功能.MDC可以看成是一个与当前线程绑定的地图,可以往其中添加键值对.MDC中包含的内容可以被同一线程中执行的代码所访问。当前线程的子线程会继承其父线程中的MDC的内容。当需要记录日志时,只需要从争取民主变革运动中获取所需的信息即可.MDC的内容则由程序在适当的时候保存进去。对于一个网络应用来说,通常是在请求被处理的最开始保存这些数据。

      李   
  

  

三,方案实现

  

由于<代码> MDC> ThreadLocal> 里的值会丢失,所以方案主要的难点是解决值的传递问题。

  

3.1。修改日志模板

  

logback配置文件模板格式添加标识X <代码> % {traceId}
日志排查问题困难?分布式日志链路跟踪来帮你“> </p>
  <p> </p>
  <h4> 3.2。网关添加过滤器</h4>
  <p>生成<代码> traceId> </代码并通过头传递给下游服务</p>
  <pre> <=坝镅詊ava代码类> @ component
  公开课TraceFilter延伸ZuulFilter {
  @ autowired
  私人TraceProperties TraceProperties;
  
  @Override
  公共字符串filterType () {
  返回FilterConstants.PRE_TYPE;
  }
  
  @Override
  公共int filterOrder () {
  FORM_BODY_WRAPPER_FILTER_ORDER返回- 1;
  }
  
  @Override
  公共布尔shouldFilter () {//根据配置控制是否开启过滤器
  返回traceProperties.getEnable ();
  }
  
  @Override
  公共对象的run () {//链路追踪id
  字符串traceId=IdUtil.fastSimpleUUID ();
  MDC.put (CommonConstant。LOG_TRACE_ID traceId);
  RequestContext ctx=RequestContext.getCurrentContext ();
  ctx.addZuulRequestHeader (CommonConstant。TRACE_ID_HEADER traceId);
  返回null;
  }
  }</代码> </pre>
  <p> </p>
  <h4> 3.3。下游服务增加弹簧拦截器</h4>
  <p>接收并保存<代码> traceId> </代码的值<br/> <强>拦截器</强> </p>
  <pre> <代码类=公共类TraceInterceptor实现HandlerInterceptor {   @Override   公共布尔preHandle (HttpServletRequest请求,HttpServletResponse响应对象处理程序){   字符串traceId=request.getHeader (CommonConstant.TRACE_ID_HEADER);   如果(StrUtil.isNotEmpty (traceId)) {   MDC.put (CommonConstant。LOG_TRACE_ID traceId);   }   返回true;   }   }   

<强>注册拦截器

  
 <代码类="语言java ">公共类DefaultWebMvcConfig延伸WebMvcConfigurationSupport {
  @Override
  保护无效addInterceptors (InterceptorRegistry注册表){//日志链路追踪拦截器
  注册表。addInterceptor(新TraceInterceptor ()) .addPathPatterns (“/* *”);
  
  super.addInterceptors(注册表);
  }
  } 
  

  

3.4。下游服务增加假装拦截器

  

继续把当前服务的<代码> traceId>   

 <代码类="语言java ">公共类FeignInterceptorConfig {
  @ bean
  公共RequestInterceptor RequestInterceptor () {
  RequestInterceptor RequestInterceptor=模板→{//传递日志traceId
  字符串traceId=MDC.get (CommonConstant.LOG_TRACE_ID);
  如果(StrUtil.isNotEmpty (traceId)) {
  template.header (CommonConstant。TRACE_ID_HEADER traceId);
  }
  };
  返回requestInterceptor;
  }
  } 
  

  

3.5。扩展线程池

  

主要针对业务会使用线程池(异步,并行处理),并且<代码>春季> @Async 注解来使用线程池,所以需要扩展

日志排查问题困难?分布式日志链路跟踪来帮你