源码分析一插件定义
- 拦截MonitorFilter.invoke
- 消费端执行MonitorFilter前已经完成mock,cluster,loadbalance等功能
- 提供者端执行MonitorFilter万后执行dubboInvoker内部的相关业务接口逻辑
public class DubboInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
private static final String ENHANCE_CLASS = "org.apache.dubbo.monitor.support.MonitorFilter";
private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.asf.dubbo.DubboInterceptor";
@Override
protected ClassMatch enhanceClass() {
return NameMatch.byName(ENHANCE_CLASS);
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return null;
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[] {
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("invoke");
}
@Override
public String getMethodsInterceptor() {
return INTERCEPT_CLASS;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}
源码分析一拦截器
- beforeMethod作为消费者createExitSpan,并将ContextCarrier追加到rpc消息上下文的附件中
- beforeMethod提供者 createEntrySpan并将rpc消息上下文的附件的ContextCarrier提取出来,反序列化注入到当前的TracerContext
- afterMethod作为提供者会将当前TraceContext栈中的span加入Segment并上报OAP
- afterMethod作为消费者会将当前TraceContext栈中的span加入Segment
public class DubboInterceptor implements InstanceMethodsAroundInterceptor {
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
Invoker invoker = (Invoker)allArguments[0];
Invocation invocation = (Invocation)allArguments[1];
RpcContext rpcContext = RpcContext.getContext();
boolean isConsumer = rpcContext.isConsumerSide();
URL requestURL = invoker.getUrl();
AbstractSpan span;
final String host = requestURL.getHost();
final int port = requestURL.getPort();
if (isConsumer) {
将tracerContext序列化到ContextCarrier,然后传递给下一个进程
final ContextCarrier contextCarrier = new ContextCarrier();
span = ContextManager.createExitSpan(generateOperationName(requestURL, invocation), contextCarrier, host + ":" + port);
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
通过dubbo的附件传递当前ContextCarrier
rpcContext.getAttachments().put(next.getHeadKey(), next.getHeadValue());
}
} else {
ContextCarrier contextCarrier = new ContextCarrier();
CarrierItem next = contextCarrier.items();
将消费者注入Attachment附件中的ContextCarrier提取出来
while (next.hasNext()) {
next = next.next();
next.setHeadValue(rpcContext.getAttachment(next.getHeadKey()));
}
将contextCarrier解析到当前TracerContext
span = ContextManager.createEntrySpan(generateOperationName(requestURL, invocation), contextCarrier);
}
为当前span打上一些kv键值对
Tags.URL.set(span, generateRequestURL(requestURL, invocation));
span.setComponent(ComponentsDefine.DUBBO);
SpanLayer.asRPCFramework(span);
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Object ret) throws Throwable {
Result result = (Result)ret;
if (result != null && result.getException() != null) {
span中记录异常kv键值对
dealException(result.getException());
}
离开时将Span加入Segment,dubbo Provider一般是EntrySpan此时需要上报OAP consumer端一般是ExitSpan,此时activeSpanStack还存在span不进行上报
ContextManager.stopSpan();
return ret;
}
private String generateOperationName(URL requestURL, Invocation invocation) {
operationName 就是span的端口名称 dubbo的span名称是接口签名
比如com.renxl.DemoService.sayHello(String);
StringBuilder operationName = new StringBuilder();
接口名处理
operationName.append(requestURL.getPath());
方法名处理
operationName.append("." + invocation.getMethodName() + "(");
参数处理
for (Class<?> classes : invocation.getParameterTypes()) {
operationName.append(classes.getSimpleName() + ",");
}
删除最后一个,号
if (invocation.getParameterTypes().length > 0) {
operationName.delete(operationName.length() - 1, operationName.length());
}
operationName.append(")");
return operationName.toString();
}
}
总结
- 跨进程基于ContextCarrier进行TracerContext的序列化和饭序列化
- ContextCarrier放置于插件拦截的中间件当前的请求对象上
- 比如MQ的requestHeader.properties
- 比如dubbo的rpcContext.attachments
|