這裏咱們能夠先查看官方針對其餘rpc的實現brave-grpc-3.9.0.jarjava
針對dubbo調用先後進行攔截,建立span,關聯parentSpanId,traceIdgit
其中咱們要實現4個接口github
DubboClientRequestAdapter實現ClientRequestAdapterspring
public class DubboClientRequestAdapter implements ClientRequestAdapter { private Map<String, String> headers; private String spanName; public DubboClientRequestAdapter(@Nullable Map<String, String> headers, @Nullable String spanName) { this.headers = headers; this.spanName = spanName; } @Override public String getSpanName() { return this.spanName; } @Override public void addSpanIdToRequest(SpanId spanId) { if (spanId == null) { headers.put(DubboTraceConst.SAMPLED, "0"); } else { headers.put(DubboTraceConst.SAMPLED, "1"); headers.put(DubboTraceConst.TRACE_ID, IdConversion.convertToString(spanId.traceId)); headers.put(DubboTraceConst.SPAN_ID, IdConversion.convertToString(spanId.spanId)); if (spanId.nullableParentId() != null) { headers.put(DubboTraceConst.PARENT_SPAN_ID, IdConversion.convertToString(spanId.parentId)); } } } @Override public Collection<KeyValueAnnotation> requestAnnotations() { return Collections.emptyList(); } @Override public Endpoint serverAddress() { return null; } }
DubboClientResponseAdapter實現ClientResponseAdapterspringboot
public class DubboClientResponseAdapter implements ClientResponseAdapter { private StatusEnum status; public DubboClientResponseAdapter(@Nullable StatusEnum status) { this.status = status; } @Override public Collection<KeyValueAnnotation> responseAnnotations() { return Collections.singleton(KeyValueAnnotation.create(DubboTraceConst.STATUS_CODE, status.getDesc())); } }
DubboServerRequestAdapter實現ServerRequestAdapterapp
public class DubboServerRequestAdapter implements ServerRequestAdapter { private Map<String, String> headers; private String spanName; public DubboServerRequestAdapter(@Nullable Map<String, String> headers, @Nullable String spanName) { this.headers = headers; this.spanName = spanName; } @Override public TraceData getTraceData() { final String sampled = headers.get(DubboTraceConst.SAMPLED); if (sampled != null) { if (sampled.equals("0") || sampled.toLowerCase().equals("false")) { return TraceData.builder().sample(false).build(); } else { final String parentSpanId = headers.get(DubboTraceConst.PARENT_SPAN_ID); final String traceId = headers.get(DubboTraceConst.TRACE_ID); final String spanId = headers.get(DubboTraceConst.SPAN_ID); if (traceId != null && spanId != null) { SpanId span = getSpanId(traceId, spanId, parentSpanId); return TraceData.builder().sample(true).spanId(span).build(); } } } return TraceData.builder().build(); } @Override public String getSpanName() { return this.spanName; } @Override public Collection<KeyValueAnnotation> requestAnnotations() { return Collections.emptyList(); } static SpanId getSpanId(String traceId, String spanId, String parentSpanId) { return SpanId.builder().traceId(convertToLong(traceId)).spanId(convertToLong(spanId)) .parentId(parentSpanId == null ? null : convertToLong(parentSpanId)).build(); } }
DubboServerResponseAdapter實現ServerResponseAdapteride
public class DubboServerResponseAdapter implements ServerResponseAdapter { private StatusEnum status; public DubboServerResponseAdapter(@Nullable StatusEnum status) { this.status = status; } @Override public Collection<KeyValueAnnotation> responseAnnotations() { return Collections.singleton(KeyValueAnnotation.create(DubboTraceConst.STATUS_CODE, status.getDesc())); } }
dubbo的調用會執行filterChain,其中區分PROVIDER,CONSUMER 因此能夠記錄對應的四個時間源碼分析
@Activate(group = {Constants.PROVIDER, Constants.CONSUMER}) public class BraveDubboFilter implements Filter { /** * @tips:這裏不要用註解的方式 */ private ClientRequestInterceptor clientRequestInterceptor; private ClientResponseInterceptor clientResponseInterceptor; private ServerRequestInterceptor serverRequestInterceptor; private ServerResponseInterceptor serverResponseInterceptor; public void setClientRequestInterceptor(ClientRequestInterceptor clientRequestInterceptor) { this.clientRequestInterceptor = clientRequestInterceptor; } public BraveDubboFilter setClientResponseInterceptor(ClientResponseInterceptor clientResponseInterceptor) { this.clientResponseInterceptor = clientResponseInterceptor; return this; } public BraveDubboFilter setServerRequestInterceptor(ServerRequestInterceptor serverRequestInterceptor) { this.serverRequestInterceptor = serverRequestInterceptor; return this; } public BraveDubboFilter setServerResponseInterceptor(ServerResponseInterceptor serverResponseInterceptor) { this.serverResponseInterceptor = serverResponseInterceptor; return this; } public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { /* * 監控的 dubbo 服務,不歸入跟蹤範圍 */ if ("com.alibaba.dubbo.monitor.MonitorService".equals(invoker.getInterface().getName())) { return invoker.invoke(invocation); } RpcContext context = RpcContext.getContext(); /* * 調用的方法名 以此做爲 span name */ String methodName = invocation.getMethodName(); /* * provider 應用相關信息 */ StatusEnum status = StatusEnum.OK; if ("0".equals(invocation.getAttachment(DubboTraceConst.SAMPLED)) || "false".equals(invocation.getAttachment(DubboTraceConst.SAMPLED))) { return invoker.invoke(invocation); } //注入 if(!inject()) { return invoker.invoke(invocation); } if (context.isConsumerSide()) { System.out.println("consumer execute"); /* * Client side */ clientRequestInterceptor.handle(new DubboClientRequestAdapter(invocation.getAttachments(), methodName)); Result result = null; try { result = invoker.invoke(invocation); } catch (RpcException e) { status = StatusEnum.ERROR; throw e; } finally { final DubboClientResponseAdapter clientResponseAdapter = new DubboClientResponseAdapter(status); clientResponseInterceptor.handle(clientResponseAdapter); } return result; } else if (context.isProviderSide()) { System.out.println("provider execute"); serverRequestInterceptor.handle(new DubboServerRequestAdapter(context.getAttachments(), methodName)); Result result = null; try { result = invoker.invoke(invocation); } finally { serverResponseInterceptor.handle(new DubboServerResponseAdapter(status)); } return result; } return invoker.invoke(invocation); } private boolean inject() { Brave brave = ApplicationContextHolder.getBean(Brave.class); if(brave == null) { return false; } this.setClientRequestInterceptor(brave.clientRequestInterceptor()); this.setClientResponseInterceptor(brave.clientResponseInterceptor()); this.setServerRequestInterceptor(brave.serverRequestInterceptor()); this.setServerResponseInterceptor(brave.serverResponseInterceptor()); return true; } }
基於註解啓用ui
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(DubboTraceConfiguration.class) public @interface EnableDubboTrace { }
配置項this
@Configuration @ConditionalOnClass(Brave.class) public class DubboTraceConfiguration { @Bean public ApplicationContextAware holder() { return new ApplicationContextHolder(); } }
ApplicationContextHolder
public class ApplicationContextHolder implements ApplicationContextAware { private static ApplicationContext applicationContext; public void setApplicationContext(ApplicationContext ctx) throws BeansException { setCtx(ctx); } private static void setCtx(ApplicationContext ctx) { applicationContext = ctx; } public static <T> T getBean(Class<T> requiredType){ return applicationContext.getBean(requiredType); } public static Object getBean(String classStr) { return applicationContext.getBean(classStr); } }
其餘類
public interface DubboTraceConst { String SAMPLED = "dubbo.trace.sampled"; String PARENT_SPAN_ID = "dubbo.trace.parentSpanId"; String SPAN_ID = "dubbo.trace.spanId"; String TRACE_ID = "dubbo.trace.traceId"; String STATUS_CODE = "dubbo.trace.staus_code"; } public enum StatusEnum { OK(200, "OK"), ERROR(500, "ERROR"); private int code; private String desc; private StatusEnum(int code, String desc) { this.code = code; this.desc = desc; } public int getCode() { return code; } public String getDesc() { return desc; } }
針對dubbo filter進行配置文件添加
src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter BraveDubboFilter=com.kite.zipkin.filter.BraveDubboFilter
ps:前置條件是已經有了Brave
導入依賴
<dependency> <groupId>com.kite.zipkin</groupId> <artifactId>dubbo-zipkin-spring-starter</artifactId> <version>1.0.0</version> </dependency>
前置條件配置
@Configuration public class ZipkinConfig { //span(一次請求信息或者一次鏈路調用)信息收集器 @Bean public SpanCollector spanCollector() { Config config = HttpSpanCollector.Config.builder() .compressionEnabled(false)// 默認false,span在transport以前是否會被gzipped .connectTimeout(5000) .flushInterval(1) .readTimeout(6000) .build(); return HttpSpanCollector.create("http://localhost:9411", config, new EmptySpanCollectorMetricsHandler()); } //做爲各調用鏈路,只須要負責將指定格式的數據發送給zipkin @Bean public Brave brave(SpanCollector spanCollector){ Builder builder = new Builder("service1");//指定serviceName builder.spanCollector(spanCollector); builder.traceSampler(Sampler.create(1));//採集率 return builder.build(); } }
啓動dubboTrace
@SpringBootApplication @EnableDubboTrace public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
實現效果