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

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

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

相关推荐
abcnull20 分钟前
用javaparser做精准测试
java·ast·静态代码分析·精准测试·javaparser
叶小鸡26 分钟前
Java 篇-项目实战-苍穹外卖-笔记汇总
java·开发语言·笔记
AI人工智能+电脑小能手42 分钟前
【大白话说Java面试题】【Java基础篇】第22题:HashMap 和 HashSet 有哪些区别
java·开发语言·哈希算法·散列表·hash
juniperhan1 小时前
Flink 系列第21篇:Flink SQL 函数与 UDF 全解读:类型推导、开发要点与 Module 扩展
java·大数据·数据仓库·分布式·sql·flink
ID_180079054731 小时前
Python 实现亚马逊商品详情 API 数据准确性校验(极简可用 + JSON 参考)
java·python·json
c++之路1 小时前
C++23概述
java·c++·c++23
专注API从业者2 小时前
Open Claw 京东商品监控选品实战:一键抓取、实时监控、高效选品
java·服务器·数据库
摇滚侠2 小时前
DBeaver 导入数据库 导入 SQL 文件 MySQL 备份恢复
java·数据库·mysql
keep one's resolveY3 小时前
SpringBoot实现重试机制的四种方案
java·spring boot·后端
天空属于哈夫克33 小时前
企业微信API常见的错误和解决方案
java·数据库·企业微信