packagebrave.dubbo.rpc;importbrave.Span;importbrave.Span.Kind;importbrave.Tracer;importbrave.Tracing;importbrave.internal.Platform;importbrave.propagation.Propagation;importbrave.propagation.TraceContext;importbrave.propagation.TraceContextOrSamplingFlags;importcom.alibaba.dubbo.common.Constants;importcom.alibaba.dubbo.common.extension.Activate;importcom.alibaba.dubbo.common.extension.ExtensionLoader;importcom.alibaba.dubbo.config.spring.extension.SpringExtensionFactory;importcom.alibaba.dubbo.remoting.exchange.ResponseCallback;importcom.alibaba.dubbo.rpc.Filter;importcom.alibaba.dubbo.rpc.Invocation;importcom.alibaba.dubbo.rpc.Invoker;importcom.alibaba.dubbo.rpc.Result;importcom.alibaba.dubbo.rpc.RpcContext;importcom.alibaba.dubbo.rpc.RpcException;importcom.alibaba.dubbo.rpc.protocol.dubbo.FutureAdapter;importcom.alibaba.dubbo.rpc.support.RpcUtils;importjava.net.InetSocketAddress;importjava.util.Map;importjava.util.concurrent.Future;
@Activate(group= {Constants.PROVIDER, Constants.CONSUMER}, value = "tracing")// http://dubbo.io/books/dubbo-dev-book-en/impls/filter.html
//public constructor permitted to allow dubbo to instantiate this
public final class TracingFilter implementsFilter {
Tracer tracer;
TraceContext.Extractor>extractor;
TraceContext.Injector>injector;/*** {@linkExtensionLoader} supplies the tracing implementation which must be named "tracing". For
* example, if using the {@linkSpringExtensionFactory}, only a bean named "tracing" will be
* injected.*/
public voidsetTracing(Tracing tracing) {
tracer=tracing.tracer();
extractor=tracing.propagation().extractor(GETTER);
injector=tracing.propagation().injector(SETTER);
}
@Overridepublic Result invoke(Invoker> invoker, Invocation invocation) throwsRpcException {if (tracer == null) returninvoker.invoke(invocation);
RpcContext rpcContext=RpcContext.getContext();
Kind kind= rpcContext.isProviderSide() ?Kind.SERVER : Kind.CLIENT;finalSpan span;if(kind.equals(Kind.CLIENT)) {
span=tracer.nextSpan();
injector.inject(span.context(), invocation.getAttachments());
}else{
TraceContextOrSamplingFlags extracted=extractor.extract(invocation.getAttachments());
span= extracted.context() != null
?tracer.joinSpan(extracted.context())
: tracer.nextSpan(extracted);
}if (!span.isNoop()) {
span.kind(kind);
String service=invoker.getInterface().getSimpleName();
String method=RpcUtils.getMethodName(invocation);
span.name(service+ "/" +method);
parseRemoteAddress(rpcContext, span);
span.start();
}boolean isOneway = false, deferFinish = false;try (Tracer.SpanInScope scope =tracer.withSpanInScope(span)) {
Result result=invoker.invoke(invocation);if(result.hasException()) {
onError(result.getException(), span);
}
isOneway=RpcUtils.isOneway(invoker.getUrl(), invocation);
Future future = rpcContext.getFuture(); //the case on async client invocation
if (future instanceofFutureAdapter) {
deferFinish= true;
((FutureAdapter) future).getFuture().setCallback(newFinishSpanCallback(span));
}returnresult;
}catch (Error |RuntimeException e) {
onError(e, span);throwe;
}finally{if(isOneway) {
span.flush();
}else if (!deferFinish) {
span.finish();
}
}
}static voidparseRemoteAddress(RpcContext rpcContext, Span span) {
InetSocketAddress remoteAddress=rpcContext.getRemoteAddress();if (remoteAddress == null) return;
span.remoteIpAndPort(Platform.get().getHostString(remoteAddress), remoteAddress.getPort());
}static voidonError(Throwable error, Span span) {
span.error(error);if (error instanceofRpcException) {
span.tag("dubbo.error_code", Integer.toString(((RpcException) error).getCode()));
}
}static final Propagation.Getter, String> GETTER =
new Propagation.Getter, String>() {
@Overridepublic String get(Mapcarrier, String key) {returncarrier.get(key);
}
@OverridepublicString toString() {return "Map::get";
}
};static final Propagation.Setter, String> SETTER =
new Propagation.Setter, String>() {
@Overridepublic void put(Mapcarrier, String key, String value) {
carrier.put(key, value);
}
@OverridepublicString toString() {return "Map::set";
}
};static final class FinishSpanCallback implementsResponseCallback {finalSpan span;
FinishSpanCallback(Span span) {this.span =span;
}
@Overridepublic voiddone(Object response) {
span.finish();
}
@Overridepublic voidcaught(Throwable exception) {
onError(exception, span);
span.finish();
}
}
}