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完全一致,达到链路追踪的目的。
目前在集成的过程中就遇到了这两个问题,如果后面有发现其他问题我会再继续补充,
我是灰小猿,我们下期见!