分布式项目集成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完全一致,达到链路追踪的目的。

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

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

相关推荐
LB21127 小时前
Kafka笔记
分布式·kafka·linq
独自破碎E7 小时前
Spring Boot 3.x和2.x版本相比有哪些区别与改进?
java·spring boot·后端
坚持学习前端日记8 小时前
个人运营小网站的最佳策略
java·学习·程序人生·职场和发展·创业创新
幽络源小助理8 小时前
SpringBoot+Vue美食网站系统源码 | Java餐饮项目免费下载 – 幽络源
java·vue.js·spring boot
k***92168 小时前
C++:继承
java·数据库·c++
Coder_Boy_8 小时前
基于SpringAI企业级智能教学考试平台考试模块全业务闭环方案
java·人工智能·spring boot·aiops
微爱帮监所写信寄信8 小时前
微爱帮监狱寄信写信小程序信件内容实时保存技术方案
java·服务器·开发语言·前端·小程序
沛沛老爹8 小时前
Web开发者实战A2A智能体交互协议:从Web API到AI Agent通信新范式
java·前端·人工智能·云原生·aigc·交互·发展趋势
shizhenshide8 小时前
物联网(IoT)设备如何应对验证码?探讨无头浏览器与协议级解决方案
java·struts·microsoft·验证码·ezcaptcha
七夜zippoe8 小时前
响应式编程基石 Project Reactor源码解读
java·spring·flux·响应式编程·mono·订阅机制