现在分布式系统中一次接口调用都需要多个服务协同完成,其中一个服务出现问题,都会导致最终失败,而查询起来非常不方便。如果在整个链路中,可以通过一个唯一ID(traceId)跟踪本次服务调用,方便查询问题。
public class TraceIdUtil { private static final ThreadLocal<String> TRACE_ID = new ThreadLocal<>(); private static final String HTTP_TYPE = "HTTP-"; private static final String RPC_TYPE = "RPC-"; public static String getTraceId() { return TRACE_ID.get(); } /** * 获取 * * @return traceid */ public static String getTraceId(String type) { if (TRACE_ID.get() == null) { setTraceId(type + UUID.randomUUID().toString()); } return Optional.ofNullable(TRACE_ID.get()).orElse(""); } public static String getHttpTraceId() { return TraceIdUtil.getTraceId(HTTP_TYPE); } public static String getRpcTraceId() { return TraceIdUtil.getTraceId(RPC_TYPE); } public static void setTraceId(String traceId) { TRACE_ID.set(traceId); } }
@Slf4j @Activate(group = {Constants.CONSUMER}, order = -9999) public class GlobalTraceConsumerFilter implements Filter { private static final String TRACE_ID = "traceId"; @Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { String traceId = TraceIdUtil.getRpcTraceId(); if (StringUtils.isNotEmpty(traceId)) { log.info("consumer当前traceId:{}", traceId); RpcContext.getContext().setAttachment(TRACE_ID, traceId); } else { // 调用无traceID RpcContext.getContext().setAttachment(TRACE_ID, TraceIdUtil.getRpcTraceId()); } return invoker.invoke(invocation); } }
@Slf4j @Activate(group = {Constants.PROVIDER}, order = -9999) public class GlobalTraceProviderFilter implements Filter { private static final String TRACE_ID = "traceId"; @Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { String traceId = invocation.getAttachment(TRACE_ID); if (!StringUtils.isBlank(traceId)) { log.info("当前traceId:{}", traceId); RpcContext.getContext().setAttachment(TRACE_ID, traceId); TraceIdUtil.setTraceId(traceId); } else { log.warn("当前traceId无"); // 调用无traceID RpcContext.getContext().setAttachment(TRACE_ID, TraceIdUtil.getRpcTraceId()); TraceIdUtil.setTraceId(traceId); } return invoker.invoke(invocation); } }
@Slf4j @WebFilter(urlPatterns = "/*") @Order(-9999) public class WebTraceIdFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { String httpTraceId = TraceIdUtil.getHttpTraceId(); log.info("接受http请求添加traceId:{}", httpTraceId); } }
为了让dubbo的spi机制生效还要在resoutces下META-INF/dubbo目录新建文件
com.alibaba.dubbo.rpc.Filter
内容:
gCtrace=com.example.common.traceid.GlobalTraceConsumerFilter gPtrace=com.example.common.traceid.GlobalTraceProviderFilter
http调用日志:
2019-11-08 18:45:35.175 [DubboServerHandler-10.112.206.222:20990-thread-2] INFO c.example.common.traceid.GlobalTraceProviderFilter - 当 前traceId:RPC-445e493a-914e-4614-891f-dd9aa248e1c7
可以通过taceId判断请求来源http还是rpc请求。