Commit f0a633373ece16ec66230886d67627b8a5cc047f

Authored by dark
1 parent cc156f6e

调整获取traceId的优先级

src/main/java/cn/iocoder/dashboard/framework/tracer/core/util/TracerUtils.java
@@ -5,7 +5,9 @@ import cn.hutool.extra.spring.SpringUtil; @@ -5,7 +5,9 @@ import cn.hutool.extra.spring.SpringUtil;
5 import cn.iocoder.dashboard.framework.tracer.core.ITrace; 5 import cn.iocoder.dashboard.framework.tracer.core.ITrace;
6 import org.apache.skywalking.apm.toolkit.trace.TraceContext; 6 import org.apache.skywalking.apm.toolkit.trace.TraceContext;
7 7
  8 +import java.util.Map;
8 import java.util.UUID; 9 import java.util.UUID;
  10 +import java.util.concurrent.ConcurrentHashMap;
9 11
10 /** 12 /**
11 * 链路追踪工具类 13 * 链路追踪工具类
@@ -15,6 +17,36 @@ import java.util.UUID; @@ -15,6 +17,36 @@ import java.util.UUID;
15 public class TracerUtils { 17 public class TracerUtils {
16 18
17 /** 19 /**
  20 + * 维护请求线程对应的TraceId
  21 + */
  22 + private final static Map<Thread, String> threadTraceIdMap = new ConcurrentHashMap<>();
  23 +
  24 + /**
  25 + * 保存链路流水号
  26 + *
  27 + * @param traceId 链路流水号
  28 + */
  29 + public static void saveThreadTraceId(String traceId) {
  30 + threadTraceIdMap.put(Thread.currentThread(), traceId);
  31 + }
  32 +
  33 + /**
  34 + * 根据线程获取链路流水号
  35 + *
  36 + * @return 链路流水号
  37 + */
  38 + public static String getThreadTraceId() {
  39 + return threadTraceIdMap.get(Thread.currentThread());
  40 + }
  41 +
  42 + /**
  43 + * 根据线程删除链路流水
  44 + */
  45 + public static void deleteThreadTraceId() {
  46 + threadTraceIdMap.remove(Thread.currentThread());
  47 + }
  48 +
  49 + /**
18 * 私有化构造方法 50 * 私有化构造方法
19 */ 51 */
20 private TracerUtils() { 52 private TracerUtils() {
@@ -26,10 +58,27 @@ public class TracerUtils { @@ -26,10 +58,27 @@ public class TracerUtils {
26 * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。 58 * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。
27 * <p> 59 * <p>
28 * 默认情况下,我们使用 Apache SkyWalking 的 traceId 作为链路追踪编号。当然,可能会存在并未引入 Skywalking 的情况,此时使用 UUID 。 60 * 默认情况下,我们使用 Apache SkyWalking 的 traceId 作为链路追踪编号。当然,可能会存在并未引入 Skywalking 的情况,此时使用 UUID 。
  61 + * 方法获取顺序: skywalking - > map -> 扩展接口 -> default
  62 + * 项目整体获取traceId的优先级 skywalking > 自定义实现接口 > 默认
  63 + * map中的traceId 当且仅当其他情况为产生时才会出现.
29 * 64 *
30 * @return 链路追踪编号 65 * @return 链路追踪编号
31 */ 66 */
32 public static String getTraceId() { 67 public static String getTraceId() {
  68 + String traceId;
  69 + // 通过 SkyWalking 获取链路编号
  70 + try {
  71 + traceId = TraceContext.traceId();
  72 + if (StrUtil.isNotBlank(traceId)) {
  73 + return traceId;
  74 + }
  75 + } catch (Throwable ignore) {
  76 + }
  77 + // 尝试从map中获取
  78 + traceId = threadTraceIdMap.get(Thread.currentThread());
  79 + if (StrUtil.isNotBlank(traceId)) {
  80 + return traceId;
  81 + }
33 // 通过自定义扩展的tracer产生traceId, 在Spring容器加载完成前会获取不到对应的Bean 82 // 通过自定义扩展的tracer产生traceId, 在Spring容器加载完成前会获取不到对应的Bean
34 ITrace tracer = null; 83 ITrace tracer = null;
35 try { 84 try {
@@ -42,20 +91,20 @@ public class TracerUtils { @@ -42,20 +91,20 @@ public class TracerUtils {
42 } catch (Throwable ignored) { 91 } catch (Throwable ignored) {
43 } 92 }
44 } 93 }
45 - // 通过 SkyWalking 获取链路编号  
46 - try {  
47 - String traceId = TraceContext.traceId();  
48 - if (StrUtil.isNotBlank(traceId)) {  
49 - return traceId;  
50 - }  
51 - } catch (Throwable ignore) {  
52 - }  
53 // TODO 芋艿 多次调用会问题 94 // TODO 芋艿 多次调用会问题
54 95
55 return defaultTraceId(); 96 return defaultTraceId();
56 } 97 }
57 98
58 /** 99 /**
  100 + * 仅仅获取Skywalking 中的traceId, 若无skywalking,则会返回""
  101 + *
  102 + * @return skywalking 的traceId
  103 + */
  104 + public static String getSkywalkingTraceId() {
  105 + return TraceContext.traceId();
  106 + }
  107 + /**
59 * 从Spring 容器中获取 ITrace 类,返回可以为null 108 * 从Spring 容器中获取 ITrace 类,返回可以为null
60 * 109 *
61 * @return ITrace 110 * @return ITrace
src/main/java/cn/iocoder/dashboard/framework/tracer/filter/SpringMvcTraceFilter.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.tracer.filter;
  2 +
  3 +import cn.hutool.core.util.StrUtil;
  4 +import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils;
  5 +import lombok.extern.slf4j.Slf4j;
  6 +import org.aspectj.lang.annotation.Aspect;
  7 +import org.aspectj.lang.annotation.Before;
  8 +import org.aspectj.lang.annotation.Pointcut;
  9 +import org.springframework.beans.factory.annotation.Value;
  10 +import org.springframework.context.annotation.Configuration;
  11 +import org.springframework.lang.Nullable;
  12 +import org.springframework.stereotype.Component;
  13 +import org.springframework.web.servlet.AsyncHandlerInterceptor;
  14 +import org.springframework.web.servlet.HandlerInterceptor;
  15 +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
  16 +
  17 +import javax.servlet.*;
  18 +import javax.servlet.http.HttpServletRequest;
  19 +import javax.servlet.http.HttpServletResponse;
  20 +import java.io.IOException;
  21 +
  22 +/**
  23 + * 对Spring Mvc 的请求拦截, 添加traceId.
  24 + *
  25 + * @author mashu
  26 + */
  27 +
  28 +@Slf4j
  29 +@Component
  30 +public class SpringMvcTraceFilter implements HandlerInterceptor {
  31 +
  32 + @Value("${cn.iocoder.tracer.name:global-trace-id}")
  33 + private String traceIdName;
  34 +
  35 + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  36 + // 请求中traceId
  37 + String reqTraceId = (String)request.getAttribute(traceIdName);
  38 + // skywalking中的traceId
  39 + String skywalkingTraceId = TracerUtils.getSkywalkingTraceId();
  40 + String traceId ;
  41 + if (null == reqTraceId && StrUtil.isBlank(skywalkingTraceId)) {
  42 + // 两者皆空,添加默认的.
  43 + traceId = TracerUtils.getTraceId();
  44 + request.setAttribute(traceIdName, traceId);
  45 + } else if (null == reqTraceId && StrUtil.isNotBlank(skywalkingTraceId)){
  46 + // 若请求空,则添加,为没有skywalking的系统添加一个TraceId
  47 + traceId = skywalkingTraceId;
  48 + request.setAttribute(traceIdName, traceId);
  49 + } else if (null != reqTraceId && StrUtil.isBlank(skywalkingTraceId)) {
  50 + // 请求非空, skywalking为空
  51 + traceId = reqTraceId;
  52 + } else {
  53 + // 两者皆非空,不动请求头
  54 + traceId = skywalkingTraceId;
  55 + }
  56 + TracerUtils.saveThreadTraceId(traceId);
  57 + log.debug("请求进入,添加traceId[{}]", traceId);
  58 + return true;
  59 + }
  60 +
  61 + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
  62 + // 请求结束,删除本地的链路流水号
  63 + log.debug("请求结束,删除traceId[{}]", TracerUtils.getTraceId());
  64 + TracerUtils.deleteThreadTraceId();
  65 +
  66 + }
  67 +
  68 +}
src/main/java/cn/iocoder/dashboard/framework/tracer/filter/WebConfig.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.tracer.filter;
  2 +
  3 +import org.springframework.beans.factory.annotation.Autowired;
  4 +import org.springframework.context.annotation.Configuration;
  5 +import org.springframework.stereotype.Component;
  6 +import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
  7 +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  8 +
  9 +import javax.annotation.Resource;
  10 +
  11 +@Configuration
  12 +@Component
  13 +public class WebConfig implements WebMvcConfigurer {
  14 +
  15 + @Resource
  16 + private SpringMvcTraceFilter springMvcTraceFilter;
  17 +
  18 + @Override
  19 + public void addInterceptors(InterceptorRegistry registry) {
  20 + registry.addInterceptor(this.springMvcTraceFilter).addPathPatterns("/**");
  21 + }
  22 +
  23 +}
0 \ No newline at end of file 24 \ No newline at end of file