package com.yirendai.infra.cicada.capture;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.Filter;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.RpcInvocation;
import com.yirendai.infra.cicada.entity.trace.Endpoint;
import com.yirendai.infra.cicada.entity.trace.Span;
import com.yirendai.infra.cicada.utils.IpUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Activate(group = {Constants.PROVIDER, Constants.CONSUMER})
@SuppressWarnings("PMD.CyclomaticComplexity")
public class CicadaDubboFilter implements Filter {
private static final Logger LOGGER = LoggerFactory.getLogger(CicadaDubboFilter.class);
private static Tracer tracer;
// 调用过程拦截
@SuppressWarnings({"PMD.OnlyOneReturn", "PMD.OnlyOneReturn"})
public Result invoke(final Invoker<?> invoker, final Invocation invocation) throws RpcException {
if (tracer == null) {
return invoker.invoke(invocation);
}
final long startTime = System.currentTimeMillis();
final RpcContext context = RpcContext.getContext();
// 传入参数,暂不做处理
// Object[] arguments = context.getArguments();
// for (Object argument : arguments) {
// LOGGER.error("arg:" + argument);
// }
final String localIp = IpUtils.getRealIpWithStaticCache();
final int localPort = context.getLocalPort();
final Endpoint endpoint = new Endpoint(localIp, localPort);
final URL url = context.getUrl();
final String appName = url.getParameter("application");
final String serviceName = url.getServiceInterface();
final String methodName = context.getMethodName();
final boolean isConsumerSide = context.isConsumerSide();
Span span = null;
try {
if (isConsumerSide) { // 是否是消费者
final Span parentSpan = tracer.getParentSpan();
if (parentSpan == null) { // 为rootSpan
// 生成root Span
span = tracer.newSpan(appName, serviceName, methodName);
} else {
span = tracer.newSpan(appName, serviceName, methodName, parentSpan);
}
} else if (context.isProviderSide()) {
final String traceId = invocation.getAttachment(TracerUtils.TRACE_ID);
final String parentId = invocation.getAttachment(TracerUtils.PARENT_SPAN_ID);
final String spanId = invocation.getAttachment(TracerUtils.SPAN_ID);
final boolean sample = traceId != null;
span = tracer.genSpan(appName, serviceName, methodName, traceId, parentId, spanId, sample);
} else {
LOGGER.error("[" + url + "] [notConsumerNorProvider]");
return invoker.invoke(invocation);
}
invokerBefore(invocation, span, endpoint, startTime);
final Result result = invoker.invoke(invocation);
final Throwable throwable = result.getException();
if (throwable != null && !isConsumerSide) {
span.addException(serviceName, methodName, throwable, endpoint);
}
// 返回值
// Object resultValue = result.getValue();
// LOGGER.error("return:" + JSON.toJSONString(resultValue));
return result;
} catch (final RpcException ex) {
if (span != null) {
span.addException(serviceName, methodName, ex, endpoint);
}
throw ex;
} finally {
if (span != null) {
final long end = System.currentTimeMillis();
invokerAfter(endpoint, span, end, isConsumerSide);// 调用后记录annotation
}
}
}
private void invokerAfter(final Endpoint endpoint, final Span span, final long end, final boolean isConsumerSide) {
if (isConsumerSide) {
tracer.clientReceiveRecord(span, endpoint, end);
} else {
tracer.serverSendRecord(span, endpoint, end);
}
}
private void invokerBefore(final Invocation invocation, final Span span, final Endpoint endpoint, final long start) {
final RpcContext context = RpcContext.getContext();
if (context.isConsumerSide()) {
if (span.isSample()) {
tracer.clientSendRecord(span, endpoint, start);
final RpcInvocation rpcInvocation = (RpcInvocation) invocation;
rpcInvocation.setAttachment(TracerUtils.PARENT_SPAN_ID, span.getParentId());
rpcInvocation.setAttachment(TracerUtils.SPAN_ID, span.getId());
rpcInvocation.setAttachment(TracerUtils.TRACE_ID, span.getTraceId());
}
} else if (context.isProviderSide()) {
tracer.serverReceiveRecord(span, endpoint, start);
}
}
// setter
public static void setTracer(final Tracer tra) {
tracer = tra;
}
}