From c4766ecbf251613bafef55722e26bba554a4aba6 Mon Sep 17 00:00:00 2001 From: Lei Zhiyuan Date: Sun, 3 Jun 2018 19:38:50 +0800 Subject: [PATCH] Add sofa rpc plugin integration (#1210) * sofa rpc integration * remove unused class and method,add component defination * only support after sofa rpc 5.4.0 * set sofarpc componentId be 32 * Add document of component library settings and incuating features abstract. (#1185) * sofa rpc integration * Update UI licenses (#1189) * Update UI licenses for beta version * Update FAQ doc (#1184) * update faq doc * update faq * update faq * Update readme for beta release. (#1191) * New english readme. * New chinese readme. * Fix #1186 Webapp read timeout config (#1192) * Updat ui (#1197) * Change the intercept point of block call way (#1190) * Change the buired point of block call way * Support future way and change the operation name of span * Update screenshot for new release. (#1209) * remove unused class and method,add component defination * only support after sofa rpc 5.4.0 * set sofarpc componentId be 32 * sofa rpc integration * remove unused class and method,add component defination * only support after sofa rpc 5.4.0 * set sofarpc componentId be 32 * sofa rpc integration * remove unused class and method,add component defination * change parent pom version * remove unused dependency --- .../main/resources/component-libraries.yml | 3 + .../test/resources/component-libraries.yml | 3 + .../trace/component/ComponentsDefine.java | 7 +- apm-sniffer/apm-sdk-plugin/pom.xml | 1 + .../apm-sdk-plugin/sofarpc-plugin/pom.xml | 65 +++++++ .../SofaRpcConsumerInstrumentation.java | 67 +++++++ .../sofarpc/SofaRpcConsumerInterceptor.java | 136 ++++++++++++++ .../SofaRpcProviderInstrumentation.java | 67 +++++++ .../sofarpc/SofaRpcProviderInterceptor.java | 115 ++++++++++++ .../src/main/resources/skywalking-plugin.def | 18 ++ .../SofaRpcConsumerInterceptorTest.java | 171 ++++++++++++++++++ .../SofaRpcProviderInterceptorTest.java | 149 +++++++++++++++ 12 files changed, 800 insertions(+), 2 deletions(-) create mode 100644 apm-sniffer/apm-sdk-plugin/sofarpc-plugin/pom.xml create mode 100644 apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcConsumerInstrumentation.java create mode 100644 apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcConsumerInterceptor.java create mode 100644 apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcProviderInstrumentation.java create mode 100644 apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcProviderInterceptor.java create mode 100644 apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/main/resources/skywalking-plugin.def create mode 100644 apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/test/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcConsumerInterceptorTest.java create mode 100644 apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/test/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcProviderInterceptorTest.java 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.is("error")); + assertThat(logData.getLogs().get(1).getValue(), CoreMatchers.is(RuntimeException.class.getName())); + assertNull(logData.getLogs().get(2).getValue()); + } + + private void assertConsumerSpan(AbstractTracingSpan span) { + assertCommonsAttribute(span); + assertTrue(span.isExit()); + } + + private void assertCommonsAttribute(AbstractTracingSpan span) { + List tags = SpanHelper.getTags(span); + assertThat(tags.size(), is(1)); + assertThat(SpanHelper.getLayer(span), CoreMatchers.is(SpanLayer.RPC_FRAMEWORK)); + assertThat(SpanHelper.getComponentId(span), is(43)); + assertThat(tags.get(0).getValue(), is("bolt://127.0.0.1:12200/org.apache.skywalking.apm.test.TestSofaRpcService.test(String)")); + assertThat(span.getOperationName(), is("org.apache.skywalking.apm.test.TestSofaRpcService.test(String)")); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/test/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcProviderInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/test/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcProviderInterceptorTest.java new file mode 100644 index 000000000..4ff2370ae --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/sofarpc-plugin/src/test/java/org/apache/skywalking/apm/plugin/sofarpc/SofaRpcProviderInterceptorTest.java @@ -0,0 +1,149 @@ +/* + * 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.ProviderInvoker; +import org.apache.skywalking.apm.agent.core.conf.Config; +import org.apache.skywalking.apm.agent.core.context.SW3CarrierItem; +import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan; +import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer; +import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment; +import org.apache.skywalking.apm.agent.core.context.trace.TraceSegmentRef; +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.SegmentRefHelper; +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.assertThat; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.when; + +@RunWith(PowerMockRunner.class) +@PowerMockRunnerDelegate(TracingSegmentRunner.class) +@PrepareForTest({RpcInternalContext.class, SofaRequest.class, SofaResponse.class}) +public class SofaRpcProviderInterceptorTest { + + public static final String SKYWALKING_PREFIX = "skywalking."; + + @SegmentStoragePoint + private SegmentStorage segmentStorage; + + @Rule + public AgentServiceRule agentServiceRule = new AgentServiceRule(); + + @Mock + private EnhancedInstance enhancedInstance; + + private SofaRpcProviderInterceptor sofaRpcProviderInterceptor; + + @Mock + private RpcInternalContext rpcContext; + + @Mock + private ProviderInvoker 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 { + sofaRpcProviderInterceptor = new SofaRpcProviderInterceptor(); + + 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(false); + 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 testProviderWithAttachment() throws Throwable { + when(rpcContext.isConsumerSide()).thenReturn(false); + when(sofaRequest.getRequestProp(SKYWALKING_PREFIX + SW3CarrierItem.HEADER_NAME)).thenReturn( + "1.323.4433|3|1|1|#192.168.1.8 :18002|#/portal/|#/testEntrySpan|#AQA*#AQA*Et0We0tQNQA*"); + + sofaRpcProviderInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult); + sofaRpcProviderInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, sofaResponse); + assertProvider(); + } + + private void assertProvider() { + TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); + assertThat(SegmentHelper.getSpans(traceSegment).size(), is(1)); + assertProviderSpan(SegmentHelper.getSpans(traceSegment).get(0)); + assertTraceSegmentRef(traceSegment.getRefs().get(0)); + } + + private void assertTraceSegmentRef(TraceSegmentRef actual) { + assertThat(SegmentRefHelper.getSpanId(actual), is(3)); + assertThat(SegmentRefHelper.getEntryApplicationInstanceId(actual), is(1)); + assertThat(SegmentRefHelper.getTraceSegmentId(actual).toString(), is("1.323.4433")); + } + + private void assertProviderSpan(AbstractTracingSpan span) { + assertCommonsAttribute(span); + assertTrue(span.isEntry()); + } + + private void assertCommonsAttribute(AbstractTracingSpan span) { + List tags = SpanHelper.getTags(span); + assertThat(tags.size(), is(0)); + assertThat(SpanHelper.getLayer(span), CoreMatchers.is(SpanLayer.RPC_FRAMEWORK)); + assertThat(SpanHelper.getComponentId(span), is(43)); + } +}