Commit f0a633373ece16ec66230886d67627b8a5cc047f
1 parent
cc156f6e
调整获取traceId的优先级
Showing
3 changed files
with
148 additions
and
8 deletions
src/main/java/cn/iocoder/dashboard/framework/tracer/core/util/TracerUtils.java
| ... | ... | @@ -5,7 +5,9 @@ import cn.hutool.extra.spring.SpringUtil; |
| 5 | 5 | import cn.iocoder.dashboard.framework.tracer.core.ITrace; |
| 6 | 6 | import org.apache.skywalking.apm.toolkit.trace.TraceContext; |
| 7 | 7 | |
| 8 | +import java.util.Map; | |
| 8 | 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 | 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 | 52 | private TracerUtils() { |
| ... | ... | @@ -26,10 +58,27 @@ public class TracerUtils { |
| 26 | 58 | * 一般来说,通过链路追踪编号,可以将访问日志,错误日志,链路追踪日志,logger 打印日志等,结合在一起,从而进行排错。 |
| 27 | 59 | * <p> |
| 28 | 60 | * 默认情况下,我们使用 Apache SkyWalking 的 traceId 作为链路追踪编号。当然,可能会存在并未引入 Skywalking 的情况,此时使用 UUID 。 |
| 61 | + * 方法获取顺序: skywalking - > map -> 扩展接口 -> default | |
| 62 | + * 项目整体获取traceId的优先级 skywalking > 自定义实现接口 > 默认 | |
| 63 | + * map中的traceId 当且仅当其他情况为产生时才会出现. | |
| 29 | 64 | * |
| 30 | 65 | * @return 链路追踪编号 |
| 31 | 66 | */ |
| 32 | 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 | 82 | // 通过自定义扩展的tracer产生traceId, 在Spring容器加载完成前会获取不到对应的Bean |
| 34 | 83 | ITrace tracer = null; |
| 35 | 84 | try { |
| ... | ... | @@ -42,20 +91,20 @@ public class TracerUtils { |
| 42 | 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 | 94 | // TODO 芋艿 多次调用会问题 |
| 54 | 95 | |
| 55 | 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 | 108 | * 从Spring 容器中获取 ITrace 类,返回可以为null |
| 60 | 109 | * |
| 61 | 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 | 24 | \ No newline at end of file | ... | ... |