diff --git a/apm-collector/apm-collector-boot/src/main/resources/component-libraries.yml b/apm-collector/apm-collector-boot/src/main/resources/component-libraries.yml
index a99ae6369..c21fa2204 100644
--- a/apm-collector/apm-collector-boot/src/main/resources/component-libraries.yml
+++ b/apm-collector/apm-collector-boot/src/main/resources/component-libraries.yml
@@ -153,6 +153,9 @@ kafka-consumer:
mongodb-driver:
id: 42
languages: Java
+SOFARPC:
+ id: 43
+ languages: Java
# .NET/.NET Core components
# [3000, 4000) for C#/.NET only
diff --git a/apm-collector/apm-collector-configuration/collector-configuration-provider/src/test/resources/component-libraries.yml b/apm-collector/apm-collector-configuration/collector-configuration-provider/src/test/resources/component-libraries.yml
index 267c0d462..5a8f425e7 100644
--- a/apm-collector/apm-collector-configuration/collector-configuration-provider/src/test/resources/component-libraries.yml
+++ b/apm-collector/apm-collector-configuration/collector-configuration-provider/src/test/resources/component-libraries.yml
@@ -124,6 +124,9 @@ Hystrix:
Jedis:
id: 30
languages: Java
+SOFARPC:
+ id: 43
+ languages: Java
# Component Server mapping defines the server display names of some components
diff --git a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
index 7af91a209..6c9c95254 100644
--- a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
+++ b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
@@ -59,7 +59,7 @@ public class ComponentsDefine {
public static final OfficialComponent GRPC = new OfficialComponent(23, "GRPC");
public static final OfficialComponent ELASTIC_JOB = new OfficialComponent(24, "ElasticJob");
-
+
public static final OfficialComponent HTTP_ASYNC_CLIENT = new OfficialComponent(26, "httpasyncclient");
public static final OfficialComponent SERVICECOMB = new OfficialComponent(28, "ServiceComb");
@@ -90,6 +90,8 @@ public class ComponentsDefine {
public static final OfficialComponent MONGO_DRIVER = new OfficialComponent(42, "mongodb-driver");
+ public static final OfficialComponent SOFARPC = new OfficialComponent(43, "SOFARPC");
+
private static ComponentsDefine INSTANCE = new ComponentsDefine();
private String[] components;
@@ -99,7 +101,7 @@ public class ComponentsDefine {
}
public ComponentsDefine() {
- components = new String[43];
+ components = new String[44];
addComponent(TOMCAT);
addComponent(HTTPCLIENT);
addComponent(DUBBO);
@@ -132,6 +134,7 @@ public class ComponentsDefine {
addComponent(KAFKA_PRODUCER);
addComponent(KAFKA_CONSUMER);
addComponent(MONGO_DRIVER);
+ addComponent(SOFARPC);
}
private void addComponent(OfficialComponent component) {
diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml
index 907c13af3..e9f49b257 100644
--- a/apm-sniffer/apm-sdk-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pom.xml
@@ -56,6 +56,7 @@
kafka-v1-plugin
servicecomb-plugin
hystrix-1.x-plugin
+ sofarpc-plugin
pom
diff --git a/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/pom.xml
new file mode 100644
index 000000000..33e4a528f
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/pom.xml
@@ -0,0 +1,65 @@
+
+
+
+
+ apm-sdk-plugin
+ org.apache.skywalking
+ 5.0.0-beta2-SNAPSHOT
+
+ 4.0.0
+
+ sofa-rpc-plugin
+ jar
+
+ sofarpc-plugin
+ http://maven.apache.org
+
+
+ UTF-8
+
+
+
+
+ com.alipay.sofa
+ sofa-rpc-all
+ 5.4.0
+ provided
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+
+ attach-sources
+ none
+
+ jar
+
+
+
+
+
+
+
diff --git a/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcConsumerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcConsumerInstrumentation.java
new file mode 100644
index 000000000..123bb1308
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcConsumerInstrumentation.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.sofarpc;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+
+public class SofaRpcConsumerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.alipay.sofa.rpc.filter.ConsumerInvoker";
+ private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.sofarpc.SofaRpcConsumerInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return null;
+ }
+
+ @Override
+ protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("invoke");
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return INTERCEPT_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcConsumerInterceptor.java b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcConsumerInterceptor.java
new file mode 100644
index 000000000..18e5ae3ae
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcConsumerInterceptor.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.sofarpc;
+
+import com.alipay.sofa.rpc.client.ProviderInfo;
+import com.alipay.sofa.rpc.context.RpcInternalContext;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import org.apache.skywalking.apm.agent.core.context.CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+
+import java.lang.reflect.Method;
+
+/**
+ * @author leizhiyuan
+ */
+public class SofaRpcConsumerInterceptor implements InstanceMethodsAroundInterceptor {
+
+ public static final String SKYWALKING_PREFIX = "skywalking.";
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+ SofaRequest sofaRequest = (SofaRequest) allArguments[0];
+ RpcInternalContext rpcContext = RpcInternalContext.getContext();
+
+ ProviderInfo providerInfo = rpcContext.getProviderInfo();
+
+ AbstractSpan span = null;
+
+ final String host = providerInfo.getHost();
+ final int port = providerInfo.getPort();
+ final ContextCarrier contextCarrier = new ContextCarrier();
+ final String operationName = generateOperationName(providerInfo, sofaRequest);
+ span = ContextManager.createExitSpan(operationName, contextCarrier, host + ":" + port);
+ CarrierItem next = contextCarrier.items();
+ while (next.hasNext()) {
+ next = next.next();
+ String key = next.getHeadKey();
+ String skyWalkingKey = SKYWALKING_PREFIX + key;
+ sofaRequest.addRequestProp(skyWalkingKey, next.getHeadValue());
+ }
+
+ Tags.URL.set(span, generateRequestURL(providerInfo, sofaRequest));
+ span.setComponent(ComponentsDefine.SOFARPC);
+ SpanLayer.asRPCFramework(span);
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Object ret) throws Throwable {
+ SofaResponse result = (SofaResponse) ret;
+ if (result != null && result.isError()) {
+ dealException((Throwable) result.getAppResponse());
+ }
+
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ dealException(t);
+ }
+
+ /**
+ * Log the throwable, which occurs in Dubbo RPC service.
+ */
+ private void dealException(Throwable throwable) {
+ AbstractSpan span = ContextManager.activeSpan();
+ span.errorOccurred();
+ span.log(throwable);
+ }
+
+ /**
+ * Format operation name. e.g. org.apache.skywalking.apm.plugin.test.Test.test(String)
+ *
+ * @return operation name.
+ */
+ private String generateOperationName(ProviderInfo providerInfo, SofaRequest sofaRequest) {
+ StringBuilder operationName = new StringBuilder();
+ operationName.append(sofaRequest.getInterfaceName());
+ operationName.append("." + sofaRequest.getMethodName() + "(");
+ for (String arg : sofaRequest.getMethodArgSigs()) {
+ operationName.append(arg + ",");
+ }
+
+ if (sofaRequest.getMethodArgs().length > 0) {
+ operationName.delete(operationName.length() - 1, operationName.length());
+ }
+
+ operationName.append(")");
+
+ return operationName.toString();
+ }
+
+ /**
+ * Format request url.
+ * e.g. bolt://127.0.0.1:20880/org.apache.skywalking.apm.plugin.test.Test.test(String).
+ *
+ * @return request url.
+ */
+ private String generateRequestURL(ProviderInfo providerInfo, SofaRequest sofaRequest) {
+ StringBuilder requestURL = new StringBuilder();
+ requestURL.append(providerInfo.getProtocolType() + "://");
+ requestURL.append(providerInfo.getHost());
+ requestURL.append(":" + providerInfo.getPort() + "/");
+ requestURL.append(generateOperationName(providerInfo, sofaRequest));
+ return requestURL.toString();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcProviderInstrumentation.java b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcProviderInstrumentation.java
new file mode 100644
index 000000000..1adafb6fb
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcProviderInstrumentation.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.sofarpc;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+
+public class SofaRpcProviderInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.alipay.sofa.rpc.filter.ProviderInvoker";
+ private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.sofarpc.SofaRpcProviderInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return null;
+ }
+
+ @Override
+ protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("invoke");
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return INTERCEPT_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcProviderInterceptor.java b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcProviderInterceptor.java
new file mode 100644
index 000000000..8d89ce753
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcProviderInterceptor.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.sofarpc;
+
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import org.apache.skywalking.apm.agent.core.context.CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+
+import java.lang.reflect.Method;
+
+/**
+ * @author leizhiyuan
+ */
+public class SofaRpcProviderInterceptor implements InstanceMethodsAroundInterceptor {
+
+ public static final String SKYWALKING_PREFIX = "skywalking.";
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+ SofaRequest sofaRequest = (SofaRequest) allArguments[0];
+
+ AbstractSpan span = null;
+
+ ContextCarrier contextCarrier = new ContextCarrier();
+ CarrierItem next = contextCarrier.items();
+ while (next.hasNext()) {
+ next = next.next();
+ final String headKey = next.getHeadKey();
+ final Object attachment = sofaRequest.getRequestProp(SKYWALKING_PREFIX + headKey);
+ if (attachment != null) {
+ next.setHeadValue(attachment.toString());
+ } else {
+ next.setHeadValue("");
+ }
+ }
+ span = ContextManager.createEntrySpan(generateViewPoint(sofaRequest), contextCarrier);
+
+ span.setComponent(ComponentsDefine.SOFARPC);
+ SpanLayer.asRPCFramework(span);
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Object ret) throws Throwable {
+ SofaResponse result = (SofaResponse) ret;
+ if (result != null && result.isError()) {
+ dealException((Throwable) result.getAppResponse());
+ }
+
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ dealException(t);
+ }
+
+ /**
+ * Log the throwable, which occurs in Dubbo RPC service.
+ */
+ private void dealException(Throwable throwable) {
+ AbstractSpan span = ContextManager.activeSpan();
+ span.errorOccurred();
+ span.log(throwable);
+ }
+
+ /**
+ * Format operation name. e.g. org.apache.skywalking.apm.plugin.test.Test.test(String)
+ *
+ * @return operation name.
+ */
+ private String generateViewPoint(SofaRequest sofaRequest) {
+ StringBuilder operationName = new StringBuilder();
+ operationName.append(sofaRequest.getInterfaceName());
+ operationName.append("." + sofaRequest.getMethodName() + "(");
+ for (String arg : sofaRequest.getMethodArgSigs()) {
+ operationName.append(arg + ",");
+ }
+
+ if (sofaRequest.getMethodArgs().length > 0) {
+ operationName.delete(operationName.length() - 1, operationName.length());
+ }
+
+ operationName.append(")");
+
+ return operationName.toString();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 000000000..9850487d5
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+sofarpc=org.apache.skywalking.apm.plugin.sofarpc.SofaRpcConsumerInstrumentation
+sofarpc=org.apache.skywalking.apm.plugin.sofarpc.SofaRpcProviderInstrumentation
diff --git a/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/test/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcConsumerInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/test/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcConsumerInterceptorTest.java
new file mode 100644
index 000000000..9962b01c6
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/test/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcConsumerInterceptorTest.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.sofarpc;
+
+import com.alipay.sofa.rpc.client.ProviderInfo;
+import com.alipay.sofa.rpc.context.RpcInternalContext;
+import com.alipay.sofa.rpc.core.request.SofaRequest;
+import com.alipay.sofa.rpc.core.response.SofaResponse;
+import com.alipay.sofa.rpc.filter.ConsumerInvoker;
+import org.apache.skywalking.apm.agent.core.conf.Config;
+import org.apache.skywalking.apm.agent.core.context.trace.*;
+import org.apache.skywalking.apm.agent.core.context.util.KeyValuePair;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
+import org.apache.skywalking.apm.agent.test.helper.SpanHelper;
+import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.hamcrest.CoreMatchers;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.modules.junit4.PowerMockRunnerDelegate;
+
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.*;
+import static org.powermock.api.mockito.PowerMockito.when;
+
+@RunWith(PowerMockRunner.class)
+@PowerMockRunnerDelegate(TracingSegmentRunner.class)
+@PrepareForTest({RpcInternalContext.class, SofaRequest.class, SofaResponse.class})
+public class SofaRpcConsumerInterceptorTest {
+
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+
+ @Rule
+ public AgentServiceRule agentServiceRule = new AgentServiceRule();
+
+ @Mock
+ private EnhancedInstance enhancedInstance;
+
+ private SofaRpcConsumerInterceptor sofaRpcConsumerInterceptor;
+
+ @Mock
+ private RpcInternalContext rpcContext;
+
+ @Mock
+ private ConsumerInvoker invoker;
+
+ private SofaRequest sofaRequest = PowerMockito.mock(SofaRequest.class);
+ @Mock
+ private MethodInterceptResult methodInterceptResult;
+
+ private SofaResponse sofaResponse = PowerMockito.mock(SofaResponse.class);
+
+ private Object[] allArguments;
+ private Class[] argumentTypes;
+
+ @Before
+ public void setUp() throws Exception {
+ sofaRpcConsumerInterceptor = new SofaRpcConsumerInterceptor();
+
+ PowerMockito.mockStatic(RpcInternalContext.class);
+
+ when(sofaRequest.getMethodName()).thenReturn("test");
+ when(sofaRequest.getMethodArgSigs()).thenReturn(new String[] {"String"});
+ when(sofaRequest.getMethodArgs()).thenReturn(new Object[] {"abc"});
+ when(sofaRequest.getInterfaceName()).thenReturn("org.apache.skywalking.apm.test.TestSofaRpcService");
+ PowerMockito.when(RpcInternalContext.getContext()).thenReturn(rpcContext);
+ when(rpcContext.isConsumerSide()).thenReturn(true);
+ final ProviderInfo providerInfo = new ProviderInfo();
+ providerInfo.setHost("127.0.0.1");
+ providerInfo.setPort(12200);
+ when(rpcContext.getProviderInfo()).thenReturn(providerInfo);
+ allArguments = new Object[] {sofaRequest};
+ argumentTypes = new Class[] {sofaRequest.getClass()};
+ Config.Agent.APPLICATION_CODE = "SOFARPC-TestCases-APP";
+ }
+
+ @Test
+ public void testConsumerWithAttachment() throws Throwable {
+ sofaRpcConsumerInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
+ sofaRpcConsumerInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, sofaResponse);
+
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+ List spans = SegmentHelper.getSpans(traceSegment);
+ assertThat(spans.size(), is(1));
+ assertConsumerSpan(spans.get(0));
+ }
+
+ @Test
+ public void testConsumerWithException() throws Throwable {
+ sofaRpcConsumerInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
+ sofaRpcConsumerInterceptor.handleMethodException(enhancedInstance, null, allArguments, argumentTypes, new RuntimeException());
+ sofaRpcConsumerInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, sofaResponse);
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+ assertConsumerTraceSegmentInErrorCase(traceSegment);
+ }
+
+ @Test
+ public void testConsumerWithResultHasException() throws Throwable {
+ when(sofaResponse.isError()).thenReturn(true);
+ when(sofaResponse.getAppResponse()).thenReturn(new RuntimeException());
+
+ sofaRpcConsumerInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
+ sofaRpcConsumerInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, sofaResponse);
+
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+ assertConsumerTraceSegmentInErrorCase(traceSegment);
+ }
+
+ private void assertConsumerTraceSegmentInErrorCase(
+ TraceSegment traceSegment) {
+ List spans = SegmentHelper.getSpans(traceSegment);
+ assertThat(spans.size(), is(1));
+ assertConsumerSpan(spans.get(0));
+ AbstractTracingSpan span = spans.get(0);
+ assertThat(SpanHelper.getLogs(span).size(), is(1));
+ assertErrorLog(SpanHelper.getLogs(span).get(0));
+ }
+
+ private void assertErrorLog(LogDataEntity logData) {
+ assertThat(logData.getLogs().size(), is(4));
+ assertThat(logData.getLogs().get(0).getValue(), CoreMatchers.