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

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

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

相关推荐
GIS数据转换器7 小时前
农村生活污水治理智慧管控平台
大数据·人工智能·分布式·数据分析·生活·智慧城市
二宝哥8 小时前
离线安装maven
java·数据库·maven
日月云棠8 小时前
6 高级配置:Spring Boot整合、泛化调用与配置指南
java·后端
云烟成雨TD8 小时前
Spring AI Alibaba 1.x 系列【58】Spring AI Alibaba Builtin Nodes 模块介绍
java·人工智能·spring
wyu729618 小时前
SpringBoot学习记录,一个小项目实战
java
小江的记录本8 小时前
【Java基础】反射与注解:核心原理、自定义注解、注解解析方式(附《思维导图》+《面试高频考点清单》)
java·数据结构·python·mysql·spring·面试·maven
ch.ju8 小时前
Java Programming Chapter 4——Composition of classes
java·开发语言
日月云棠8 小时前
5 高级配置:多注册中心与异步化编程
java·后端
敖正炀9 小时前
BlockingQueue 与生产者-消费者模式:并发数据传递的源码内核
java
敖正炀9 小时前
Stream API 惰性求值与内部迭代
java