分布式项目集成TLog实现轻量级日志链路追踪

hello,大家好,我是灰小猿!

随着公司业务的不断扩增,不同的业务中心逐渐开始采用不同的服务来完成,这就出现了典型的服务调用场景,随着调用服务节点的不断增加,分布式服务日志链路问题便随之出现,这也导致了开发同学在做请求日志链路排查时变得十分困难,往往很难完整的获取到整个链路的日志信息。

其实做日志链路追踪的基本思想:都是在整条调用链路中设置一个Trace_id,并不断传递输出在日志中,同时再结合标准输出的全局异常捕获,即可满足,基本原理如下:

但当前市面上已经有了比较完善的原理基本类似的解决框架,所以经过技术分析和对比,并结合项目情况,我采用TLog的方式来进行日志链路追踪,

具体的集成操作我就不再赘述,TLog官网已经介绍的十分详细:
TLog官网

这里我主要记录在springboot版本是3.2.4,jakarta版本是6.0.0的情况下,引入1.5.2版本的TLog,出现的若干问题及解决。(1.5.2版本的TLog是我截止发文能获取到的最新版本)

问题一:TLog底层依赖javax.*,但该依赖已停用并更新至 jakarta.*,导致控制台无法打印Trace_id等信息问题解决

如果你的项目仍然在使用javax依赖,那么大概率不会出现任何问题,但是如果你和我一样,已经更新为了Jakarta依赖,那么问题就会接踵而至。

想要解决这个问题,需要将"TLog的过滤器"和"TLog web的逻辑封装"这两个核心方法进行重写,主要是为了替换成Jakarta依赖

具体如下:

重写-TLog的过滤器

java 复制代码
import com.yomahub.tlog.constant.TLogConstants;
import com.yomahub.tlog.context.TLogContext;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

/**
 * 重写TLog过滤器,兼容jakarta
 */
public class TLogFilter implements Filter {


  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
      try {
        TLogWebCommon.loadInstance().preHandle((HttpServletRequest) request);
        //把traceId放入response的header,方便从前端拿整条链路的traceId
        ((HttpServletResponse) response).addHeader(TLogConstants.TLOG_TRACE_KEY, TLogContext.getTraceId());
        chain.doFilter(request, response);
        return;
      } finally {
        TLogWebCommon.loadInstance().afterCompletion();
      }
    }
    chain.doFilter(request, response);
  }

}

重写-TLog web的逻辑封装

java 复制代码
import com.yomahub.tlog.constant.TLogConstants;
import com.yomahub.tlog.core.rpc.TLogLabelBean;
import com.yomahub.tlog.core.rpc.TLogRPCHandler;
import jakarta.servlet.http.HttpServletRequest;
 
 
/**
 * TLog web的逻辑封装
 */
public class TLogWebCommon extends TLogRPCHandler {
 
    private static volatile TLogWebCommon tLogWebCommon;
 
    public static TLogWebCommon loadInstance() {
        if (tLogWebCommon == null) {
            synchronized (TLogWebCommon.class) {
                if (tLogWebCommon == null) {
                    tLogWebCommon = new TLogWebCommon();
                }
            }
        }
        return tLogWebCommon;
    }
 
    public void preHandle(HttpServletRequest request) {
        String traceId = request.getHeader(TLogConstants.TLOG_TRACE_KEY);
        String spanId = request.getHeader(TLogConstants.TLOG_SPANID_KEY);
        String preIvkApp = request.getHeader(TLogConstants.PRE_IVK_APP_KEY);
        String preIvkHost = request.getHeader(TLogConstants.PRE_IVK_APP_HOST);
        String preIp = request.getHeader(TLogConstants.PRE_IP_KEY);
 
        TLogLabelBean labelBean = new TLogLabelBean(preIvkApp, preIvkHost, preIp, traceId, spanId);
 
        processProviderSide(labelBean);
    }
 
    public void afterCompletion() {
        cleanThreadLocal();
    }
}

之后将其注册到配置

java 复制代码
import com.yomahub.tlog.feign.filter.TLogFeignFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 日志链路配置
 */
@Configuration
public class LogLinkConfig {

  @Bean
  public FilterRegistrationBean<TLogFilter> loggingFilter() {
    FilterRegistrationBean<TLogFilter> registrationBean = new FilterRegistrationBean<>();
    registrationBean.setFilter(new TLogFilter());
    // 拦截所有请求路径
    registrationBean.addUrlPatterns("/*");
    return registrationBean;
  }
}

这样重写之后,TLog在控制台的日志就可以正常输出Trace_id信息

问题二:服务间调用时,同一请求在不同的服务下打印日志输出的Trace_id不同问题解决

问题和上述同理,也是由于TLog引用的是jacx导致的,导致原来注册在TLog的config都不会生效,因此我们需要将TLogFeignFilter在我们的配置中重新注入:

直接在上面的LogLinkConfig 中添加注入TLogFeignFilter后,完整配置代码如下:

java 复制代码
import com.yomahub.tlog.feign.filter.TLogFeignFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 日志链路配置
 */
@Configuration
public class LogLinkConfig {

  @Bean
  public FilterRegistrationBean<TLogFilter> loggingFilter() {
    FilterRegistrationBean<TLogFilter> registrationBean = new FilterRegistrationBean<>();
    registrationBean.setFilter(new TLogFilter());
    // 拦截所有请求路径
    registrationBean.addUrlPatterns("/*");
    return registrationBean;
  }

  @Bean
  public TLogFeignFilter getTLogFeignFilter() {
    return new TLogFeignFilter();
  }
}

之后重启服务并重新调用,可见在不同的服务下对同一次请求输出的Trace_id完全一致,达到链路追踪的目的。

目前在集成的过程中就遇到了这两个问题,如果后面有发现其他问题我会再继续补充,

我是灰小猿,我们下期见!

相关推荐
无心水1 小时前
【分布式利器:事务】5、本地消息表vs事务消息:异步方案怎么选?
分布式·rocketmq·分布式事务·saga·事务消息·分布式利器·2pc3pc
乄bluefox1 小时前
高性能分布式 ID 生成器:基于 Redis Segment 预分配的实践
java·redis·分布式
编码追梦人1 小时前
【探索实战】Kurator:开启分布式云原生之旅
分布式·云原生
Jiong-9521 小时前
Java求职面试:谢飞机的奇妙旅程
java·jvm·线程池·多线程·hashmap·juc·arraylist
小二·1 小时前
Java核心机制精讲:深入理解 static 关键字与引用传递
java·java-ee
IDOlaoluo1 小时前
apache-tomcat-7.0.42.tar.gz 下载与安装完整教程(附安装包)
java·tomcat·apache
喝养乐多长不高1 小时前
RabbitMQ:消息确认
java·rabbitmq·java-rabbitmq
草莓熊Lotso2 小时前
C++ STL map 系列全方位解析:从基础使用到实战进阶
java·开发语言·c++·人工智能·经验分享·网络协议·everything
shura10142 小时前
如何优雅地实现参数校验
java·开发语言