From ced5cb28283b56456f33fd2f7d038c3770dd3914 Mon Sep 17 00:00:00 2001 From: yoje Date: Wed, 11 Mar 2020 13:04:58 +0800 Subject: [PATCH] Add finagle plugin (#4441) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add finagle plugin (#4433) * fix failed checks for pr(#4441) * Add licenses for some files * Update Supported doc * Add finagle to test component-libraries.yml * Add finagle automatic tests into CI * Add comments * update comments * Remove CompatibilityChecker * Move query-protocol submodule to the right version * Remove `enhancedInstance.setSkyWalkingDynamicField` in `ClientTracingFilterInterceptor`. * Update expectedData.yaml of finagle tests * Use lazy ContextCarrier injection. * Add comments for `ContextCarrierHelper` * Fix ContextHolderFactory to avoid context pollution Co-authored-by: huangyongjie Co-authored-by: 吴晟 Wu Sheng --- .github/workflows/plugins-test.yaml | 8 +- .../trace/component/ComponentsDefine.java | 2 + .../finagle-6.25.x-plugin/pom.xml | 83 ++++++ .../plugin/finagle/AbstractInterceptor.java | 112 +++++++++ .../plugin/finagle/AnnotationInterceptor.java | 74 ++++++ .../ClientDestTracingFilterInterceptor.java | 84 +++++++ .../ClientTracingFilterInterceptor.java | 92 +++++++ .../apm/plugin/finagle/CodecUtils.java | 155 ++++++++++++ .../apm/plugin/finagle/Constants.java | 24 ++ .../plugin/finagle/ContextCarrierHelper.java | 56 +++++ .../apm/plugin/finagle/ContextHolder.java | 90 +++++++ .../plugin/finagle/ContextHolderFactory.java | 238 ++++++++++++++++++ .../apm/plugin/finagle/FinagleCtxs.java | 70 ++++++ .../ServerTracingFilterInterceptor.java | 88 +++++++ .../define/AbstractInstrumentation.java | 34 +++ .../define/AnnotationInstrumentation.java | 81 ++++++ ...ClientDestTracingFilterInstrumetation.java | 79 ++++++ .../ClientTracingFilterInstrumentation.java | 67 +++++ .../ServerTracingFilterInstrumentation.java | 66 +++++ .../src/main/resources/skywalking-plugin.def | 20 ++ .../apm/plugin/finagle/SWContextCarrier.scala | 57 +++++ .../finagle/AbstractTracingFilterTest.java | 117 +++++++++ .../ClientTracingFilterInterceptorTest.java | 112 +++++++++ .../apm/plugin/finagle/CodecUtilsTest.java | 79 ++++++ .../finagle/ContextHolderFactoryTest.java | 145 +++++++++++ .../plugin/finagle/MockEnhancedInstance.java | 36 +++ .../ServerTracingFilterInterceptorTest.java | 144 +++++++++++ apm-sniffer/apm-sdk-plugin/pom.xml | 1 + .../java-agent/Supported-list.md | 1 + .../main/resources/component-libraries.yml | 3 + .../test/resources/component-libraries.yml | 3 + .../finagle-17.10.x-scenario/bin/startup.sh | 21 ++ .../config/expectedData.yaml | 78 ++++++ .../configuration.yml | 23 ++ .../finagle-17.10.x-scenario/pom.xml | 170 +++++++++++++ .../src/main/assembly/assembly.xml | 41 +++ .../finagle/FinagleRpcApplication.java | 55 ++++ .../finagle/controller/CaseController.java | 50 ++++ .../service/FinagleRpcDemoServiceImpl.java | 30 +++ .../src/main/resources/application.yaml | 21 ++ .../src/main/thrift/service.thrift | 23 ++ .../support-version.list | 46 ++++ .../finagle-6.25.x-scenario/bin/startup.sh | 21 ++ .../config/expectedData.yaml | 86 +++++++ .../finagle-6.25.x-scenario/configuration.yml | 21 ++ .../scenarios/finagle-6.25.x-scenario/pom.xml | 177 +++++++++++++ .../src/main/assembly/assembly.xml | 41 +++ .../finagle/FinagleRpcApplication.java | 55 ++++ .../finagle/controller/CaseController.java | 50 ++++ .../service/FinagleRpcDemoServiceImpl.java | 30 +++ .../src/main/resources/application.yml | 20 ++ .../src/main/thrift/service.thrift | 23 ++ .../support-version.list | 34 +++ .../finagle-6.44.x-scenario/bin/startup.sh | 21 ++ .../config/expectedData.yaml | 78 ++++++ .../finagle-6.44.x-scenario/configuration.yml | 23 ++ .../scenarios/finagle-6.44.x-scenario/pom.xml | 170 +++++++++++++ .../src/main/assembly/assembly.xml | 41 +++ .../finagle/FinagleRpcApplication.java | 55 ++++ .../finagle/controller/CaseController.java | 50 ++++ .../service/FinagleRpcDemoServiceImpl.java | 30 +++ .../src/main/resources/application.yaml | 21 ++ .../src/main/thrift/service.thrift | 23 ++ .../support-version.list | 20 ++ 64 files changed, 3868 insertions(+), 1 deletion(-) create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/pom.xml create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/AbstractInterceptor.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/AnnotationInterceptor.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ClientDestTracingFilterInterceptor.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ClientTracingFilterInterceptor.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/CodecUtils.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/Constants.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ContextCarrierHelper.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ContextHolder.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ContextHolderFactory.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/FinagleCtxs.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ServerTracingFilterInterceptor.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/AbstractInstrumentation.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/AnnotationInstrumentation.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/ClientDestTracingFilterInstrumetation.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/ClientTracingFilterInstrumentation.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/ServerTracingFilterInstrumentation.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/resources/skywalking-plugin.def create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/scala/org/apache/skywalking/apm/plugin/finagle/SWContextCarrier.scala create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/AbstractTracingFilterTest.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/ClientTracingFilterInterceptorTest.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/CodecUtilsTest.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/ContextHolderFactoryTest.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/MockEnhancedInstance.java create mode 100644 apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/ServerTracingFilterInterceptorTest.java create mode 100644 test/plugin/scenarios/finagle-17.10.x-scenario/bin/startup.sh create mode 100644 test/plugin/scenarios/finagle-17.10.x-scenario/config/expectedData.yaml create mode 100644 test/plugin/scenarios/finagle-17.10.x-scenario/configuration.yml create mode 100644 test/plugin/scenarios/finagle-17.10.x-scenario/pom.xml create mode 100644 test/plugin/scenarios/finagle-17.10.x-scenario/src/main/assembly/assembly.xml create mode 100644 test/plugin/scenarios/finagle-17.10.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/FinagleRpcApplication.java create mode 100644 test/plugin/scenarios/finagle-17.10.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/controller/CaseController.java create mode 100644 test/plugin/scenarios/finagle-17.10.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/service/FinagleRpcDemoServiceImpl.java create mode 100644 test/plugin/scenarios/finagle-17.10.x-scenario/src/main/resources/application.yaml create mode 100644 test/plugin/scenarios/finagle-17.10.x-scenario/src/main/thrift/service.thrift create mode 100644 test/plugin/scenarios/finagle-17.10.x-scenario/support-version.list create mode 100644 test/plugin/scenarios/finagle-6.25.x-scenario/bin/startup.sh create mode 100644 test/plugin/scenarios/finagle-6.25.x-scenario/config/expectedData.yaml create mode 100644 test/plugin/scenarios/finagle-6.25.x-scenario/configuration.yml create mode 100644 test/plugin/scenarios/finagle-6.25.x-scenario/pom.xml create mode 100644 test/plugin/scenarios/finagle-6.25.x-scenario/src/main/assembly/assembly.xml create mode 100644 test/plugin/scenarios/finagle-6.25.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/FinagleRpcApplication.java create mode 100644 test/plugin/scenarios/finagle-6.25.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/controller/CaseController.java create mode 100644 test/plugin/scenarios/finagle-6.25.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/service/FinagleRpcDemoServiceImpl.java create mode 100644 test/plugin/scenarios/finagle-6.25.x-scenario/src/main/resources/application.yml create mode 100644 test/plugin/scenarios/finagle-6.25.x-scenario/src/main/thrift/service.thrift create mode 100644 test/plugin/scenarios/finagle-6.25.x-scenario/support-version.list create mode 100644 test/plugin/scenarios/finagle-6.44.x-scenario/bin/startup.sh create mode 100644 test/plugin/scenarios/finagle-6.44.x-scenario/config/expectedData.yaml create mode 100644 test/plugin/scenarios/finagle-6.44.x-scenario/configuration.yml create mode 100644 test/plugin/scenarios/finagle-6.44.x-scenario/pom.xml create mode 100644 test/plugin/scenarios/finagle-6.44.x-scenario/src/main/assembly/assembly.xml create mode 100644 test/plugin/scenarios/finagle-6.44.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/FinagleRpcApplication.java create mode 100644 test/plugin/scenarios/finagle-6.44.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/controller/CaseController.java create mode 100644 test/plugin/scenarios/finagle-6.44.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/service/FinagleRpcDemoServiceImpl.java create mode 100644 test/plugin/scenarios/finagle-6.44.x-scenario/src/main/resources/application.yaml create mode 100644 test/plugin/scenarios/finagle-6.44.x-scenario/src/main/thrift/service.thrift create mode 100644 test/plugin/scenarios/finagle-6.44.x-scenario/support-version.list diff --git a/.github/workflows/plugins-test.yaml b/.github/workflows/plugins-test.yaml index a945244e2..b8f2091f2 100644 --- a/.github/workflows/plugins-test.yaml +++ b/.github/workflows/plugins-test.yaml @@ -239,7 +239,7 @@ jobs: - name: Run kotlin coroutine 1.0.1-1.3.3 (4) run: bash test/plugin/run.sh kotlin-coroutine-scenario - Ehcache_Undertow_Jedis: + Ehcache_Undertow_Jedis_Finagle: runs-on: ubuntu-18.04 timeout-minutes: 90 strategy: @@ -271,6 +271,12 @@ jobs: run: bash test/plugin/run.sh undertow-scenario - name: Run jedis 2.4.0-2.9.0 (18) run: bash test/plugin/run.sh jedis-scenario + - name: Run finagle 6.25.0-6.43.0 + run: bash test/plugin/run.sh finagle-6.25.x-scenario + - name: Run finagle 6.44.0-7.1.0 + run: bash test/plugin/run.sh finagle-6.44.x-scenario + - name: Run finagle 17.10.0-20.1.0 + run: bash test/plugin/run.sh finagle-17.10.x-scenario Spring41x_SolrJ-Http: runs-on: ubuntu-18.04 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 67171afcc..136ebb6df 100755 --- 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 @@ -154,4 +154,6 @@ public class ComponentsDefine { public static final OfficialComponent AVRO_CLIENT = new OfficialComponent(83, "AvroClient"); public static final OfficialComponent UNDERTOW = new OfficialComponent(84, "Undertow"); + + public static final OfficialComponent FINAGLE = new OfficialComponent(85, "Finagle"); } diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/pom.xml new file mode 100644 index 000000000..9f6d3638b --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/pom.xml @@ -0,0 +1,83 @@ + + + + + + apm-sdk-plugin + org.apache.skywalking + 7.0.0-SNAPSHOT + + 4.0.0 + + apm-finagle-6.25.x-plugin + jar + + apm-finagle-6.25.x-plugin + http://maven.apache.org + + + UTF-8 + 6.34.0 + 2.11.8 + + + + + com.twitter + finagle-core_2.11 + ${finagle.version} + provided + + + org.scala-lang + scala-library + ${scala.library.version} + provided + + + + + + + net.alchim31.maven + scala-maven-plugin + 4.3.1 + + + scala-compile-first + process-resources + + add-source + compile + + + + scala-test-compile + process-test-resources + + testCompile + + + + + + + \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/AbstractInterceptor.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/AbstractInterceptor.java new file mode 100644 index 000000000..ef5c1165b --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/AbstractInterceptor.java @@ -0,0 +1,112 @@ +/* + * 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.finagle; + +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; + +import java.lang.reflect.Method; + +/** + * Finagle is an asynchronous rpc framework, every method in its rpc call stack return a future, which means each + * method may be executed in other thread. The data transfer mechanism across threads or across processes of finagle is + * achieved by using com.twitter.finagle.context. There are two kinds of context, LocalContext used to transfer data + * across threads, MarshalledContext used to transfer data across processes. + * + *

A simple finagle rpc stack

+ * + * +-----------------------------------------------------------------------------------------------+ + * | Client Server | + * | | + * | initiate rpc (user thread) invoke service (usually io thread) | + * | | /|\ | + * | \|/ | | + * | ClientTracingFilter (user thread) +------------------+ | + * | | | other filters | | + * | \|/ | in the | | + * | +------------------+ | rpc call stack | | + * | | other filters | +------------------+ | + * | | in the | (other thread) /|\ | + * | | rpc call stack | | | + * | +----------+-------+ | | + * | | ServerTracingFilter (usually io thread) | + * | \|/ /|\ | + * | ClientDestTracingFilter (other thread) | | + * | | +------------------+ | + * | \|/ | other filters | | + * | +------------------+ | in the | (usually io thread) | + * | | other filters | | rpc call stack | | + * | | in the | (other thread) +------------------+ | + * | | rpc call stack | /|\ | + * | +----------+-------+ | | + * | | | | + * | \|/ | | + * | +----------------------------------------------------------------------------------+ | + * | | Protocol specified transport | | + * | | such as http, thrift, redis, mysql, etc. | | + * | +----------------------------------------------------------------------------------+ | + * +-----------------------------------------------------------------------------------------------+ + * + *

Plugin Implementation

+ * + * In client side, We create finagle exitspan in the ClientTracingFilter, then add SWContextCarrier into the + * MarshalledContext, however in ClientTracingFilter, we can not know the remote address, So we add exitspan + * into the LocalContext, when the request reaches ClientDestTracingFilter, we know the remote address, then we can get + * exitspan from LocalContext and set remote address. + * + * In Server side, with default config, the ServerTracingFilter and the user code will be executed in the same thread, + * unless users use a com.twitter.util.FuturePool to execute business code or the com.twitter.finagle.filter + * .OffloadFilter is enabled which default is disabled, in bose cases, we had better do nothing and leave this to + * users, they can custom FuturePool to propagate context correctly. So we just create finagel entryspan in + * ServerTracingFilter to meet the default behavior of finagle. + */ +abstract class AbstractInterceptor implements InstanceConstructorInterceptor, InstanceMethodsAroundInterceptor { + @Override + public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { + onConstructImpl(objInst, allArguments); + } + + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, MethodInterceptResult result) throws Throwable { + beforeMethodImpl(objInst, method, allArguments, argumentsTypes, result); + } + + @Override + public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, Object ret) throws Throwable { + return afterMethodImpl(objInst, method, allArguments, argumentsTypes, ret); + } + + @Override + public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, Throwable t) { + handleMethodExceptionImpl(objInst, method, allArguments, argumentsTypes, t); + } + + abstract protected void onConstructImpl(EnhancedInstance objInst, Object[] allArguments); + + abstract protected void beforeMethodImpl(EnhancedInstance objInst, Method method, Object[] allArguments, + Class[] argumentsTypes, MethodInterceptResult result) throws Throwable; + + abstract protected Object afterMethodImpl(EnhancedInstance objInst, Method method, Object[] allArguments, + Class[] argumentsTypes, Object ret) throws Throwable; + + abstract protected void handleMethodExceptionImpl(EnhancedInstance objInst, Method method, Object[] allArguments, + Class[] argumentsTypes, Throwable t); +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/AnnotationInterceptor.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/AnnotationInterceptor.java new file mode 100644 index 000000000..51492e273 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/AnnotationInterceptor.java @@ -0,0 +1,74 @@ +/* + * 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.finagle; + +import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; +import org.apache.skywalking.apm.agent.core.context.trace.ExitSpan; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; + +import static org.apache.skywalking.apm.plugin.finagle.ContextCarrierHelper.tryInjectContext; +import static org.apache.skywalking.apm.plugin.finagle.FinagleCtxs.getSpan; + +/** + * Finagle use Annotation to represent data that tracing system interested, usually these annotations are created by + * filters after ClientTracingFilter in the rpc call stack. We can intercept annotations that we interested. + */ +public class AnnotationInterceptor { + + abstract static class Abstract implements InstanceConstructorInterceptor { + + @Override + public void onConstruct(EnhancedInstance enhancedInstance, Object[] objects) { + onConstruct(enhancedInstance, objects, getSpan()); + } + + protected abstract void onConstruct(EnhancedInstance enhancedInstance, Object[] objects, AbstractSpan span); + } + + /** + * When we create exitspan in ClientTracingFilter, we can't know the operation name, however the Rpc annotation + * contains the operation name we need, so we intercept the constructor of this Annotation and set operation name + * to exitspan. + */ + public static class Rpc extends Abstract { + + @Override + protected void onConstruct(EnhancedInstance enhancedInstance, Object[] objects, AbstractSpan span) { + if (objects != null && objects.length == 1) { + String rpc = (String) objects[0]; + if (span != null && span.isExit()) { + /* + * The Rpc Annotation is created both in client side and server side, in server side, this + * annotation is created only in finagle versions below 17.12.0. + * + * If the span is not null, which means we are in the client side, we just set op name to the + * exitspan. + * + * If the span is null, which means we are in the server side with finagle version below 17.12.0. + * In server side, we don't need this annotation, because we can get op name from Contexts.broadcast + * which comes from client. + */ + span.setOperationName(rpc); + tryInjectContext((ExitSpan) span); + } + } + } + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ClientDestTracingFilterInterceptor.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ClientDestTracingFilterInterceptor.java new file mode 100644 index 000000000..5f083de71 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ClientDestTracingFilterInterceptor.java @@ -0,0 +1,84 @@ +/* + * 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.finagle; + +import com.twitter.finagle.Address; +import org.apache.skywalking.apm.agent.core.context.ContextManager; +import org.apache.skywalking.apm.agent.core.context.trace.ExitSpan; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; + +import java.lang.reflect.Method; +import java.net.InetSocketAddress; + +import static org.apache.skywalking.apm.plugin.finagle.ContextCarrierHelper.tryInjectContext; +import static org.apache.skywalking.apm.plugin.finagle.ContextHolderFactory.getLocalContextHolder; +import static org.apache.skywalking.apm.plugin.finagle.FinagleCtxs.getSpan; + +/** + * When we create exitspan in ClientTracingFilter, we can't know the remote address because the ClientTracingFilter + * is above the loadbalancefilter in the rpc call stack. However by intercept the ClientDestTracingFilter, we can get + * the remote adress and set it to exitspan and contextCarrier. + */ +public class ClientDestTracingFilterInterceptor extends AbstractInterceptor { + + @Override + public void onConstructImpl(EnhancedInstance enhancedInstance, Object[] objects) { + enhancedInstance.setSkyWalkingDynamicField(getRemote(objects)); + } + + @Override + public void beforeMethodImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class[] classes, MethodInterceptResult methodInterceptResult) throws Throwable { + String peer = (String) enhancedInstance.getSkyWalkingDynamicField(); + getLocalContextHolder().let(FinagleCtxs.PEER_HOST, peer); + tryInjectContext((ExitSpan) getSpan()); + } + + @Override + public Object afterMethodImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class[] classes, Object o) throws Throwable { + getLocalContextHolder().remove(FinagleCtxs.PEER_HOST); + return o; + } + + @Override + public void handleMethodExceptionImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects, + Class[] classes, Throwable t) { + ContextManager.activeSpan().errorOccurred().log(t); + } + + private String getRemote(Object[] objects) { + if (objects == null || objects.length == 0) { + return ""; + } + if (objects[0] instanceof InetSocketAddress) { + /* + * Compatible with versions below 6.33.0 + * 6.33.0 and below use {@link java.net.SocketAddress} as parameter + */ + return formatPeer((InetSocketAddress) objects[0]); + } else if (objects[0] instanceof Address.Inet) { + return formatPeer(((Address.Inet) objects[0]).addr()); + } + return ""; + } + + private String formatPeer(InetSocketAddress socketAddress) { + return socketAddress.getAddress().getHostAddress() + ":" + socketAddress.getPort(); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ClientTracingFilterInterceptor.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ClientTracingFilterInterceptor.java new file mode 100644 index 000000000..8aae4c15b --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ClientTracingFilterInterceptor.java @@ -0,0 +1,92 @@ +/* + * 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.finagle; + +import com.twitter.util.Future; +import com.twitter.util.FutureEventListener; +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.MethodInterceptResult; + +import java.lang.reflect.Method; + +import static org.apache.skywalking.apm.network.trace.component.ComponentsDefine.FINAGLE; +import static org.apache.skywalking.apm.plugin.finagle.Constants.PENDING_OP_NAME; +import static org.apache.skywalking.apm.plugin.finagle.ContextHolderFactory.getLocalContextHolder; +import static org.apache.skywalking.apm.plugin.finagle.ContextHolderFactory.getMarshalledContextHolder; +import static org.apache.skywalking.apm.plugin.finagle.FinagleCtxs.SW_SPAN; +import static org.apache.skywalking.apm.plugin.finagle.FinagleCtxs.getSpan; + +public class ClientTracingFilterInterceptor extends AbstractInterceptor { + + @Override + protected void onConstructImpl(EnhancedInstance objInst, Object[] allArguments) { + + } + + @Override + public void beforeMethodImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class[] classes, + MethodInterceptResult methodInterceptResult) throws Throwable { + /* + * At this time, we can't know the operation name and peer address, so we just use placeholders here, the + * operation name will be filled by {@link AnnotationInterceptor$Rpc} and the peer address will be filled by + * {@link ClientDestTracingFilterInterceptor} later. + */ + AbstractSpan finagleSpan = ContextManager.createExitSpan(PENDING_OP_NAME, ""); + + finagleSpan.setComponent(FINAGLE); + SpanLayer.asRPCFramework(finagleSpan); + + getLocalContextHolder().let(SW_SPAN, finagleSpan); + getMarshalledContextHolder().let(SWContextCarrier$.MODULE$, new SWContextCarrier()); + } + + @Override + public Object afterMethodImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class[] classes, Object ret) throws Throwable { + + final AbstractSpan finagleSpan = getSpan(); + getLocalContextHolder().remove(SW_SPAN); + getMarshalledContextHolder().remove(SWContextCarrier$.MODULE$); + + finagleSpan.prepareForAsync(); + ContextManager.stopSpan(finagleSpan); + + ((Future) ret).addEventListener(new FutureEventListener() { + @Override + public void onSuccess(Object value) { + finagleSpan.asyncFinish(); + } + + @Override + public void onFailure(Throwable cause) { + finagleSpan.errorOccurred(); + finagleSpan.log(cause); + finagleSpan.asyncFinish(); + } + }); + return ret; + } + + @Override + public void handleMethodExceptionImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class[] classes, Throwable throwable) { + ContextManager.activeSpan().errorOccurred().log(throwable); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/CodecUtils.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/CodecUtils.java new file mode 100644 index 000000000..52426e557 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/CodecUtils.java @@ -0,0 +1,155 @@ +/* + * 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.finagle; + +import com.twitter.io.Buf; +import com.twitter.io.Bufs; +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.logging.api.ILog; +import org.apache.skywalking.apm.agent.core.logging.api.LogManager; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +public class CodecUtils { + + static ILog LOGGER = LogManager.getLogger(CodecUtils.class); + + private static ThreadLocal REUSED_BOS = new ThreadLocal() { + @Override + protected ByteArrayOutputStream initialValue() { + return new ByteArrayOutputStream(128); + } + }; + + private static ByteArrayOutputStream getBos() { + ByteArrayOutputStream bos = REUSED_BOS.get(); + bos.reset(); + return bos; + } + + /** + * Encodes the swContextCarrier to byte array. + * + * SWContextCarrier consists of some strings, such as operation name, {@link CarrierItem#getHeadKey()}, + * {@link CarrierItem#getHeadValue()}. We encode each string to byte array by + * {@link #encodeStringToBytes(String)}, then assemble these byte arrays in a certain order, each byte array has + * a fixed length of 4 bytes before it to record the length. The format as follow: + * + * |length of following byte array,4 byte|byte array|length of following byte array,4 byte|byte array|... + * + * The first byte array is operation name, followed by byte array of the key of first {@code CarrierItem}, + * followed by byte array of the value of first {@code CarrierItem}, followed by byte array of second {@code + * CarrierItem}, and so on. + * + * @param swContextCarrier the swContextCarrier to encode + * @return + */ + static Buf encode(SWContextCarrier swContextCarrier) { + ByteArrayOutputStream bos = getBos(); + try (DataOutputStream dos = new DataOutputStream(bos)) { + putString(dos, swContextCarrier.getOperationName()); + CarrierItem next = swContextCarrier.getCarrier().items(); + while (next.hasNext()) { + next = next.next(); + if (next.getHeadKey() != null && next.getHeadValue() != null) { + putString(dos, next.getHeadKey()); + putString(dos, next.getHeadValue()); + } + } + bos.flush(); + return Bufs.ownedBuf(bos.toByteArray()); + } catch (Exception e) { + LOGGER.error("encode swContextCarrier exception.", e); + } + return Bufs.EMPTY; + } + + /** + * Decodes byte array to SWContextCarrier. + * + * First we read 4 bytes from byte array, composing them into an int value n, and read the following n bytes, + * decodes them to a string by {@link #decodeStringFromBytes(byte[])}, and so on. + * + * The first string is operation name, other strings are a list pair of key and value, can be translated to + * {@link ContextCarrier} + * + * For convenient, we use {@link ByteBuffer} to wrap byte array. + * + * @param buf the byte array to decode + * @return + */ + static SWContextCarrier decode(Buf buf) { + ContextCarrier contextCarrier = new ContextCarrier(); + SWContextCarrier swContextCarrier = new SWContextCarrier(); + swContextCarrier.setContextCarrier(contextCarrier); + + ByteBuffer byteBuffer = ByteBuffer.wrap(Bufs.ownedByteArray(buf)); + String operationName = getNextString(byteBuffer); + if (operationName != null) { + swContextCarrier.setOperationName(operationName); + } + + Map data = readToMap(byteBuffer); + CarrierItem next = contextCarrier.items(); + while (next.hasNext()) { + next = next.next(); + next.setHeadValue(data.get(next.getHeadKey())); + } + return swContextCarrier; + } + + private static void putString(DataOutputStream dos, String value) throws IOException { + byte[] bytes = encodeStringToBytes(value); + dos.writeInt(bytes.length); + dos.write(bytes); + } + + private static String getNextString(ByteBuffer byteBuffer) { + if (byteBuffer.hasRemaining()) { + byte[] bytes = new byte[byteBuffer.getInt()]; + byteBuffer.get(bytes); + return decodeStringFromBytes(bytes); + } + return null; + } + + private static Map readToMap(ByteBuffer byteBuffer) { + Map data = new HashMap<>(); + String key = null; + while ((key = getNextString(byteBuffer)) != null) { + data.put(key, getNextString(byteBuffer)); + } + return data; + } + + private static byte[] encodeStringToBytes(String value) { + return value.getBytes(StandardCharsets.UTF_8); + } + + private static String decodeStringFromBytes(byte[] bytes) { + return new String(bytes, StandardCharsets.UTF_8); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/Constants.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/Constants.java new file mode 100644 index 000000000..791a62489 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/Constants.java @@ -0,0 +1,24 @@ +/* + * 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.finagle; + +public class Constants { + + public static final String PENDING_OP_NAME = "pending"; +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ContextCarrierHelper.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ContextCarrierHelper.java new file mode 100644 index 000000000..1f094513a --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ContextCarrierHelper.java @@ -0,0 +1,56 @@ +/* + * 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.finagle; + +import org.apache.skywalking.apm.agent.core.context.ContextCarrier; +import org.apache.skywalking.apm.agent.core.context.trace.ExitSpan; + +import static org.apache.skywalking.apm.plugin.finagle.Constants.PENDING_OP_NAME; +import static org.apache.skywalking.apm.plugin.finagle.FinagleCtxs.getPeerHost; +import static org.apache.skywalking.apm.plugin.finagle.FinagleCtxs.getSWContextCarrier; + +class ContextCarrierHelper { + + /** + * In {@link ClientTracingFilterInterceptor}, we create {@link ExitSpan} without op name and peer information, and + * we use {@link AnnotationInterceptor.Rpc} and {@link ClientDestTracingFilterInterceptor} to put op name and + * peer information into LocalContext, but the order of these two interceptors are uncertain, so after each + * interceptor, we check if the op name and peer information are exists in LocalContext, if it exists, we set it + * to span and inject to contextCarrier. + */ + static void tryInjectContext(ExitSpan span) { + String operationName = span.getOperationName(); + if (PENDING_OP_NAME.equals(operationName)) { + return; + } + String peer = getPeerHost(); + if (peer == null) { + return; + } + span.setPeer(peer); + + ContextCarrier contextCarrier = new ContextCarrier(); + span.inject(contextCarrier); + + SWContextCarrier swContextCarrier = getSWContextCarrier(); + // we can ensure swContextCarrier is not null here + swContextCarrier.setContextCarrier(contextCarrier); + swContextCarrier.setOperationName(operationName); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ContextHolder.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ContextHolder.java new file mode 100644 index 000000000..bafaf0830 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ContextHolder.java @@ -0,0 +1,90 @@ +/* + * 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.finagle; + +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; + +/** + *

Finagle context usage

+ * + * The only way we can transfer data through finagle context as below: + *
{@code
+ *    Context context =  Contexts.local(); // Contexts.broadcast()
+ *    context.let(key, value, (Function0) fn);
+ * }
+ * + * which means bind value to key in the scope of fn, even if fn may be executed in any threads. But we can't use this + * method directly, for example, when we intercept ClientTracingFilter, what we need is add SWContextCarrier + * into the MarshalledContext in beforeMethod, and remove it in afterMethod, as below: + *
{@code
+ * abstract ClientTracingFilterInterceptor extends InstanceMethodsAroundInterceptor {
+ *     void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes
+ *             MethodInterceptResult result) throws Throwable {
+ *         Context context =  Contexts.broadcast();
+ *         SWContextCarrier swContextCarrier = new SWContextCarrier();
+ *         context.let(key, swContextCarrier);
+ *     }
+ *
+ *     Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes
+ *             Object ret) throws Throwable {
+ *         Context context =  Contexts.broadcast();
+ *         context.remove(key);
+ *     }
+ * }}
+ * + * So we use ContextHolder to achieve this, the {@link #let(Object, Object)} and {@link #remove(Object)} methos split + * the function of
let(key, value, (Function0) fn)
into two methods. + * + *

ContextHolder usage

+ * + * 1. For each let operation, there MUST be a corresponding remove operaton. + * 2. The order of remove operation MUST be the opposite of the order of let operation, that is, first let last remove + * 3. This class can ONLY be used in subclasses of {@link InstanceMethodsAroundInterceptor}, and the let method can + * ONLY called in {@link InstanceMethodsAroundInterceptor#beforeMethod}, the remove method can ONLY be called in + * {@link InstanceMethodsAroundInterceptor#afterMethod}. + * + *
{@code
+ * class Interceptor implements InstanceMethodsAroundInterceptor {
+ *
+ *     @Override
+ *     public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes,
+ *                              MethodInterceptResult result) throws Throwable {
+ *         ContextHolder contextHolder = ...;
+ *         contextHolder.let(key1, value1);
+ *         contextHolder.let(key2, value2);
+ *         contextHolder.let(key3, value3);
+ *     }
+ *
+ *     @Override
+ *     public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes,
+ *                              Object ret) throws Throwable {
+ *         ContextHolder contextHolder = ...;
+ *         contextHolder.remove(key3);
+ *         contextHolder.remove(key2);
+ *         contextHolder.remove(key1);
+ *         return afterMethodImpl(objInst, method, allArguments, argumentsTypes, ret);
+ *     }
+ * }}
+ */ +abstract class ContextHolder { + + abstract void let(Object key, Object value); + + abstract void remove(Object key); +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ContextHolderFactory.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ContextHolderFactory.java new file mode 100644 index 000000000..02b73df79 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ContextHolderFactory.java @@ -0,0 +1,238 @@ +/* + * 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.finagle; + +import com.twitter.finagle.context.Context; +import com.twitter.finagle.context.Contexts; +import com.twitter.finagle.context.LocalContext; +import com.twitter.finagle.context.MarshalledContext; +import com.twitter.io.Buf; +import com.twitter.util.Local; +import scala.Some; +import scala.Some$; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.LinkedList; + +/** + * The implementation of {@link ContextHolder} depend on implementation detail of LocalContext and MarshalledContext of + * finagle. To implement {@link ContextHolder}, we need know the actual data struct that the underlying Context use, + * and use that data struct to impelment {@link ContextHolder#let(Object, Object)} and + * {@link ContextHolder#remove(Object)}. + */ +class ContextHolderFactory { + + /* + * Below version 6.41.0(inclusive), this class is used to implement Context, above version 6.41.0, ImmutableMap + * is used. we check if this class is on the classpath, then we can know the actual data struct the underlying + * finagle used. + */ + private static final String CONTEXT_ENV_CLASS = "com.twitter.finagle.context.Context$Env"; + + private static ContextHolder MARSHALLED_CONTEXT_HOLDER; + private static ContextHolder LOCAL_CONTEXT_HOLDER; + + static { + try { + Class.forName(CONTEXT_ENV_CLASS); + /* + * Compatible with versions 6.41.0 and below + */ + MARSHALLED_CONTEXT_HOLDER = new EnvContextHolder(Contexts.broadcast()); + LOCAL_CONTEXT_HOLDER = new EnvContextHolder(Contexts.local()); + } catch (ClassNotFoundException e) { + /* + * Compatible with versions above 6.41.0 + */ + LOCAL_CONTEXT_HOLDER = new MapLocalContextHolder(Contexts.local()); + MARSHALLED_CONTEXT_HOLDER = new MapMarshalledContextHolder(Contexts.broadcast()); + } + } + + static ContextHolder getMarshalledContextHolder() { + return MARSHALLED_CONTEXT_HOLDER; + } + + static ContextHolder getLocalContextHolder() { + return LOCAL_CONTEXT_HOLDER; + } + + static abstract class AbstractContextHolder extends ContextHolder { + + final Local local; + final S initContext; + /** + * We push each let operation to the stack, when there is a remove operation, the key must be the same with + * key of let operation on the stack head. + */ + private final ThreadLocal>> snapshots; + + static class Snapshot { + /** + * key from let operation + */ + private Object key; + /** + * value of {@link #local} before current let operation + */ + private S saved; + + private Snapshot(Object key, S saved) { + this.key = key; + this.saved = saved; + } + } + + AbstractContextHolder(Context context, String localFieldName) { + this.local = getLocal(context, localFieldName); + this.initContext = getInitContext(context); + this.snapshots = new ThreadLocal>>() { + @Override + protected LinkedList> initialValue() { + return new LinkedList<>(); + } + }; + } + + @Override + void let(Object key, Object value) { + S currentContext = getCurrentContext(); + snapshots.get().push(new Snapshot<>(key, currentContext)); + local.update(getUpdatedContext(currentContext, key, value)); + } + + @Override + void remove(Object key) { + Snapshot snapshot = snapshots.get().peek(); + if (snapshot == null || !snapshot.key.equals(key)) { + throw new IllegalStateException(String.format("can't remove %s. the order of remove must be opposite with" + + " let.", key)); + } + local.update(snapshot.saved); + snapshots.get().pop(); + } + + private S getCurrentContext() { + if (local.apply().isDefined()) { + return local.apply().get(); + } + return initContext; + } + + abstract protected S getUpdatedContext(S currentContext, Object key, Object value); + + @SuppressWarnings("unchecked") + private Local getLocal(Context context, String localFieldName) { + try { + Field localField = context.getClass().getDeclaredField(localFieldName); + localField.setAccessible(true); + return (Local) localField.get(context); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @SuppressWarnings("unchecked") + private S getInitContext(Context context) { + try { + Method method = context.getClass().getDeclaredMethod("env"); + method.setAccessible(true); + return (S) method.invoke(context); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + + static class EnvContextHolder extends AbstractContextHolder { + + private static final String LOCAL_FIELD_NAME = "com$twitter$finagle$context$Context$$local"; + + EnvContextHolder(Context context) { + super(context, LOCAL_FIELD_NAME); + } + + @Override + protected Context.Env getUpdatedContext(Context.Env currentContext, Object key, Object value) { + return currentContext.bound(key, value); + } + } + + static class MapLocalContextHolder extends ContextHolderFactory.AbstractContextHolder> { + + private static final String LOCAL_FIELD_NAME = "local"; + + MapLocalContextHolder(LocalContext context) { + super(context, LOCAL_FIELD_NAME); + } + + @Override + protected scala.collection.immutable.Map getUpdatedContext(scala.collection.immutable.Map currentContext, Object key, Object value) { + checkKeyType(key); + return currentContext.updated((LocalContext.Key) key, value); + } + + private void checkKeyType(Object key) { + if (!(key instanceof LocalContext.Key)) { + throw new IllegalArgumentException("key should be subclass of LocalContext.Key"); + } + } + } + + static class MapMarshalledContextHolder extends ContextHolderFactory.AbstractContextHolder> { + + private static final String LOCAL_FIELD_NAME = "local"; + + private static final Constructor REAL_CONSTRUCTOR; + + static { + try { + Class clz = Class.forName(MarshalledContext.class.getName() + "$Real"); + REAL_CONSTRUCTOR = clz.getDeclaredConstructor(MarshalledContext.class, + MarshalledContext.Key.class, Some.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + MapMarshalledContextHolder(MarshalledContext context) { + super(context, LOCAL_FIELD_NAME); + } + + @Override + protected scala.collection.immutable.Map getUpdatedContext(scala.collection.immutable.Map currentContext, Object key, Object value) { + checkKeyType(key); + try { + MarshalledContext.Key marshalledContextKey = (MarshalledContext.Key) key; + Object real = REAL_CONSTRUCTOR.newInstance(Contexts.broadcast(), marshalledContextKey, Some$.MODULE$.apply(value)); + return currentContext.updated(marshalledContextKey.marshalId(), real); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private void checkKeyType(Object key) { + if (!(key instanceof MarshalledContext.Key)) { + throw new IllegalArgumentException("key should be subclass of MarshalledContext.Key"); + } + } + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/FinagleCtxs.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/FinagleCtxs.java new file mode 100644 index 000000000..edb5f933c --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/FinagleCtxs.java @@ -0,0 +1,70 @@ +/* + * 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.finagle; + +import com.twitter.finagle.context.Contexts; +import com.twitter.finagle.context.LocalContext; +import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; + +import javax.annotation.Nullable; +import java.lang.reflect.Constructor; + +class FinagleCtxs { + + static LocalContext.Key SW_SPAN = null; + + static LocalContext.Key PEER_HOST = null; + + static { + try { + Constructor constructor = LocalContext.Key.class.getConstructor(LocalContext.class); + SW_SPAN = (LocalContext.Key) constructor.newInstance(Contexts.local()); + PEER_HOST = (LocalContext.Key) constructor.newInstance(Contexts.local()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Nullable + static AbstractSpan getSpan() { + if (Contexts.local().contains(SW_SPAN)) { + AbstractSpan abstractSpan = Contexts.local().apply(SW_SPAN); + return abstractSpan; + } + return null; + } + + @Nullable + static SWContextCarrier getSWContextCarrier() { + if (Contexts.broadcast().contains(SWContextCarrier$.MODULE$)) { + SWContextCarrier swContextCarrier = Contexts.broadcast().apply(SWContextCarrier$.MODULE$); + return swContextCarrier; + } + return null; + } + + @Nullable + static String getPeerHost() { + if (Contexts.local().contains(PEER_HOST)) { + String peerHost = Contexts.local().apply(PEER_HOST); + return peerHost; + } + return null; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ServerTracingFilterInterceptor.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ServerTracingFilterInterceptor.java new file mode 100644 index 000000000..6cd22be31 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/ServerTracingFilterInterceptor.java @@ -0,0 +1,88 @@ +/* + * 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.finagle; + +import com.twitter.finagle.context.Contexts; +import com.twitter.util.Future; +import com.twitter.util.FutureEventListener; +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.MethodInterceptResult; + +import java.lang.reflect.Method; + +import static org.apache.skywalking.apm.network.trace.component.ComponentsDefine.FINAGLE; +import static org.apache.skywalking.apm.plugin.finagle.ContextHolderFactory.getLocalContextHolder; +import static org.apache.skywalking.apm.plugin.finagle.FinagleCtxs.getSpan; + +public class ServerTracingFilterInterceptor extends AbstractInterceptor { + + @Override + protected void onConstructImpl(EnhancedInstance objInst, Object[] allArguments) { + + } + + @Override + public void beforeMethodImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class[] classes, + MethodInterceptResult methodInterceptResult) throws Throwable { + AbstractSpan span = null; + if (Contexts.broadcast().contains(SWContextCarrier$.MODULE$)) { + SWContextCarrier swContextCarrier = Contexts.broadcast().apply(SWContextCarrier$.MODULE$); + span = ContextManager.createEntrySpan(swContextCarrier.getOperationName(), swContextCarrier.getCarrier()); + } else { + span = ContextManager.createEntrySpan("unknown", new ContextCarrier()); + } + + span.setComponent(FINAGLE); + SpanLayer.asRPCFramework(span); + + getLocalContextHolder().let(FinagleCtxs.SW_SPAN, span); + } + + @Override + public Object afterMethodImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class[] classes, Object ret) throws Throwable { + final AbstractSpan finagleSpan = getSpan(); + getLocalContextHolder().remove(FinagleCtxs.SW_SPAN); + finagleSpan.prepareForAsync(); + ContextManager.stopSpan(finagleSpan); + ((Future) ret).addEventListener(new FutureEventListener() { + @Override + public void onSuccess(Object value) { + finagleSpan.asyncFinish(); + } + + @Override + public void onFailure(Throwable cause) { + finagleSpan.errorOccurred(); + finagleSpan.log(cause); + finagleSpan.asyncFinish(); + } + }); + return ret; + } + + @Override + public void handleMethodExceptionImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects, + Class[] classes, Throwable t) { + ContextManager.activeSpan().errorOccurred().log(t); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/AbstractInstrumentation.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/AbstractInstrumentation.java new file mode 100644 index 000000000..39c784c9e --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/AbstractInstrumentation.java @@ -0,0 +1,34 @@ +/* + * 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.finagle.define; + +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; + +public abstract class AbstractInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + + /** + * this class exists in version 6.25.0 and above + */ + private static final String ADDRMETADATAEXTRACTION_CLASS = "com.twitter.finagle.client.AddrMetadataExtraction"; + + @Override + protected String[] witnessClasses() { + return new String[]{ADDRMETADATAEXTRACTION_CLASS}; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/AnnotationInstrumentation.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/AnnotationInstrumentation.java new file mode 100644 index 000000000..bcf3167a7 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/AnnotationInstrumentation.java @@ -0,0 +1,81 @@ +/* + * 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.finagle.define; + +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.match.ClassMatch; +import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch; + +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +public class AnnotationInstrumentation { + + private static final String ANNOTATION_CLASS = "com.twitter.finagle.tracing.Annotation$"; + private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.finagle.AnnotationInterceptor$"; + + abstract static class Abstract extends AbstractInstrumentation { + + @Override + protected ClassMatch enhanceClass() { + return NameMatch.byName(ANNOTATION_CLASS + getAnnoationName()); + } + + @Override + public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[]{ + new ConstructorInterceptPoint() { + @Override + public ElementMatcher getConstructorMatcher() { + return getConstructor(); + } + + @Override + public String getConstructorInterceptor() { + return INTERCEPT_CLASS + getAnnoationName(); + } + } + }; + } + + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[0]; + } + + protected abstract String getAnnoationName(); + + protected abstract ElementMatcher getConstructor(); + } + + public static class Rpc extends Abstract { + + @Override + protected String getAnnoationName() { + return "Rpc"; + } + + @Override + protected ElementMatcher getConstructor() { + return takesArgument(0, String.class); + } + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/ClientDestTracingFilterInstrumetation.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/ClientDestTracingFilterInstrumetation.java new file mode 100644 index 000000000..0c0dc6185 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/ClientDestTracingFilterInstrumetation.java @@ -0,0 +1,79 @@ +/* + * 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.finagle.define; + +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.match.ClassMatch; +import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch; + +import static net.bytebuddy.matcher.ElementMatchers.any; +import static net.bytebuddy.matcher.ElementMatchers.named; + +public class ClientDestTracingFilterInstrumetation extends AbstractInstrumentation { + + private static final String ENHANCE_CLASS = "com.twitter.finagle.tracing.ClientDestTracingFilter"; + private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.finagle.ClientDestTracingFilterInterceptor"; + + @Override + protected ClassMatch enhanceClass() { + return NameMatch.byName(ENHANCE_CLASS); + } + + @Override + public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[]{ + new ConstructorInterceptPoint() { + @Override + public ElementMatcher getConstructorMatcher() { + return any(); + } + + @Override + public String getConstructorInterceptor() { + return INTERCEPT_CLASS; + } + } + }; + } + + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[]{ + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return named("apply"); + } + + @Override + public String getMethodsInterceptor() { + return INTERCEPT_CLASS; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + } + }; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/ClientTracingFilterInstrumentation.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/ClientTracingFilterInstrumentation.java new file mode 100644 index 000000000..29a2e40eb --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/ClientTracingFilterInstrumentation.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.finagle.define; + +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.match.ClassMatch; +import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch; + +import static net.bytebuddy.matcher.ElementMatchers.named; + +public class ClientTracingFilterInstrumentation extends AbstractInstrumentation { + + private static final String ENHANCE_CLASS = "com.twitter.finagle.tracing.ClientTracingFilter$TracingFilter"; + private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.finagle.ClientTracingFilterInterceptor"; + + @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 getMethodsMatcher() { + return named("apply"); + } + + @Override + public String getMethodsInterceptor() { + return INTERCEPT_CLASS; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + } + }; + } +} + diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/ServerTracingFilterInstrumentation.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/ServerTracingFilterInstrumentation.java new file mode 100644 index 000000000..fe4a835ff --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/finagle/define/ServerTracingFilterInstrumentation.java @@ -0,0 +1,66 @@ +/* + * 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.finagle.define; + +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.match.ClassMatch; +import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch; + +import static net.bytebuddy.matcher.ElementMatchers.named; + +public class ServerTracingFilterInstrumentation extends AbstractInstrumentation { + + private static final String ENHANCE_CLASS = "com.twitter.finagle.tracing.ServerTracingFilter$TracingFilter"; + private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.finagle.ServerTracingFilterInterceptor"; + + @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 getMethodsMatcher() { + return named("apply"); + } + + @Override + public String getMethodsInterceptor() { + return INTERCEPT_CLASS; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + } + }; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/resources/skywalking-plugin.def new file mode 100644 index 000000000..33d15ebee --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/resources/skywalking-plugin.def @@ -0,0 +1,20 @@ +# 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. + +finagle=org.apache.skywalking.apm.plugin.finagle.define.AnnotationInstrumentation$Rpc +finagle=org.apache.skywalking.apm.plugin.finagle.define.ClientTracingFilterInstrumentation +finagle=org.apache.skywalking.apm.plugin.finagle.define.ClientDestTracingFilterInstrumetation +finagle=org.apache.skywalking.apm.plugin.finagle.define.ServerTracingFilterInstrumentation diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/scala/org/apache/skywalking/apm/plugin/finagle/SWContextCarrier.scala b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/scala/org/apache/skywalking/apm/plugin/finagle/SWContextCarrier.scala new file mode 100644 index 000000000..a444f96ca --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/main/scala/org/apache/skywalking/apm/plugin/finagle/SWContextCarrier.scala @@ -0,0 +1,57 @@ +/* + * 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.finagle + +import com.twitter.finagle.context.Contexts +import com.twitter.io.Buf +import com.twitter.util.{Return, Try} +import org.apache.skywalking.apm.agent.core.context.ContextCarrier + +class SWContextCarrier() { + private var operationName: String = "" + private var carrier: ContextCarrier = null; + + def setOperationName(op: String): Unit = { + operationName = op + } + + def setContextCarrier(carrier: ContextCarrier): Unit = this.carrier = carrier; + + def getOperationName: String = operationName + + def getCarrier(): ContextCarrier = carrier; +} + +object SWContextCarrier extends Contexts.broadcast.Key[SWContextCarrier]("org.apache.skywalking.apm.plugin.finagle.SWContextCarrier") { + + def of(carrier: ContextCarrier): SWContextCarrier = { + val sWContextCarrier = new SWContextCarrier() + sWContextCarrier.setContextCarrier(carrier) + sWContextCarrier + } + + override def marshal(context: SWContextCarrier): Buf = { + CodecUtils.encode(context) + } + + override def tryUnmarshal(buf: Buf): Try[SWContextCarrier] = { + val context = CodecUtils.decode(buf) + Return(context) + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/AbstractTracingFilterTest.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/AbstractTracingFilterTest.java new file mode 100644 index 000000000..4b9002f4a --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/AbstractTracingFilterTest.java @@ -0,0 +1,117 @@ +/* + * 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.finagle; + +import com.twitter.finagle.Service; +import com.twitter.util.Future; +import com.twitter.util.Promise; +import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan; +import org.apache.skywalking.apm.agent.core.context.trace.LogDataEntity; +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.util.TagValuePair; +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.hamcrest.CoreMatchers; +import org.junit.Before; +import org.junit.Rule; +import org.mockito.Mock; + +import java.util.List; + +import static org.apache.skywalking.apm.network.trace.component.ComponentsDefine.FINAGLE; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; + +public abstract class AbstractTracingFilterTest { + + @Rule + public AgentServiceRule agentServiceRule = new AgentServiceRule(); + + @Mock + protected MethodInterceptResult methodInterceptResult; + + protected EnhancedInstance enhancedInstance = new MockEnhancedInstance(); + + protected AnnotationInterceptor.Rpc rpcInterceptor = new AnnotationInterceptor.Rpc(); + + protected String rpc = "finagleRpc"; + + protected Object[] allArguments; + protected Class[] argumentTypes; + + protected Promise result; + + @Before + public void setup() throws Throwable { + result = new Promise(); + allArguments = new Object[]{new Object(), new Service() { + @Override + public Future apply(Object request) { + return result; + } + } }; + argumentTypes = new Class[]{Object.class, Service.class}; + prepareForTest(); + } + + protected abstract void prepareForTest() throws Throwable; + + protected abstract void assertSpan(AbstractTracingSpan span); + + protected void assertTraceSegments(List traceSegments) { + assertThat(traceSegments.size(), is(1)); + TraceSegment traceSegment = traceSegments.get(0); + List spans = SegmentHelper.getSpans(traceSegment); + assertThat(spans.size(), is(1)); + assertFinagleSpan(spans.get(0)); + } + + protected void assertTraceSegmentsWithError(List traceSegments) { + assertThat(traceSegments.size(), is(1)); + TraceSegment traceSegment = traceSegments.get(0); + List spans = SegmentHelper.getSpans(traceSegment); + assertThat(spans.size(), is(1)); + assertFinagleSpan(spans.get(0)); + + assertThat(SpanHelper.getLogs(spans.get(0)).size(), is(1)); + assertErrorLog(SpanHelper.getLogs(spans.get(0)).get(0)); + } + + private void assertFinagleSpan(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(FINAGLE.getId())); + assertThat(span.getOperationName(), is(rpc)); + + assertSpan(span); + } + + 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()); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/ClientTracingFilterInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/ClientTracingFilterInterceptorTest.java new file mode 100644 index 000000000..84dc1edff --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/ClientTracingFilterInterceptorTest.java @@ -0,0 +1,112 @@ +/* + * 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.finagle; + +import com.twitter.finagle.Address; +import com.twitter.finagle.Addresses$; +import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan; +import org.apache.skywalking.apm.agent.core.context.trace.ExitTypeSpan; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +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.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.modules.junit4.PowerMockRunnerDelegate; + +import java.net.Inet4Address; +import java.net.InetSocketAddress; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +@RunWith(PowerMockRunner.class) +@PowerMockRunnerDelegate(TracingSegmentRunner.class) +public class ClientTracingFilterInterceptorTest extends AbstractTracingFilterTest { + + @SegmentStoragePoint + protected SegmentStorage segmentStorage; + + private ClientTracingFilterInterceptor clientTracingFilterInterceptor; + private ClientDestTracingFilterInterceptor clientDestTracingFilterInterceptor = + new ClientDestTracingFilterInterceptor(); + private EnhancedInstance enhancedClientDestTracingFilter = new MockEnhancedInstance(); + private InetSocketAddress serverSocketAddress; + private Address serverAddr; + + @Override + protected void prepareForTest() throws Throwable { + clientTracingFilterInterceptor = new ClientTracingFilterInterceptor(); + serverSocketAddress = new InetSocketAddress(Inet4Address.getLocalHost(), 9999); + serverAddr = Addresses$.MODULE$.newInetAddress(serverSocketAddress); + } + + @Override + protected void assertSpan(AbstractTracingSpan span) { + assertTrue(span.isExit()); + assertThat(((ExitTypeSpan) span).getPeer(), is(serverSocketAddress.getAddress().getHostAddress() + ":" + serverSocketAddress.getPort())); + } + + @Test + public void testClient() throws Throwable { + clientTracingFilterInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult); + result.setValue(new Object()); + rpcInterceptor.onConstruct(null, new Object[]{rpc}); + clientDestTracingFilterInterceptor.onConstruct(enhancedClientDestTracingFilter, new Object[]{serverAddr}); + + clientDestTracingFilterInterceptor.beforeMethod(enhancedClientDestTracingFilter, null, allArguments, argumentTypes, methodInterceptResult); + clientDestTracingFilterInterceptor.afterMethod(enhancedClientDestTracingFilter, null, allArguments, argumentTypes, result); + + clientTracingFilterInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result); + + assertTraceSegments(segmentStorage.getTraceSegments()); + } + + @Test + public void testClientWithException() throws Throwable { + clientTracingFilterInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult); + result.setValue(new Object()); + rpcInterceptor.onConstruct(null, new Object[]{rpc}); + clientDestTracingFilterInterceptor.onConstruct(enhancedClientDestTracingFilter, new Object[]{serverAddr}); + clientDestTracingFilterInterceptor.beforeMethod(enhancedClientDestTracingFilter, null, allArguments, argumentTypes, methodInterceptResult); + clientDestTracingFilterInterceptor.afterMethod(enhancedClientDestTracingFilter, null, allArguments, argumentTypes, result); + + clientTracingFilterInterceptor.handleMethodException(enhancedInstance, null, allArguments, argumentTypes, new RuntimeException()); + clientTracingFilterInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result); + + assertTraceSegmentsWithError(segmentStorage.getTraceSegments()); + } + + @Test + public void testClientWithResultHasException() throws Throwable { + + clientTracingFilterInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult); + result.setException(new RuntimeException()); + rpcInterceptor.onConstruct(null, new Object[]{rpc}); + clientDestTracingFilterInterceptor.onConstruct(enhancedClientDestTracingFilter, new Object[]{serverAddr}); + clientDestTracingFilterInterceptor.beforeMethod(enhancedClientDestTracingFilter, null, allArguments, argumentTypes, methodInterceptResult); + clientDestTracingFilterInterceptor.afterMethod(enhancedClientDestTracingFilter, null, allArguments, argumentTypes, result); + + clientTracingFilterInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result); + + assertTraceSegments(segmentStorage.getTraceSegments()); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/CodecUtilsTest.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/CodecUtilsTest.java new file mode 100644 index 000000000..d7763d6ec --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/CodecUtilsTest.java @@ -0,0 +1,79 @@ +/* + * 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.finagle; + +import com.twitter.io.Bufs; +import org.apache.skywalking.apm.agent.core.context.CarrierItem; +import org.apache.skywalking.apm.agent.core.context.ContextCarrier; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +public class CodecUtilsTest { + + @Test + public void encode() { + SWContextCarrier swContextCarrier = makeSWContextCarrier(); + assertSwContextCarrier(swContextCarrier, CodecUtils.decode(CodecUtils.encode(swContextCarrier))); + + swContextCarrier = makeSWContextCarrier(); + assertSwContextCarrier(swContextCarrier, CodecUtils.decode(CodecUtils.encode(swContextCarrier))); + + swContextCarrier = makeSWContextCarrier(); + assertSwContextCarrier(swContextCarrier, CodecUtils.decode(CodecUtils.encode(swContextCarrier))); + + ContextCarrier contextCarrier = new ContextCarrier(); + swContextCarrier = new SWContextCarrier(); + swContextCarrier.setContextCarrier(contextCarrier); + assertSwContextCarrier(swContextCarrier, CodecUtils.decode(Bufs.EMPTY)); + } + + private SWContextCarrier makeSWContextCarrier() { + ContextCarrier contextCarrier = new ContextCarrier(); + CarrierItem next = contextCarrier.items(); + while (next.hasNext()) { + next = next.next(); + next.setHeadValue(UUID.randomUUID().toString()); + } + SWContextCarrier swContextCarrier = new SWContextCarrier(); + swContextCarrier.setContextCarrier(contextCarrier); + swContextCarrier.setOperationName(UUID.randomUUID().toString()); + return swContextCarrier; + } + + private void assertSwContextCarrier(SWContextCarrier expected, SWContextCarrier actual) { + assertThat(expected.getOperationName(), is(actual.getOperationName())); + Map data = new HashMap<>(); + CarrierItem next = expected.getCarrier().items(); + while (next.hasNext()) { + next = next.next(); + data.put(next.getHeadKey(), next.getHeadValue()); + } + next = actual.getCarrier().items(); + while (next.hasNext()) { + next = next.next(); + assertThat(next.getHeadValue(), is(data.get(next.getHeadKey()))); + } + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/ContextHolderFactoryTest.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/ContextHolderFactoryTest.java new file mode 100644 index 000000000..0b63bce2d --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/ContextHolderFactoryTest.java @@ -0,0 +1,145 @@ +/* + * 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.finagle; + +import com.twitter.finagle.context.Contexts; +import com.twitter.finagle.context.LocalContext; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.lang.reflect.Constructor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.apache.skywalking.apm.plugin.finagle.ContextHolderFactory.getLocalContextHolder; +import static org.apache.skywalking.apm.plugin.finagle.ContextHolderFactory.getMarshalledContextHolder; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +public class ContextHolderFactoryTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private static LocalContext.Key KEY1; + private static LocalContext.Key KEY2; + private static LocalContext.Key KEY3; + + @BeforeClass + public static void setup() throws Exception { + Constructor constructor = LocalContext.Key.class.getConstructor(LocalContext.class); + KEY1 = (LocalContext.Key) constructor.newInstance(Contexts.local()); + KEY2 = (LocalContext.Key) constructor.newInstance(Contexts.local()); + KEY3 = (LocalContext.Key) constructor.newInstance(Contexts.local()); + } + + @Test + public void testLCRemoveNonExistKey() { + testRemoveNonExistKey(getLocalContextHolder()); + } + + @Test + public void testLCRemoveWrongOrder() { + ContextHolder localContextHolder = getLocalContextHolder(); + try { + localContextHolder.let(KEY1, "key1"); + localContextHolder.let(KEY2, "key2"); + testLCRemoveWrongOrder(localContextHolder, KEY1); + } finally { + localContextHolder.remove(KEY2); + localContextHolder.remove(KEY1); + } + } + + @Test + public void testLCLetAndRemove() { + ContextHolder localContextHolder = getLocalContextHolder(); + localContextHolder.let(KEY1, Thread.currentThread().getName() + KEY1); + localContextHolder.let(KEY2, Thread.currentThread().getName() + KEY2); + localContextHolder.let(KEY3, Thread.currentThread().getName() + KEY3); + localContextHolder.let(KEY2, Thread.currentThread().getName() + KEY2 + KEY2); + + assertEquals(Contexts.local().apply(KEY1), Thread.currentThread().getName() + KEY1); + assertEquals(Contexts.local().apply(KEY2), Thread.currentThread().getName() + KEY2 + KEY2); + assertEquals(Contexts.local().apply(KEY3), Thread.currentThread().getName() + KEY3); + + localContextHolder.remove(KEY2); + assertEquals(Contexts.local().apply(KEY1), Thread.currentThread().getName() + KEY1); + assertEquals(Contexts.local().apply(KEY2), Thread.currentThread().getName() + KEY2); + assertEquals(Contexts.local().apply(KEY3), Thread.currentThread().getName() + KEY3); + + localContextHolder.remove(KEY3); + assertEquals(Contexts.local().apply(KEY1), Thread.currentThread().getName() + KEY1); + assertEquals(Contexts.local().apply(KEY2), Thread.currentThread().getName() + KEY2); + assertFalse(Contexts.local().get(KEY3).isDefined()); + + localContextHolder.remove(KEY2); + assertEquals(Contexts.local().apply(KEY1), Thread.currentThread().getName() + KEY1); + assertFalse(Contexts.local().get(KEY2).isDefined()); + assertFalse(Contexts.local().get(KEY3).isDefined()); + + localContextHolder.remove(KEY1); + assertFalse(Contexts.local().get(KEY1).isDefined()); + assertFalse(Contexts.local().get(KEY2).isDefined()); + assertFalse(Contexts.local().get(KEY3).isDefined()); + } + + @Test + public void testLCLetAndRemoveMultiThread() throws InterruptedException { + ExecutorService exec = Executors.newFixedThreadPool(5); + final AtomicInteger exceptions = new AtomicInteger(0); + for (int i = 0; i < 30; i++) { + exec.submit(new Runnable() { + @Override + public void run() { + try { + testLCLetAndRemove(); + } catch (Exception e) { + exceptions.incrementAndGet(); + } + } + }); + } + exec.shutdown(); + exec.awaitTermination(3, TimeUnit.MINUTES); + assertEquals(exceptions.get(), 0); + } + + @Test + public void testMCRemoveNonExistKey() { + testRemoveNonExistKey(getMarshalledContextHolder()); + } + + private void testRemoveNonExistKey(ContextHolder contextHolder) { + thrown.expect(IllegalStateException.class); + thrown.expectMessage("can't remove"); + contextHolder.remove(new Object()); + } + + private void testLCRemoveWrongOrder(ContextHolder contextHolder, Object key) { + thrown.expect(IllegalStateException.class); + thrown.expectMessage("can't remove"); + thrown.expectMessage(key.toString()); + contextHolder.remove(key); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/MockEnhancedInstance.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/MockEnhancedInstance.java new file mode 100644 index 000000000..f47fc5fd6 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/MockEnhancedInstance.java @@ -0,0 +1,36 @@ +/* + * 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.finagle; + +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; + +public class MockEnhancedInstance implements EnhancedInstance { + + private Object object; + + @Override + public Object getSkyWalkingDynamicField() { + return object; + } + + @Override + public void setSkyWalkingDynamicField(Object value) { + this.object = value; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/ServerTracingFilterInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/ServerTracingFilterInterceptorTest.java new file mode 100644 index 000000000..a51305b1d --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/finagle-6.25.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/finagle/ServerTracingFilterInterceptorTest.java @@ -0,0 +1,144 @@ +/* + * 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.finagle; + +import com.twitter.finagle.context.Contexts; +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.SW6CarrierItem; +import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan; +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.test.helper.SegmentRefHelper; +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.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.modules.junit4.PowerMockRunnerDelegate; +import scala.runtime.AbstractFunction0; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +@RunWith(PowerMockRunner.class) +@PowerMockRunnerDelegate(TracingSegmentRunner.class) +public class ServerTracingFilterInterceptorTest extends AbstractTracingFilterTest { + + @SegmentStoragePoint + protected SegmentStorage segmentStorage; + + private ServerTracingFilterInterceptor serverTracingFilterInterceptor; + + @Override + protected void prepareForTest() { + serverTracingFilterInterceptor = new ServerTracingFilterInterceptor(); + } + + @Override + protected void assertSpan(AbstractTracingSpan span) { + assertTrue(span.isEntry()); + } + + @Test + public void testServer() { + runWithContext(new TestFunction() { + @Override + public void apply() throws Throwable { + rpcInterceptor.onConstruct(null, new Object[]{rpc}); + serverTracingFilterInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult); + result.setValue(new Object()); + serverTracingFilterInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result); + assertServer(); + assertTraceSegments(segmentStorage.getTraceSegments()); + } + }); + } + + @Test + public void testServerWithException() { + runWithContext(new TestFunction() { + @Override + public void apply() throws Throwable { + rpcInterceptor.onConstruct(null, new Object[]{rpc}); + serverTracingFilterInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult); + result.setValue(new Object()); + serverTracingFilterInterceptor.handleMethodException(enhancedInstance, null, allArguments, argumentTypes, new RuntimeException()); + serverTracingFilterInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result); + assertServer(); + assertTraceSegmentsWithError(segmentStorage.getTraceSegments()); + } + }); + } + + @Test + public void testServerWithResultHasException() { + runWithContext(new TestFunction() { + @Override + public void apply() throws Throwable { + rpcInterceptor.onConstruct(null, new Object[]{rpc}); + serverTracingFilterInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult); + result.setException(new RuntimeException()); + serverTracingFilterInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result); + assertServer(); + assertTraceSegmentsWithError(segmentStorage.getTraceSegments()); + } + }); + } + + private void runWithContext(final TestFunction function) { + ContextCarrier contextCarrier = new ContextCarrier(); + CarrierItem next = contextCarrier.items(); + while (next.hasNext()) { + next = next.next(); + if (next.getHeadKey().equals(SW6CarrierItem.HEADER_NAME)) { + next.setHeadValue("1-MC4wLjA=-MS4zMjMuNDQzMw==-3-1-1-IzE5Mi4xNjguMS44IDoxODAwMg==-Iy9wb3J0Y" + + "Wwv-Iy90ZXN0RW50cnlTcGFu"); + } + } + SWContextCarrier swContextCarrier = new SWContextCarrier(); + swContextCarrier.setContextCarrier(contextCarrier); + swContextCarrier.setOperationName(rpc); + Contexts.broadcast().let(SWContextCarrier$.MODULE$, swContextCarrier, new AbstractFunction0() { + @Override + public Void apply() { + try { + function.apply(); + } catch (Throwable throwable) { + throw new RuntimeException(throwable); + } + return null; + } + }); + } + + interface TestFunction { + void apply() throws Throwable; + } + + private void assertServer() { + TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); + TraceSegmentRef actual = traceSegment.getRefs().get(0); + assertThat(SegmentRefHelper.getSpanId(actual), is(3)); + assertThat(SegmentRefHelper.getEntryServiceInstanceId(actual), is(1)); + assertThat(SegmentRefHelper.getTraceSegmentId(actual).toString(), is("1.323.4433")); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml index 9b1a53412..9bf5ef848 100644 --- a/apm-sniffer/apm-sdk-plugin/pom.xml +++ b/apm-sniffer/apm-sdk-plugin/pom.xml @@ -88,6 +88,7 @@ play-2.x-plugin lettuce-5.x-plugin avro-plugin + finagle-6.25.x-plugin pom diff --git a/docs/en/setup/service-agent/java-agent/Supported-list.md b/docs/en/setup/service-agent/java-agent/Supported-list.md index 55e93602f..5647c327b 100644 --- a/docs/en/setup/service-agent/java-agent/Supported-list.md +++ b/docs/en/setup/service-agent/java-agent/Supported-list.md @@ -42,6 +42,7 @@ * [SOFARPC](https://github.com/alipay/sofa-rpc) 5.4.0 * [Armeria](https://github.com/line/armeria) 0.63.0 -> 0.98.0 * [Apache Avro](http://avro.apache.org) 1.7.0 - 1.8.x + * [Finagle](https://github.com/twitter/finagle) 6.25.0 -> 20.1.0 * MQ * [RocketMQ](https://github.com/apache/rocketmq) 4.x * [Kafka](http://kafka.apache.org) 0.11.0.0 -> 1.0 diff --git a/oap-server/server-bootstrap/src/main/resources/component-libraries.yml b/oap-server/server-bootstrap/src/main/resources/component-libraries.yml index 03c452018..4cd93d983 100755 --- a/oap-server/server-bootstrap/src/main/resources/component-libraries.yml +++ b/oap-server/server-bootstrap/src/main/resources/component-libraries.yml @@ -281,6 +281,9 @@ AvroClient: Undertow: id: 84 languages: Java +Finagle: + id: 85 + languages: Java,Scala # .NET/.NET Core components # [3000, 4000) for C#/.NET only diff --git a/oap-server/server-core/src/test/resources/component-libraries.yml b/oap-server/server-core/src/test/resources/component-libraries.yml index 05e81cf16..643b0b2b7 100755 --- a/oap-server/server-core/src/test/resources/component-libraries.yml +++ b/oap-server/server-core/src/test/resources/component-libraries.yml @@ -248,6 +248,9 @@ AvroServer: AvroClient: id: 83 languages: Java +Finagle: + id: 85 + languages: Java,Scala # .NET/.NET Core components diff --git a/test/plugin/scenarios/finagle-17.10.x-scenario/bin/startup.sh b/test/plugin/scenarios/finagle-17.10.x-scenario/bin/startup.sh new file mode 100644 index 000000000..8a9c9300e --- /dev/null +++ b/test/plugin/scenarios/finagle-17.10.x-scenario/bin/startup.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# +# 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. + +home="$(cd "$(dirname $0)"; pwd)" + +java -jar ${agent_opts} ${home}/../libs/finagle-17.10.x-scenario.jar & \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-17.10.x-scenario/config/expectedData.yaml b/test/plugin/scenarios/finagle-17.10.x-scenario/config/expectedData.yaml new file mode 100644 index 000000000..13e28ea81 --- /dev/null +++ b/test/plugin/scenarios/finagle-17.10.x-scenario/config/expectedData.yaml @@ -0,0 +1,78 @@ +# 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. +registryItems: + services: + - {finagle-17.10.x-scenario: 2} + instances: + - {finagle-17.10.x-scenario: 1} + operationNames: + - finagle-17.10.x-scenario: [hello, /finagle-17.10.x-scenario/case/finagle] + heartbeat: [] +segmentItems: + - serviceName: finagle-17.10.x-scenario + segmentSize: gt 2 + segments: + - segmentId: not null + spans: + - operationName: hello + operationId: 0 + parentSpanId: -1 + spanId: 0 + spanLayer: RPCFramework + startTime: nq 0 + endTime: nq 0 + componentId: 85 + componentName: '' + isError: false + spanType: Entry + peer: '' + peerId: 0 + refs: + - {parentEndpointId: 0, parentEndpoint: /finagle-17.10.x-scenario/case/finagle, networkAddressId: 0, + entryEndpointId: 0, refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null, + parentServiceInstanceId: 1, networkAddress: '127.0.0.1:12220', entryEndpoint: /finagle-17.10.x-scenario/case/finagle, + entryServiceInstanceId: 1} + - segmentId: not null + spans: + - operationName: hello + operationId: 0 + parentSpanId: 0 + spanId: 1 + spanLayer: RPCFramework + startTime: nq 0 + endTime: nq 0 + componentId: 85 + componentName: '' + isError: false + spanType: Exit + peer: 127.0.0.1:12220 + peerId: 0 + - operationName: /finagle-17.10.x-scenario/case/finagle + operationId: 0 + parentSpanId: -1 + spanId: 0 + spanLayer: Http + startTime: nq 0 + endTime: nq 0 + componentId: 1 + componentName: '' + isError: false + spanType: Entry + peer: '' + peerId: 0 + tags: + - {key: url, value: 'http://localhost:8080/finagle-17.10.x-scenario/case/finagle'} + - {key: http.method, value: GET} \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-17.10.x-scenario/configuration.yml b/test/plugin/scenarios/finagle-17.10.x-scenario/configuration.yml new file mode 100644 index 000000000..a6b9e03f4 --- /dev/null +++ b/test/plugin/scenarios/finagle-17.10.x-scenario/configuration.yml @@ -0,0 +1,23 @@ +# 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. + +type: jvm +entryService: http://localhost:8080/finagle-17.10.x-scenario/case/finagle +healthCheck: http://localhost:8080/finagle-17.10.x-scenario/case/healthCheck +startScript: ./bin/startup.sh +framework: finagle-17.10.x-scenario +environment: +dependencies: \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-17.10.x-scenario/pom.xml b/test/plugin/scenarios/finagle-17.10.x-scenario/pom.xml new file mode 100644 index 000000000..08e963a8d --- /dev/null +++ b/test/plugin/scenarios/finagle-17.10.x-scenario/pom.xml @@ -0,0 +1,170 @@ + + + + + org.apache.skywalking.apm.testcase + finagle-17.10.x-scenario + 1.0.0 + jar + + 4.0.0 + + + UTF-8 + 1.8 + 17.10.0 + 2.1.6.RELEASE + 1.18.10 + + + skywalking-finagle-17.10.x-scenario + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot-version} + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-logging + + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + com.twitter + finagle-core_2.11 + ${test.framework.version} + + + + com.twitter + finagle-thrift_2.11 + ${test.framework.version} + + + servlet-api + javax.servlet + + + + + + com.twitter + scrooge-core_2.11 + ${test.framework.version} + + + + + finagle-17.10.x-scenario + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + maven-compiler-plugin + + ${compiler.version} + ${compiler.version} + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-assembly-plugin + + + assemble + package + + single + + + + src/main/assembly/assembly.xml + + ./target/ + + + + + + com.twitter + scrooge-maven-plugin + ${test.framework.version} + + java + + --finagle + + false + + + + generate-thrift-sources + generate-sources + + compile + + + + thrift-test-sources + generate-test-sources + + testCompile + + + + + + + \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/assembly/assembly.xml b/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/assembly/assembly.xml new file mode 100644 index 000000000..76b0dbbf7 --- /dev/null +++ b/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/assembly/assembly.xml @@ -0,0 +1,41 @@ + + + + + zip + + + + + ./bin + 0775 + + + + + + ${project.build.directory}/finagle-17.10.x-scenario.jar + ./libs + 0775 + + + diff --git a/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/FinagleRpcApplication.java b/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/FinagleRpcApplication.java new file mode 100644 index 000000000..f1e40daea --- /dev/null +++ b/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/FinagleRpcApplication.java @@ -0,0 +1,55 @@ +/* + * 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.testcase.finagle; + + +import com.twitter.finagle.ListeningServer; +import com.twitter.finagle.Thrift; +import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService; +import org.apache.skywalking.apm.testcase.finagle.service.FinagleRpcDemoServiceImpl; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@SpringBootApplication +public class FinagleRpcApplication { + + public static void main(String[] args) { + SpringApplication.run(FinagleRpcApplication.class, args); + } + + + @Configuration + public static class FinagleRpcConfiguration { + + @Bean(destroyMethod = "close") + public ListeningServer server() { + ListeningServer server = Thrift.server() + .serveIface(":12220", new FinagleRpcDemoServiceImpl()); + return server; + } + + @Bean + public FinagleRpcDemoService.ServiceIface client() { + return Thrift.client() + .newIface("localhost:12220", FinagleRpcDemoService.ServiceIface.class); + } + } +} diff --git a/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/controller/CaseController.java b/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/controller/CaseController.java new file mode 100644 index 000000000..026fc6316 --- /dev/null +++ b/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/controller/CaseController.java @@ -0,0 +1,50 @@ +/* + * 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.testcase.finagle.controller; + +import com.twitter.util.Await; +import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +@RequestMapping("/case") +public class CaseController { + + private static final String SUCCESS = "Success"; + + @Autowired + private FinagleRpcDemoService.ServiceIface finagleRpcDemoService; + + @RequestMapping("/healthCheck") + @ResponseBody + public String healthCheck() { + return SUCCESS; + } + + @RequestMapping("/finagle") + @ResponseBody + public String finagle() throws Exception { + System.out.println(Await.result(finagleRpcDemoService.hello("finagle"))); + return SUCCESS; + } +} diff --git a/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/service/FinagleRpcDemoServiceImpl.java b/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/service/FinagleRpcDemoServiceImpl.java new file mode 100644 index 000000000..784519370 --- /dev/null +++ b/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/service/FinagleRpcDemoServiceImpl.java @@ -0,0 +1,30 @@ +/* + * 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.testcase.finagle.service; + +import com.twitter.util.Future; +import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService; + + +public class FinagleRpcDemoServiceImpl implements FinagleRpcDemoService.ServiceIface { + + public Future hello(String name) { + return Future.value("hello, " + name); + } +} diff --git a/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/resources/application.yaml b/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/resources/application.yaml new file mode 100644 index 000000000..96d5680d5 --- /dev/null +++ b/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/resources/application.yaml @@ -0,0 +1,21 @@ +# +# 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. +# +# +server: + port: 8080 + servlet: + context-path: /finagle-17.10.x-scenario \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/thrift/service.thrift b/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/thrift/service.thrift new file mode 100644 index 000000000..f37d915e1 --- /dev/null +++ b/test/plugin/scenarios/finagle-17.10.x-scenario/src/main/thrift/service.thrift @@ -0,0 +1,23 @@ +/* + * 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. + * + */ + +namespace java org.apache.skywalking.apm.testcase.finagle.interfaces + +service FinagleRpcDemoService { + string hello(string name); +} \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-17.10.x-scenario/support-version.list b/test/plugin/scenarios/finagle-17.10.x-scenario/support-version.list new file mode 100644 index 000000000..ecd0fac6d --- /dev/null +++ b/test/plugin/scenarios/finagle-17.10.x-scenario/support-version.list @@ -0,0 +1,46 @@ +# 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 +# "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. + +17.10.0 +17.11.0 +17.12.0 +18.1.0 +18.2.0 +18.3.0 +18.4.0 +18.5.0 +18.6.0 +18.7.0 +18.8.0 +18.9.0 +18.9.1 +18.10.0 +18.11.0 +18.12.0 +19.1.0 +19.2.0 +19.3.0 +19.4.0 +19.5.0 +19.5.1 +19.6.0 +19.7.0 +19.8.0 +19.9.0 +19.10.0 +19.11.0 +19.12.0 +20.1.0 \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-6.25.x-scenario/bin/startup.sh b/test/plugin/scenarios/finagle-6.25.x-scenario/bin/startup.sh new file mode 100644 index 000000000..14e577efd --- /dev/null +++ b/test/plugin/scenarios/finagle-6.25.x-scenario/bin/startup.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# +# 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. + +home="$(cd "$(dirname $0)"; pwd)" + +java -jar ${agent_opts} ${home}/../libs/finagle-6.25.x-scenario.jar & \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-6.25.x-scenario/config/expectedData.yaml b/test/plugin/scenarios/finagle-6.25.x-scenario/config/expectedData.yaml new file mode 100644 index 000000000..6f49af51e --- /dev/null +++ b/test/plugin/scenarios/finagle-6.25.x-scenario/config/expectedData.yaml @@ -0,0 +1,86 @@ +# 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. + +registryItems: + services: + - {finagle-6.25.x-scenario: 2} + instances: + - {finagle-6.25.x-scenario: 1} + operationNames: + - finagle-6.25.x-scenario: [hello, /finagle-6.25.x-scenario/case/finagle] + heartbeat: [] +segmentItems: + - serviceName: finagle-6.25.x-scenario + segmentSize: gt 2 + segments: + - segmentId: not null + spans: + - operationName: hello + operationId: 0 + parentSpanId: -1 + spanId: 0 + spanLayer: RPCFramework + startTime: nq 0 + endTime: nq 0 + componentId: 85 + componentName: '' + isError: false + spanType: Entry + peer: '' + peerId: 0 + refs: + - {parentEndpointId: 0, parentEndpoint: /finagle-6.25.x-scenario/case/finagle, networkAddressId: 0, + entryEndpointId: 0, refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null, + parentServiceInstanceId: 1, networkAddress: '127.0.0.1:12220', entryEndpoint: /finagle-6.25.x-scenario/case/finagle, + entryServiceInstanceId: 1} + - segmentId: not null + spans: + - operationName: hello + operationId: 0 + parentSpanId: 0 + spanId: 1 + spanLayer: RPCFramework + startTime: nq 0 + endTime: nq 0 + componentId: 85 + componentName: '' + isError: false + spanType: Exit + peer: 127.0.0.1:12220 + peerId: 0 + - operationName: /finagle-6.25.x-scenario/case/finagle + operationId: 0 + parentSpanId: -1 + spanId: 0 + spanLayer: Http + startTime: nq 0 + endTime: nq 0 + componentId: 1 + componentName: '' + isError: false + spanType: Entry + peer: '' + peerId: 0 + tags: + - {key: url, value: 'http://localhost:8080/finagle-6.25.x-scenario/case/finagle'} + - {key: http.method, value: GET} + + + + + + + diff --git a/test/plugin/scenarios/finagle-6.25.x-scenario/configuration.yml b/test/plugin/scenarios/finagle-6.25.x-scenario/configuration.yml new file mode 100644 index 000000000..9cc859af3 --- /dev/null +++ b/test/plugin/scenarios/finagle-6.25.x-scenario/configuration.yml @@ -0,0 +1,21 @@ +# 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. + +type: jvm +entryService: http://localhost:8080/finagle-6.25.x-scenario/case/finagle +healthCheck: http://localhost:8080/finagle-6.25.x-scenario/case/healthCheck +startScript: ./bin/startup.sh +framework: finagle \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-6.25.x-scenario/pom.xml b/test/plugin/scenarios/finagle-6.25.x-scenario/pom.xml new file mode 100644 index 000000000..34a102e2f --- /dev/null +++ b/test/plugin/scenarios/finagle-6.25.x-scenario/pom.xml @@ -0,0 +1,177 @@ + + + + 4.0.0 + + org.apache.skywalking + finagle-6.25.x-scenario + jar + 5.0.0 + + + UTF-8 + 1.8 + + 2.1.6.RELEASE + finagle + 6.25.0 + + + skywalking-finagle-6.25.x-scenario + + + + + org.springframework.boot + spring-boot-dependencies + ${spring.boot.version} + pom + import + + + + + + + com.twitter + finagle-core_2.11 + ${test.framework.version} + + + + com.twitter + finagle-thrift_2.11 + ${test.framework.version} + + + servlet-api + javax.servlet + + + + + + org.apache.thrift + libthrift + 0.9.3 + + + + com.twitter + scrooge-core_2.11 + 4.7.0 + + + + com.twitter + scrooge-runtime_2.11 + 4.5.0 + + + + org.springframework.boot + spring-boot-starter-web + + + + + finagle-6.25.x-scenario + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + maven-compiler-plugin + + ${compiler.version} + ${compiler.version} + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-assembly-plugin + + + assemble + package + + single + + + + src/main/assembly/assembly.xml + + ./target/ + + + + + + com.twitter + scrooge-maven-plugin + 4.5.0 + + experimental-java + + --finagle + + false + + + + generate-thrift-sources + generate-sources + + compile + + + + thrift-test-sources + generate-test-sources + + testCompile + + + + + + + + + + spring-snapshots + http://repo.spring.io/snapshot + + + spring-milestones + http://repo.spring.io/milestone + + + \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/assembly/assembly.xml b/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/assembly/assembly.xml new file mode 100644 index 000000000..c0ab4d3b8 --- /dev/null +++ b/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/assembly/assembly.xml @@ -0,0 +1,41 @@ + + + + + zip + + + + + ./bin + 0775 + + + + + + ${project.build.directory}/finagle-6.25.x-scenario.jar + ./libs + 0775 + + + diff --git a/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/FinagleRpcApplication.java b/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/FinagleRpcApplication.java new file mode 100644 index 000000000..c172b8b6b --- /dev/null +++ b/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/FinagleRpcApplication.java @@ -0,0 +1,55 @@ +/* + * 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.testcase.finagle; + + +import com.twitter.finagle.ListeningServer; +import com.twitter.finagle.Thrift; +import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService; +import org.apache.skywalking.apm.testcase.finagle.service.FinagleRpcDemoServiceImpl; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@SpringBootApplication +public class FinagleRpcApplication { + + public static void main(String[] args) { + SpringApplication.run(FinagleRpcApplication.class, args); + } + + + @Configuration + public static class FinagleRpcConfiguration { + + @Bean(destroyMethod = "close") + public ListeningServer server() { + ListeningServer server = Thrift.server() + .serveIface(":12220", new FinagleRpcDemoServiceImpl()); + return server; + } + + @Bean + public FinagleRpcDemoService.FutureIface client() { + return Thrift.client() + .newIface("localhost:12220", FinagleRpcDemoService.FutureIface.class); + } + } +} diff --git a/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/controller/CaseController.java b/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/controller/CaseController.java new file mode 100644 index 000000000..7f698c692 --- /dev/null +++ b/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/controller/CaseController.java @@ -0,0 +1,50 @@ +/* + * 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.testcase.finagle.controller; + +import com.twitter.util.Await; +import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +@RequestMapping("/case") +public class CaseController { + + private static final String SUCCESS = "Success"; + + @Autowired + private FinagleRpcDemoService.FutureIface finagleRpcDemoService; + + @RequestMapping("/healthCheck") + @ResponseBody + public String healthCheck() { + return SUCCESS; + } + + @RequestMapping("/finagle") + @ResponseBody + public String finagle() throws Exception { + System.out.println(Await.result(finagleRpcDemoService.hello("finagle"))); + return SUCCESS; + } +} diff --git a/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/service/FinagleRpcDemoServiceImpl.java b/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/service/FinagleRpcDemoServiceImpl.java new file mode 100644 index 000000000..91b6f8a9e --- /dev/null +++ b/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/service/FinagleRpcDemoServiceImpl.java @@ -0,0 +1,30 @@ +/* + * 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.testcase.finagle.service; + +import com.twitter.util.Future; +import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService; + + +public class FinagleRpcDemoServiceImpl implements FinagleRpcDemoService.FutureIface { + + public Future hello(String name) { + return Future.value("hello, " + name); + } +} diff --git a/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/resources/application.yml b/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/resources/application.yml new file mode 100644 index 000000000..b8c30e939 --- /dev/null +++ b/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/resources/application.yml @@ -0,0 +1,20 @@ +# 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. + +server: + port: 8080 + servlet: + context-path: /finagle-6.25.x-scenario \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/thrift/service.thrift b/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/thrift/service.thrift new file mode 100644 index 000000000..f37d915e1 --- /dev/null +++ b/test/plugin/scenarios/finagle-6.25.x-scenario/src/main/thrift/service.thrift @@ -0,0 +1,23 @@ +/* + * 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. + * + */ + +namespace java org.apache.skywalking.apm.testcase.finagle.interfaces + +service FinagleRpcDemoService { + string hello(string name); +} \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-6.25.x-scenario/support-version.list b/test/plugin/scenarios/finagle-6.25.x-scenario/support-version.list new file mode 100644 index 000000000..ae96648f2 --- /dev/null +++ b/test/plugin/scenarios/finagle-6.25.x-scenario/support-version.list @@ -0,0 +1,34 @@ +# 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 +# "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. + +6.25.0 +6.26.0 +6.27.0 +6.28.0 +6.29.0 +6.30.0 +6.31.0 +6.33.0 +6.34.0 +6.35.0 +6.36.0 +6.37.0 +6.38.0 +6.39.0 +6.40.0 +6.41.0 +6.42.0 +6.43.0 diff --git a/test/plugin/scenarios/finagle-6.44.x-scenario/bin/startup.sh b/test/plugin/scenarios/finagle-6.44.x-scenario/bin/startup.sh new file mode 100644 index 000000000..275802029 --- /dev/null +++ b/test/plugin/scenarios/finagle-6.44.x-scenario/bin/startup.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# +# 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. + +home="$(cd "$(dirname $0)"; pwd)" + +java -jar ${agent_opts} ${home}/../libs/finagle-6.44.x-scenario.jar & \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-6.44.x-scenario/config/expectedData.yaml b/test/plugin/scenarios/finagle-6.44.x-scenario/config/expectedData.yaml new file mode 100644 index 000000000..05ba675b1 --- /dev/null +++ b/test/plugin/scenarios/finagle-6.44.x-scenario/config/expectedData.yaml @@ -0,0 +1,78 @@ +# 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. +registryItems: + services: + - {finagle-6.44.x-scenario: 2} + instances: + - {finagle-6.44.x-scenario: 1} + operationNames: + - finagle-6.44.x-scenario: [hello, /finagle-6.44.x-scenario/case/finagle] + heartbeat: [] +segmentItems: + - serviceName: finagle-6.44.x-scenario + segmentSize: gt 2 + segments: + - segmentId: not null + spans: + - operationName: hello + operationId: 0 + parentSpanId: -1 + spanId: 0 + spanLayer: RPCFramework + startTime: nq 0 + endTime: nq 0 + componentId: 85 + componentName: '' + isError: false + spanType: Entry + peer: '' + peerId: 0 + refs: + - {parentEndpointId: 0, parentEndpoint: /finagle-6.44.x-scenario/case/finagle, networkAddressId: 0, + entryEndpointId: 0, refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null, + parentServiceInstanceId: 1, networkAddress: '127.0.0.1:12220', entryEndpoint: /finagle-6.44.x-scenario/case/finagle, + entryServiceInstanceId: 1} + - segmentId: not null + spans: + - operationName: hello + operationId: 0 + parentSpanId: 0 + spanId: 1 + spanLayer: RPCFramework + startTime: nq 0 + endTime: nq 0 + componentId: 85 + componentName: '' + isError: false + spanType: Exit + peer: 127.0.0.1:12220 + peerId: 0 + - operationName: /finagle-6.44.x-scenario/case/finagle + operationId: 0 + parentSpanId: -1 + spanId: 0 + spanLayer: Http + startTime: nq 0 + endTime: nq 0 + componentId: 1 + componentName: '' + isError: false + spanType: Entry + peer: '' + peerId: 0 + tags: + - {key: url, value: 'http://localhost:8080/finagle-6.44.x-scenario/case/finagle'} + - {key: http.method, value: GET} \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-6.44.x-scenario/configuration.yml b/test/plugin/scenarios/finagle-6.44.x-scenario/configuration.yml new file mode 100644 index 000000000..311b45286 --- /dev/null +++ b/test/plugin/scenarios/finagle-6.44.x-scenario/configuration.yml @@ -0,0 +1,23 @@ +# 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. + +type: jvm +entryService: http://localhost:8080/finagle-6.44.x-scenario/case/finagle +healthCheck: http://localhost:8080/finagle-6.44.x-scenario/case/healthCheck +startScript: ./bin/startup.sh +framework: finagle-6.44.x-scenario +environment: +dependencies: \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-6.44.x-scenario/pom.xml b/test/plugin/scenarios/finagle-6.44.x-scenario/pom.xml new file mode 100644 index 000000000..95ee34088 --- /dev/null +++ b/test/plugin/scenarios/finagle-6.44.x-scenario/pom.xml @@ -0,0 +1,170 @@ + + + + + org.apache.skywalking.apm.testcase + finagle-6.44.x-scenario + 1.0.0 + jar + + 4.0.0 + + + UTF-8 + 1.8 + 6.41.0 + 2.1.6.RELEASE + 1.18.10 + + + skywalking-finagle-6.44.x-scenario + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot-version} + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-logging + + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + com.twitter + finagle-core_2.11 + ${test.framework.version} + + + + com.twitter + finagle-thrift_2.11 + ${test.framework.version} + + + servlet-api + javax.servlet + + + + + + com.twitter + scrooge-core_2.11 + 4.20.0 + + + + + finagle-6.44.x-scenario + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + maven-compiler-plugin + + ${compiler.version} + ${compiler.version} + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-assembly-plugin + + + assemble + package + + single + + + + src/main/assembly/assembly.xml + + ./target/ + + + + + + com.twitter + scrooge-maven-plugin + 4.20.0 + + java + + --finagle + + false + + + + generate-thrift-sources + generate-sources + + compile + + + + thrift-test-sources + generate-test-sources + + testCompile + + + + + + + \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/assembly/assembly.xml b/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/assembly/assembly.xml new file mode 100644 index 000000000..84da8ccfc --- /dev/null +++ b/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/assembly/assembly.xml @@ -0,0 +1,41 @@ + + + + + zip + + + + + ./bin + 0775 + + + + + + ${project.build.directory}/finagle-6.44.x-scenario.jar + ./libs + 0775 + + + diff --git a/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/FinagleRpcApplication.java b/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/FinagleRpcApplication.java new file mode 100644 index 000000000..f1e40daea --- /dev/null +++ b/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/FinagleRpcApplication.java @@ -0,0 +1,55 @@ +/* + * 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.testcase.finagle; + + +import com.twitter.finagle.ListeningServer; +import com.twitter.finagle.Thrift; +import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService; +import org.apache.skywalking.apm.testcase.finagle.service.FinagleRpcDemoServiceImpl; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@SpringBootApplication +public class FinagleRpcApplication { + + public static void main(String[] args) { + SpringApplication.run(FinagleRpcApplication.class, args); + } + + + @Configuration + public static class FinagleRpcConfiguration { + + @Bean(destroyMethod = "close") + public ListeningServer server() { + ListeningServer server = Thrift.server() + .serveIface(":12220", new FinagleRpcDemoServiceImpl()); + return server; + } + + @Bean + public FinagleRpcDemoService.ServiceIface client() { + return Thrift.client() + .newIface("localhost:12220", FinagleRpcDemoService.ServiceIface.class); + } + } +} diff --git a/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/controller/CaseController.java b/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/controller/CaseController.java new file mode 100644 index 000000000..026fc6316 --- /dev/null +++ b/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/controller/CaseController.java @@ -0,0 +1,50 @@ +/* + * 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.testcase.finagle.controller; + +import com.twitter.util.Await; +import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +@RequestMapping("/case") +public class CaseController { + + private static final String SUCCESS = "Success"; + + @Autowired + private FinagleRpcDemoService.ServiceIface finagleRpcDemoService; + + @RequestMapping("/healthCheck") + @ResponseBody + public String healthCheck() { + return SUCCESS; + } + + @RequestMapping("/finagle") + @ResponseBody + public String finagle() throws Exception { + System.out.println(Await.result(finagleRpcDemoService.hello("finagle"))); + return SUCCESS; + } +} diff --git a/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/service/FinagleRpcDemoServiceImpl.java b/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/service/FinagleRpcDemoServiceImpl.java new file mode 100644 index 000000000..784519370 --- /dev/null +++ b/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/finagle/service/FinagleRpcDemoServiceImpl.java @@ -0,0 +1,30 @@ +/* + * 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.testcase.finagle.service; + +import com.twitter.util.Future; +import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService; + + +public class FinagleRpcDemoServiceImpl implements FinagleRpcDemoService.ServiceIface { + + public Future hello(String name) { + return Future.value("hello, " + name); + } +} diff --git a/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/resources/application.yaml b/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/resources/application.yaml new file mode 100644 index 000000000..341369212 --- /dev/null +++ b/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/resources/application.yaml @@ -0,0 +1,21 @@ +# +# 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. +# +# +server: + port: 8080 + servlet: + context-path: /finagle-6.44.x-scenario \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/thrift/service.thrift b/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/thrift/service.thrift new file mode 100644 index 000000000..f37d915e1 --- /dev/null +++ b/test/plugin/scenarios/finagle-6.44.x-scenario/src/main/thrift/service.thrift @@ -0,0 +1,23 @@ +/* + * 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. + * + */ + +namespace java org.apache.skywalking.apm.testcase.finagle.interfaces + +service FinagleRpcDemoService { + string hello(string name); +} \ No newline at end of file diff --git a/test/plugin/scenarios/finagle-6.44.x-scenario/support-version.list b/test/plugin/scenarios/finagle-6.44.x-scenario/support-version.list new file mode 100644 index 000000000..34a0e1c17 --- /dev/null +++ b/test/plugin/scenarios/finagle-6.44.x-scenario/support-version.list @@ -0,0 +1,20 @@ +# 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 +# "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. + +6.44.0 +6.45.0 +7.0.0 +7.1.0 \ No newline at end of file