diff --git a/.github/workflows/plugins-test.3.yaml b/.github/workflows/plugins-test.3.yaml
index d4c45f9bb..d86c917b3 100644
--- a/.github/workflows/plugins-test.3.yaml
+++ b/.github/workflows/plugins-test.3.yaml
@@ -54,6 +54,7 @@ jobs:
- elasticjob-2.x-scenario
- quartz-scheduler-2.x-scenario
- xxl-job-2.x-scenario
+ - thrift-scenario
steps:
- uses: actions/checkout@v2
with:
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 2494d1b73..91b3b449d 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
@@ -180,4 +180,9 @@ public class ComponentsDefine {
public static final OfficialComponent XXL_JOB = new OfficialComponent(98, "xxl-job");
public static final OfficialComponent SPRING_WEBCLIENT = new OfficialComponent(99, "spring-webflux-webclient");
+
+ public static final OfficialComponent THRIFT_SERVER = new OfficialComponent(100, "thrift-server");
+
+ public static final OfficialComponent THRIFT_CLIENT = new OfficialComponent(101, "thrift-client");
+
}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml
index 383e55f8a..f7b68a376 100644
--- a/apm-sniffer/apm-sdk-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pom.xml
@@ -100,6 +100,7 @@
hbase-1.x-plugin
graphql-plugin
xxl-job-2.x-plugin
+ thrift-plugin
pom
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/thrift-plugin/pom.xml
new file mode 100644
index 000000000..b235f5de3
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/pom.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+ org.apache.skywalking
+ apm-sdk-plugin
+ 8.2.0-SNAPSHOT
+
+ 4.0.0
+
+ thrift-plugin
+ jar
+ apm-thrift-plugin
+
+
+ 0.13.0
+
+
+
+
+ org.apache.thrift
+ libthrift
+ ${thrift.version}
+ provided
+
+
+
+
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/TBaseAsyncProcessorInterceptor.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/TBaseAsyncProcessorInterceptor.java
new file mode 100644
index 000000000..50e9e5942
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/TBaseAsyncProcessorInterceptor.java
@@ -0,0 +1,76 @@
+/*
+ * 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.thrift;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+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 org.apache.skywalking.apm.plugin.thrift.wrapper.AsyncContext;
+import org.apache.skywalking.apm.plugin.thrift.wrapper.ServerInProtocolWrapper;
+import org.apache.thrift.AsyncProcessFunction;
+import org.apache.thrift.TBaseAsyncProcessor;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.server.AbstractNonblockingServer;
+
+/**
+ * To wrap the AsyncProcessFunction for getting arguments of method.
+ *
+ * @see TBaseAsyncProcessor
+ */
+public class TBaseAsyncProcessorInterceptor implements InstanceConstructorInterceptor, InstanceMethodsAroundInterceptor {
+ private Map processMapView = null;
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
+ processMapView = ((TBaseAsyncProcessor) objInst).getProcessMapView();
+ }
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst,
+ Method method,
+ Object[] allArguments,
+ Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ TProtocol protocol = ((AbstractNonblockingServer.AsyncFrameBuffer) allArguments[0]).getInputProtocol();
+ ((ServerInProtocolWrapper) protocol).initial(new AsyncContext(processMapView));
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst,
+ Method method,
+ Object[] allArguments,
+ Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst,
+ Method method,
+ Object[] allArguments,
+ Class>[] argumentsTypes,
+ Throwable t) {
+ ContextManager.activeSpan().log(t);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/TBaseProcessorInterceptor.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/TBaseProcessorInterceptor.java
new file mode 100644
index 000000000..5f3ba80c6
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/TBaseProcessorInterceptor.java
@@ -0,0 +1,76 @@
+/*
+ * 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.thrift;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+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 org.apache.skywalking.apm.plugin.thrift.wrapper.Context;
+import org.apache.skywalking.apm.plugin.thrift.wrapper.ServerInProtocolWrapper;
+import org.apache.thrift.ProcessFunction;
+import org.apache.thrift.TBaseAsyncProcessor;
+import org.apache.thrift.TBaseProcessor;
+
+/**
+ * To wrap the ProcessFunction for getting arguments of method.
+ *
+ * @see TBaseAsyncProcessor
+ * @see TBaseProcessorInterceptor
+ */
+public class TBaseProcessorInterceptor implements InstanceConstructorInterceptor, InstanceMethodsAroundInterceptor {
+ private Map processMap;
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
+ processMap = ((TBaseProcessor) objInst).getProcessMapView();
+ }
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst,
+ Method method,
+ Object[] allArguments,
+ Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ ServerInProtocolWrapper in = (ServerInProtocolWrapper) allArguments[0];
+ in.initial(new Context(processMap));
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst,
+ Method method,
+ Object[] allArguments,
+ Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst,
+ Method method,
+ Object[] allArguments,
+ Class>[] argumentsTypes,
+ Throwable t) {
+ ContextManager.activeSpan().log(t);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/TServerInterceptor.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/TServerInterceptor.java
new file mode 100644
index 000000000..0563dd423
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/TServerInterceptor.java
@@ -0,0 +1,54 @@
+/*
+ * 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.thrift;
+
+import org.apache.skywalking.apm.agent.core.logging.api.ILog;
+import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
+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.plugin.thrift.commons.ReflectionUtils;
+import org.apache.skywalking.apm.plugin.thrift.wrapper.ServerInProtocolWrapper;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.server.TServer;
+
+/**
+ * Hijack the ProtocolFactory for wrapping the Protocol object to propagate trace context(receiver).
+ */
+public class TServerInterceptor implements InstanceConstructorInterceptor {
+ private static final ILog LOGGER = LogManager.getLogger(TServerInterceptor.class);
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
+ try {
+ final TProtocolFactory inputProtocolFactory = (TProtocolFactory) ReflectionUtils.getValue(
+ TServer.class,
+ objInst,
+ "inputProtocolFactory_"
+ );
+ ReflectionUtils.setValue(
+ TServer.class,
+ objInst,
+ "inputProtocolFactory_",
+ (TProtocolFactory) trans -> new ServerInProtocolWrapper(inputProtocolFactory.getProtocol(trans))
+ );
+ } catch (Exception e) {
+ LOGGER.error("Failed to hijack TServer's TProtocolFactory.", e);
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/client/TAsyncClientInterceptor.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/client/TAsyncClientInterceptor.java
new file mode 100644
index 000000000..9472a84bb
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/client/TAsyncClientInterceptor.java
@@ -0,0 +1,52 @@
+/*
+ * 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.thrift.client;
+
+import org.apache.skywalking.apm.agent.core.logging.api.ILog;
+import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
+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.plugin.thrift.commons.ReflectionUtils;
+import org.apache.skywalking.apm.plugin.thrift.wrapper.ClientOutProtocolWrapper;
+import org.apache.thrift.async.TAsyncClient;
+import org.apache.thrift.protocol.TProtocolFactory;
+
+/**
+ * Hijack the TProtocolFactory for wrapping the Protocol object to propagate trace context(write out).
+ *
+ * @see TAsyncClient
+ */
+public class TAsyncClientInterceptor implements InstanceConstructorInterceptor {
+ private static final ILog LOGGER = LogManager.getLogger(TAsyncClientInterceptor.class);
+
+ @Override
+ public void onConstruct(final EnhancedInstance objInst, final Object[] objects) {
+ try {
+ ReflectionUtils.setValue(
+ TAsyncClient.class,
+ objInst,
+ "___protocolFactory",
+ (TProtocolFactory) transport ->
+ new ClientOutProtocolWrapper(((TProtocolFactory) objects[0]).getProtocol(transport))
+ );
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ LOGGER.error("Failed to hijack TAsyncClient's TProtocolFactory.", e);
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/client/TAsyncMethodCallInterceptor.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/client/TAsyncMethodCallInterceptor.java
new file mode 100644
index 000000000..6cd0b1895
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/client/TAsyncMethodCallInterceptor.java
@@ -0,0 +1,104 @@
+/*
+ * 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.thrift.client;
+
+import java.lang.reflect.Method;
+import org.apache.skywalking.apm.agent.core.context.AsyncSpan;
+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.InstanceConstructorInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.thrift.commons.ReflectionUtils;
+import org.apache.thrift.async.AsyncMethodCallback;
+import org.apache.thrift.async.TAsyncMethodCall;
+
+/**
+ * Here is asynchronized client.
+ */
+public class TAsyncMethodCallInterceptor implements InstanceConstructorInterceptor, InstanceMethodsAroundInterceptor {
+ private String remotePeer = "UNKNOWN";
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst,
+ Object[] allArguments) throws NoSuchFieldException, IllegalAccessException {
+ ReflectionUtils.setValue(TAsyncMethodCall.class, objInst, "callback", new AsyncMethodCallback() {
+ final AsyncMethodCallback callback = (AsyncMethodCallback) allArguments[3];
+
+ @Override
+ public void onComplete(final Object response) {
+ try {
+ AsyncSpan span = (AsyncSpan) objInst.getSkyWalkingDynamicField();
+ span.asyncFinish();
+ } finally {
+ callback.onComplete(response);
+ }
+ }
+
+ @Override
+ public void onError(final Exception exception) {
+ try {
+ AsyncSpan span = (AsyncSpan) objInst.getSkyWalkingDynamicField();
+ span.asyncFinish().log(exception);
+ } finally {
+ callback.onError(exception);
+ }
+ }
+ });
+ if (allArguments[2] instanceof EnhancedInstance) {
+ remotePeer = (String) ((EnhancedInstance) allArguments[2]).getSkyWalkingDynamicField();
+ }
+ }
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst,
+ Method method,
+ Object[] allArguments,
+ Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ AbstractSpan span = ContextManager.createExitSpan(objInst.getClass().getName(), remotePeer);
+ span.setComponent(ComponentsDefine.THRIFT_CLIENT);
+ SpanLayer.asRPCFramework(span);
+
+ AbstractSpan async = span.prepareForAsync();
+ objInst.setSkyWalkingDynamicField(async);
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst,
+ Method method,
+ Object[] allArguments,
+ Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst,
+ Method method,
+ Object[] allArguments,
+ Class>[] argumentsTypes,
+ Throwable t) {
+ ContextManager.activeSpan().errorOccurred().log(t);
+ }
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/client/TServiceClientInterceptor.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/client/TServiceClientInterceptor.java
new file mode 100644
index 000000000..ae3a3c978
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/client/TServiceClientInterceptor.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.thrift.client;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.tag.StringTag;
+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.InstanceConstructorInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.thrift.commons.ReflectionUtils;
+import org.apache.skywalking.apm.plugin.thrift.wrapper.ClientOutProtocolWrapper;
+import org.apache.thrift.TBase;
+import org.apache.thrift.TFieldIdEnum;
+import org.apache.thrift.TServiceClient;
+import org.apache.thrift.protocol.TProtocol;
+
+import java.lang.reflect.Method;
+import java.util.Objects;
+
+/**
+ * Here is synchronized client.
+ *
+ * @see TServiceClient
+ */
+public class TServiceClientInterceptor implements InstanceConstructorInterceptor, InstanceMethodsAroundInterceptor {
+ private static final StringTag TAG_ARGS = new StringTag("args");
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst,
+ Object[] allArguments) throws NoSuchFieldException, IllegalAccessException {
+ if (!(allArguments[1] instanceof ClientOutProtocolWrapper)) {
+ TProtocol protocol = (TProtocol) allArguments[1];
+ ReflectionUtils.setValue(
+ TServiceClient.class,
+ objInst,
+ "oprot_",
+ new ClientOutProtocolWrapper(protocol)
+ );
+ Object dynamicField = ((EnhancedInstance) protocol.getTransport()).getSkyWalkingDynamicField();
+ objInst.setSkyWalkingDynamicField(Objects.isNull(dynamicField) ? "UNKNOWN" : dynamicField);
+ }
+ }
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst,
+ Method method,
+ Object[] allArguments,
+ Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ AbstractSpan span = ContextManager.createExitSpan(
+ objInst.getClass().getName() + "." + allArguments[0],
+ (String) objInst.getSkyWalkingDynamicField()
+ );
+ SpanLayer.asRPCFramework(span);
+ span.setComponent(ComponentsDefine.THRIFT_CLIENT);
+ span.tag(TAG_ARGS, getArguments((String) allArguments[0], (TBase) allArguments[1]));
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst,
+ Method method,
+ Object[] allArguments,
+ Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst,
+ Method method,
+ Object[] allArguments,
+ Class>[] argumentsTypes,
+ Throwable t) {
+ ContextManager.activeSpan().log(t);
+ }
+
+ private String getArguments(String method, TBase base) {
+ int idx = 0;
+ StringBuilder buffer = new StringBuilder(method).append("(");
+ while (true) {
+ TFieldIdEnum field = base.fieldForId(++idx);
+ if (field == null) {
+ break;
+ }
+ buffer.append(field.getFieldName()).append(", ");
+ }
+ if (idx > 0) {
+ buffer.delete(buffer.length() - 2, buffer.length());
+ }
+ return buffer.append(")").toString();
+ }
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/client/TServiceClientReceiveInterceptor.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/client/TServiceClientReceiveInterceptor.java
new file mode 100644
index 000000000..0e18a8134
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/client/TServiceClientReceiveInterceptor.java
@@ -0,0 +1,63 @@
+/*
+ * 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.thrift.client;
+
+import java.lang.reflect.Method;
+import java.util.Objects;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+
+/**
+ * TAsyncClient creates a TServiceClient for receiving the response. So splitting this method,
+ * TAsyncClient#receiveBase(...), into here for more efficiency.
+ */
+public class TServiceClientReceiveInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(final EnhancedInstance objInst,
+ final Method method,
+ final Object[] objects,
+ final Class>[] classes,
+ final MethodInterceptResult ret) throws Throwable {
+ }
+
+ @Override
+ public Object afterMethod(final EnhancedInstance objInst,
+ final Method method,
+ final Object[] objects,
+ final Class>[] classes,
+ final Object ret) throws Throwable {
+ // Have to stop only when the span is created by TServiceClientInterceptor#beforeMethod(...).
+ if (Objects.nonNull(objInst.getSkyWalkingDynamicField())) {
+ ContextManager.stopSpan();
+ }
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(final EnhancedInstance enhancedInstance,
+ final Method method,
+ final Object[] objects,
+ final Class>[] classes,
+ final Throwable throwable) {
+ ContextManager.activeSpan().log(throwable);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/commons/ReflectionUtils.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/commons/ReflectionUtils.java
new file mode 100644
index 000000000..c53eeb181
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/commons/ReflectionUtils.java
@@ -0,0 +1,37 @@
+/*
+ * 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.thrift.commons;
+
+import java.lang.reflect.Field;
+
+public class ReflectionUtils {
+
+ public static final void setValue(Class klass, Object instance, String name, Object value) throws NoSuchFieldException, IllegalAccessException {
+ Field field = klass.getDeclaredField(name);
+ field.setAccessible(true);
+ field.set(instance, value);
+ }
+
+ public static final Object getValue(Class klass, Object instance, String name) throws NoSuchFieldException, IllegalAccessException {
+ Field field = klass.getDeclaredField(name);
+ field.setAccessible(true);
+ return field.get(instance);
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/TBaseAsyncProcessorInstrumentation.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/TBaseAsyncProcessorInstrumentation.java
new file mode 100644
index 000000000..c993e340b
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/TBaseAsyncProcessorInstrumentation.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.thrift.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+public class TBaseAsyncProcessorInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.thrift.TBaseAsyncProcessorInterceptor";
+ private static final String ENHANCE_CLASS = "org.apache.thrift.TBaseAsyncProcessor";
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return ElementMatchers.any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return ElementMatchers.named("process");
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/TBaseProcessorInstrumentation.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/TBaseProcessorInstrumentation.java
new file mode 100644
index 000000000..335aa9f84
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/TBaseProcessorInstrumentation.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.thrift.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+public class TBaseProcessorInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+ private static final String ENHANCE_CLASS = "org.apache.thrift.TBaseProcessor";
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.thrift.TBaseProcessorInterceptor";
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return ElementMatchers.any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return ElementMatchers.named("process").and(ElementMatchers.takesArguments(2));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/TServerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/TServerInstrumentation.java
new file mode 100644
index 000000000..8fd377447
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/TServerInstrumentation.java
@@ -0,0 +1,63 @@
+/*
+ * 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.thrift.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch;
+
+public class TServerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.thrift.TServerInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return MultiClassNameMatch.byMultiClassMatch(
+ "org.apache.thrift.server.TServer",
+ "org.apache.thrift.server.TServlet"
+ );
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return ElementMatchers.any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {};
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/client/TAsyncClientInstrumentation.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/client/TAsyncClientInstrumentation.java
new file mode 100644
index 000000000..27cf956d8
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/client/TAsyncClientInstrumentation.java
@@ -0,0 +1,65 @@
+/*
+ * 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.thrift.define.client;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+/**
+ * Hijack the TProtocolFactory.(Asynchronized Client)
+ *
+ * @see org.apache.thrift.async.TAsyncClient
+ */
+public class TAsyncClientInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+ private static final String ENHANCE_CLASS = "org.apache.thrift.async.TAsyncClient";
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.thrift.client.TAsyncClientInterceptor";
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return ElementMatchers.takesArguments(4);
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {};
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/client/TAsyncMethodCallInstrumentation.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/client/TAsyncMethodCallInstrumentation.java
new file mode 100644
index 000000000..690383e00
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/client/TAsyncMethodCallInstrumentation.java
@@ -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.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.thrift.define.client;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+public class TAsyncMethodCallInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.thrift.client.TAsyncMethodCallInterceptor";
+ private static final String ENHANCE_CLASS = "org.apache.thrift.async.TAsyncMethodCall";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return ElementMatchers.any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return ElementMatchers.named("prepareMethodCall");
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/client/TServiceClientInstrumentation.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/client/TServiceClientInstrumentation.java
new file mode 100644
index 000000000..fbe1eb743
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/client/TServiceClientInstrumentation.java
@@ -0,0 +1,101 @@
+/*
+ * 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.thrift.define.client;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+/**
+ * Hijack the TProtocolFactory.(Synchronized Client)
+ *
+ * @see org.apache.thrift.TServiceClient
+ */
+public class TServiceClientInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+ private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.thrift.client.TServiceClientInterceptor";
+ private static final String RECEIVE_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.thrift.client.TServiceClientReceiveInterceptor";
+ private static final String ENHANCE_CLASS = "org.apache.thrift.TServiceClient";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return ElementMatchers.takesArguments(2);
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return ElementMatchers.named("sendBase").and(ElementMatchers.takesArguments(3));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return INTERCEPTOR_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return ElementMatchers.named("receiveBase");
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return RECEIVE_INTERCEPTOR_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/transport/TSocketInstrumentation.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/transport/TSocketInstrumentation.java
new file mode 100644
index 000000000..0f30e3d6a
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/define/transport/TSocketInstrumentation.java
@@ -0,0 +1,61 @@
+/*
+ * 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.thrift.define.transport;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.MultiClassNameMatch;
+
+public class TSocketInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return MultiClassNameMatch.byMultiClassMatch(
+ "org.apache.thrift.transport.TSocket",
+ "org.apache.thrift.transport.TNonblockingSocket"
+ );
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return ElementMatchers.takesArguments(String.class, int.class, int.class);
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return "org.apache.skywalking.apm.plugin.thrift.transport.TSocketInterceptor";
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {};
+ }
+}
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/transport/TSocketInterceptor.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/transport/TSocketInterceptor.java
new file mode 100644
index 000000000..0fd68a778
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/transport/TSocketInterceptor.java
@@ -0,0 +1,35 @@
+/*
+ * 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.thrift.transport;
+
+import java.io.IOException;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
+
+/**
+ * For getting remote peer.
+ */
+public class TSocketInterceptor implements InstanceConstructorInterceptor {
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws IOException {
+ objInst.setSkyWalkingDynamicField(allArguments[0] + ":" + allArguments[1]);
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/AbstractContext.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/AbstractContext.java
new file mode 100644
index 000000000..f524de952
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/AbstractContext.java
@@ -0,0 +1,37 @@
+/*
+ * 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.thrift.wrapper;
+
+/**
+ * A context
+ */
+public abstract class AbstractContext {
+ public String methodName;
+ public long startTime = 0L;
+
+ public abstract String getArguments();
+
+ public abstract String getOperatorName();
+
+ public final void setup(String methodName) {
+ this.methodName = methodName;
+ this.startTime = System.currentTimeMillis();
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/AbstractProtocolWrapper.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/AbstractProtocolWrapper.java
new file mode 100644
index 000000000..86661cfc2
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/AbstractProtocolWrapper.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.thrift.wrapper;
+
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolDecorator;
+
+/**
+ * Note that the 8888th field of record is reserved for transporting trace header. Because Thrift doesn't support to
+ * transport metadata.
+ */
+public abstract class AbstractProtocolWrapper extends TProtocolDecorator {
+ public static final String SW_MAGIC_FIELD = "SW_MAGIC_FIELD"; // Field Name
+ public static final short SW_MAGIC_FIELD_ID = 8888; // Field ID, a magic number
+
+ public AbstractProtocolWrapper(final TProtocol protocol) {
+ super(protocol);
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/AsyncContext.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/AsyncContext.java
new file mode 100644
index 000000000..f02695eeb
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/AsyncContext.java
@@ -0,0 +1,41 @@
+/*
+ * 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.thrift.wrapper;
+
+import java.util.Map;
+import org.apache.thrift.AsyncProcessFunction;
+
+public class AsyncContext extends AbstractContext {
+ private final Map processMapView;
+
+ public AsyncContext(Map processMapView) {
+ this.processMapView = processMapView;
+ }
+
+ @Override
+ public String getArguments() {
+ return processMapView.get(methodName).getEmptyArgsInstance().toString();
+ }
+
+ @Override
+ public String getOperatorName() {
+ return processMapView.get(methodName).getClass().getName();
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/ClientOutProtocolWrapper.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/ClientOutProtocolWrapper.java
new file mode 100644
index 000000000..6d76c11db
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/ClientOutProtocolWrapper.java
@@ -0,0 +1,91 @@
+/*
+ * 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.thrift.wrapper;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import org.apache.skywalking.apm.agent.core.context.CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.logging.api.ILog;
+import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TField;
+import org.apache.thrift.protocol.TMap;
+import org.apache.thrift.protocol.TMessage;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TType;
+
+/**
+ * Wrapping client output protocol for injecting and propagating the trace header. This is also safe even if the server
+ * doesn't deal with it.
+ */
+public class ClientOutProtocolWrapper extends AbstractProtocolWrapper {
+ private static final ILog LOGGER = LogManager.getLogger(ClientOutProtocolWrapper.class);
+ private boolean injected = true;
+
+ public ClientOutProtocolWrapper(final TProtocol protocol) {
+ super(protocol);
+ }
+
+ @Override
+ public final void writeMessageBegin(final TMessage message) throws TException {
+ injected = false;
+ super.writeMessageBegin(message);
+ }
+
+ @Override
+ public final void writeFieldStop() throws TException {
+ if (!injected && ContextManager.isActive()) {
+ try {
+ final ContextCarrier carrier = new ContextCarrier();
+ ContextManager.inject(carrier);
+ CarrierItem items = carrier.items();
+
+ final Map header = new HashMap<>(3);
+ while (items.hasNext()) {
+ items = items.next();
+ header.put(items.getHeadKey(), items.getHeadValue());
+ }
+ writeHeader(header);
+ } catch (Throwable throwable) {
+ LOGGER.error("Failed to propagating CarrierItems.", throwable);
+ } finally {
+ injected = true;
+ }
+ }
+ super.writeFieldStop();
+ }
+
+ private void writeHeader(Map header) throws TException {
+ super.writeFieldBegin(new TField(SW_MAGIC_FIELD, TType.MAP, SW_MAGIC_FIELD_ID));
+ super.writeMapBegin(new TMap(TType.STRING, TType.STRING, header.size()));
+
+ final Set> entries = header.entrySet();
+ for (Map.Entry entry : entries) {
+ super.writeString(entry.getKey());
+ super.writeString(entry.getValue());
+ }
+
+ super.writeMapEnd();
+ super.writeFieldEnd();
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/Context.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/Context.java
new file mode 100644
index 000000000..66c6d63e4
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/Context.java
@@ -0,0 +1,40 @@
+/*
+ * 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.thrift.wrapper;
+
+import java.util.Map;
+import org.apache.thrift.ProcessFunction;
+
+public class Context extends AbstractContext {
+ private final Map processMapView;
+
+ public Context(Map processMapView) {
+ this.processMapView = processMapView;
+ }
+
+ @Override
+ public String getArguments() {
+ return processMapView.get(methodName).getEmptyArgsInstance().toString();
+ }
+
+ @Override
+ public String getOperatorName() {
+ return processMapView.get(methodName).getClass().getName();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/ServerInProtocolWrapper.java b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/ServerInProtocolWrapper.java
new file mode 100644
index 000000000..a05404641
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/java/org/apache/skywalking/apm/plugin/thrift/wrapper/ServerInProtocolWrapper.java
@@ -0,0 +1,108 @@
+/*
+ * 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.thrift.wrapper;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import org.apache.skywalking.apm.agent.core.context.CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.tag.StringTag;
+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.logging.api.ILog;
+import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TField;
+import org.apache.thrift.protocol.TMap;
+import org.apache.thrift.protocol.TMessage;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TType;
+
+/**
+ * Wrapping server input protocol for reading and parsing the trace header from the original protocol. It is a special
+ * field which will be skipped without one deal with.
+ */
+public class ServerInProtocolWrapper extends AbstractProtocolWrapper {
+ private static final ILog LOGGER = LogManager.getLogger(ServerInProtocolWrapper.class);
+ private static final StringTag TAG_ARGS = new StringTag("args");
+ private AbstractContext context;
+
+ public ServerInProtocolWrapper(final TProtocol protocol) {
+ super(protocol);
+ }
+
+ public void initial(AbstractContext context) {
+ this.context = context;
+ }
+
+ @Override
+ public TField readFieldBegin() throws TException {
+ final TField field = super.readFieldBegin();
+ if (field.id == SW_MAGIC_FIELD_ID && field.type == TType.MAP) {
+ try {
+ TMap tMap = super.readMapBegin();
+ Map header = new HashMap<>(tMap.size);
+
+ for (int i = 0; i < tMap.size; i++) {
+ header.put(readString(), readString());
+ }
+
+ AbstractSpan span = ContextManager.createEntrySpan(
+ context.getOperatorName(), createContextCarrier(header));
+ span.start(context.startTime);
+ span.tag(TAG_ARGS, context.getArguments());
+ span.setComponent(ComponentsDefine.THRIFT_SERVER);
+ SpanLayer.asRPCFramework(span);
+ } catch (Throwable throwable) {
+ LOGGER.error("Failed to resolve header or create EntrySpan.", throwable);
+ } finally {
+ context = null;
+ super.readMapEnd();
+ super.readFieldEnd();
+ }
+ return readFieldBegin();
+ }
+ return field;
+ }
+
+ private ContextCarrier createContextCarrier(Map header) {
+ ContextCarrier carrier = new ContextCarrier();
+ if (Objects.nonNull(header)) {
+ CarrierItem items = carrier.items();
+ while (items.hasNext()) {
+ items = items.next();
+ items.setHeadValue(header.get(items.getHeadKey()));
+ }
+ }
+ return carrier;
+ }
+
+ @Override
+ public TMessage readMessageBegin() throws TException {
+ final TMessage message = super.readMessageBegin();
+ if (Objects.nonNull(message)) {
+ context.setup(message.name);
+ }
+ return message;
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 000000000..47ad968f8
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/thrift-plugin/src/main/resources/skywalking-plugin.def
@@ -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.
+
+thrift=org.apache.skywalking.apm.plugin.thrift.define.TServerInstrumentation
+thrift=org.apache.skywalking.apm.plugin.thrift.define.client.TAsyncClientInstrumentation
+thrift=org.apache.skywalking.apm.plugin.thrift.define.client.TAsyncMethodCallInstrumentation
+thrift=org.apache.skywalking.apm.plugin.thrift.define.client.TServiceClientInstrumentation
+thrift=org.apache.skywalking.apm.plugin.thrift.define.client.TServiceClientReceiveInstrumentation
+thrift=org.apache.skywalking.apm.plugin.thrift.define.TBaseProcessorInstrumentation
+thrift=org.apache.skywalking.apm.plugin.thrift.define.TBaseAsyncProcessorInstrumentation
+thrift=org.apache.skywalking.apm.plugin.thrift.define.transport.TSocketInstrumentation
diff --git a/docs/en/FAQ/README.md b/docs/en/FAQ/README.md
index 0413ee131..f0b8f43c4 100644
--- a/docs/en/FAQ/README.md
+++ b/docs/en/FAQ/README.md
@@ -26,3 +26,4 @@ These are known and common FAQs. We welcome you to contribute yours.
* [Use the profile exporter tool if the profile analysis is not right](../guides/backend-profile-export.md)
* [Compatible with other javaagent bytecode processing](Compatible-with-other-javaagent-bytecode-processing.md)
* [**Java agent memory leak** when enhance `Worker thread` at use Thread Pool](Memory-leak-enhance-Worker-thread.md)
+* [Thrift plugin](thrift-plugin.md)
\ No newline at end of file
diff --git a/docs/en/FAQ/thrift-plugin.md b/docs/en/FAQ/thrift-plugin.md
new file mode 100644
index 000000000..abb4b513f
--- /dev/null
+++ b/docs/en/FAQ/thrift-plugin.md
@@ -0,0 +1,10 @@
+### Problem
+The message with Field ID, 8888, must be revered.
+
+### Reason
+Because Thrift cannot carry metadata to transport Trace Header in the original API, we transport those by wrapping TProtocolFactory to do that.
+
+Thrift allows us to append any additional field in the Message even if the receiver doesn't deal with them. This data is going to be skipped while no one reads. Base on this, we take the 8888th field of Message to store Trace Header(or metadata) and to transport. That means the message with Field ID, 8888, must be revered.
+
+### Resolve
+Avoiding to use the Field(ID is 8888) in your application.
\ No newline at end of file
diff --git a/docs/en/setup/service-agent/java-agent/Plugin-list.md b/docs/en/setup/service-agent/java-agent/Plugin-list.md
index 79a1410cb..ef0ed1ce0 100644
--- a/docs/en/setup/service-agent/java-agent/Plugin-list.md
+++ b/docs/en/setup/service-agent/java-agent/Plugin-list.md
@@ -90,6 +90,7 @@
- spring-webflux-5.x-webclient
- spymemcached-2.x
- struts2-2.x
+- thrift
- tomcat-7.x/8.x
- toolkit-counter
- toolkit-gauge
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 4fc1e5323..e5d12272d 100644
--- a/docs/en/setup/service-agent/java-agent/Supported-list.md
+++ b/docs/en/setup/service-agent/java-agent/Supported-list.md
@@ -46,6 +46,7 @@
* [Apache Avro](http://avro.apache.org) 1.7.0 - 1.8.x
* [Finagle](https://github.com/twitter/finagle) 6.25.0 -> 20.1.0
* [Brpc-Java](https://github.com/baidu/brpc-java) 2.3.7 -> 2.5.3
+ * [Thrift](https://github.com/apache/thrift/tree/master/lib/java) 0.10.0 -> 0.12.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 a0a816d68..8a513e78f 100755
--- a/oap-server/server-bootstrap/src/main/resources/component-libraries.yml
+++ b/oap-server/server-bootstrap/src/main/resources/component-libraries.yml
@@ -329,6 +329,13 @@ xxl-job:
spring-webflux-webclient:
id: 99
languages: Java
+thrift-server:
+ id: 100
+ languages: Java
+thrift-client:
+ id: 101
+ languages: Java
+
# .NET/.NET Core components
# [3000, 4000) for C#/.NET only
@@ -525,4 +532,4 @@ Component-Server-Mappings:
influxdb-java: InfluxDB
Predis: Redis
PyMysql: Mysql
- spring-kafka-consumer: kafka-consumer
+ spring-kafka-consumer: kafka-consumer
\ No newline at end of file
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 83ee2010d..6078025e3 100755
--- a/oap-server/server-core/src/test/resources/component-libraries.yml
+++ b/oap-server/server-core/src/test/resources/component-libraries.yml
@@ -275,6 +275,15 @@ quartz-scheduler:
xxl-job:
id: 98
languages: Java
+spring-webflux-webclient:
+ id: 99
+ languages: Java
+thrift-server:
+ id: 100
+ languages: Java
+thrift-client:
+ id: 101
+ languages: Java
# .NET/.NET Core components
# [3000, 4000) for C#/.NET only
diff --git a/test/plugin/scenarios/thrift-scenario/config/expectedData.yaml b/test/plugin/scenarios/thrift-scenario/config/expectedData.yaml
new file mode 100644
index 000000000..2274d471a
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/config/expectedData.yaml
@@ -0,0 +1,96 @@
+# 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.
+segmentItems:
+ - serviceName: thrift-server-scenario
+ segmentSize: 2
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: org.apache.skywalking.apm.testcase.thrift.protocol.GreeterService$AsyncProcessor$echo
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: RPCFramework
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 100
+ isError: false
+ spanType: Entry
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - {key: args, value: 'echo_args(message:null)'}
+ refs:
+ - {parentEndpoint: org.apache.skywalking.apm.testcase.thrift.protocol.GreeterService$AsyncClient$echo_call,
+ networkAddress: 'localhost:9091', refType: CrossProcess, parentSpanId: 0,
+ parentTraceSegmentId: not null,
+ parentServiceInstance: not null, parentService: thrift-client-scenario,
+ traceId: not null }
+ - segmentId: not null
+ spans:
+ - operationName: org.apache.skywalking.apm.testcase.thrift.protocol.GreeterService$Processor$echo
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: RPCFramework
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 100
+ isError: false
+ spanType: Entry
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - {key: args, value: 'echo_args(message:null)'}
+ refs:
+ - {parentEndpoint: org.apache.skywalking.apm.testcase.thrift.protocol.GreeterService$Client.echo,
+ networkAddress: 'localhost:9090', refType: CrossProcess, parentSpanId: 0,
+ parentTraceSegmentId: not null,
+ parentServiceInstance: not null, parentService: thrift-client-scenario,
+ traceId: not null }
+ - serviceName: thrift-client-scenario
+ segmentSize: ge 2
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: org.apache.skywalking.apm.testcase.thrift.protocol.GreeterService$Client.echo
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: RPCFramework
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 101
+ isError: false
+ spanType: Exit
+ peer: localhost:9090
+ skipAnalysis: false
+ tags:
+ - {key: args, value: echo(message)}
+ - segmentId: not null
+ spans:
+ - operationName: org.apache.skywalking.apm.testcase.thrift.protocol.GreeterService$AsyncClient$echo_call
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: RPCFramework
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 101
+ isError: false
+ spanType: Exit
+ peer: 'localhost:9091'
+ skipAnalysis: false
\ No newline at end of file
diff --git a/test/plugin/scenarios/thrift-scenario/configuration.yml b/test/plugin/scenarios/thrift-scenario/configuration.yml
new file mode 100644
index 000000000..35f43be3f
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/configuration.yml
@@ -0,0 +1,22 @@
+# 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/thrift-scenario/case/thrift-scenario
+healthCheck: http://localhost:8080/thrift-scenario/case/healthCheck
+startScript: ./bin/startup.sh
+environment:
+dependencies:
diff --git a/test/plugin/scenarios/thrift-scenario/pom.xml b/test/plugin/scenarios/thrift-scenario/pom.xml
new file mode 100644
index 000000000..27fe4303b
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/pom.xml
@@ -0,0 +1,80 @@
+
+
+
+
+ org.apache.skywalking.apm.testcase
+ thrift-scenario
+ 1.0.0
+ pom
+
+ 4.0.0
+
+
+ UTF-8
+ 1.8
+ 0.12.0
+ 2.1.6.RELEASE
+ 1.18.10
+ ${test.framework.version}
+
+
+ skywalking-thrift-scenario
+
+
+ thrift-common
+ thrift-client
+ thrift-server
+ thrift-dist
+
+
+
+
+
+ org.apache.thrift
+ libthrift
+ ${thrift.version}
+
+
+
+
+
+
+ org.apache.thrift
+ libthrift
+ ${thrift.version}
+
+
+
+
+ thrift-scenario
+
+
+ maven-compiler-plugin
+
+ ${compiler.version}
+ ${compiler.version}
+ ${project.build.sourceEncoding}
+
+
+
+
+
+
diff --git a/test/plugin/scenarios/thrift-scenario/support-version.list b/test/plugin/scenarios/thrift-scenario/support-version.list
new file mode 100644
index 000000000..ba27aa49f
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/support-version.list
@@ -0,0 +1,19 @@
+# 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.
+
+0.12.0
+0.11.0
+0.10.0
\ No newline at end of file
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-client/pom.xml b/test/plugin/scenarios/thrift-scenario/thrift-client/pom.xml
new file mode 100644
index 000000000..56ae7c62c
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-client/pom.xml
@@ -0,0 +1,93 @@
+
+
+
+
+ org.apache.skywalking.apm.testcase
+ thrift-scenario
+ 1.0.0
+
+ 4.0.0
+
+ thrift-client
+
+
+
+ org.apache.skywalking.apm.testcase
+ thrift-common
+ ${version}
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${spring-boot-version}
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-log4j2
+ ${spring-boot-version}
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+ ${spring-boot-version}
+
+
+
+
+ thrift-client
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot-version}
+
+
+
+ repackage
+
+
+
+
+ org.apache.skywalking.apm.testcase.thrift.client.Application
+
+
+
+ maven-compiler-plugin
+
+ ${compiler.version}
+ ${compiler.version}
+ ${project.build.sourceEncoding}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/Application.java b/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/Application.java
new file mode 100644
index 000000000..31715707f
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/Application.java
@@ -0,0 +1,32 @@
+package org.apache.skywalking.apm.testcase.thrift.client;/*
+ * 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.
+ *
+ */
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ try {
+ SpringApplication.run(Application.class, args);
+ } catch (Exception e) {
+ // Never do this
+ }
+ }
+}
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/controller/CaseController.java b/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/controller/CaseController.java
new file mode 100644
index 000000000..a187e44dc
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/controller/CaseController.java
@@ -0,0 +1,94 @@
+/*
+ * 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.thrift.client.controller;
+
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.skywalking.apm.testcase.thrift.client.service.AsyncClient;
+import org.apache.skywalking.apm.testcase.thrift.client.service.IClient;
+import org.apache.skywalking.apm.testcase.thrift.client.service.SyncClient;
+import org.apache.thrift.TException;
+import org.apache.thrift.transport.TTransportException;
+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 Logger logger = LogManager.getLogger(CaseController.class);
+
+ private static final String SUCCESS = "Success";
+ private IClient async;
+ private IClient sync;
+
+ private IClient hasync;
+
+ private final AtomicInteger status = new AtomicInteger(0);
+ private final CountDownLatch initialized = new CountDownLatch(1);
+
+ @RequestMapping("/thrift-scenario")
+ @ResponseBody
+ public String testcase() throws InterruptedException {
+ final CountDownLatch latch = new CountDownLatch(3);
+
+ call(async, latch);
+ call(sync, latch);
+
+ latch.await();
+ return SUCCESS;
+ }
+
+ @RequestMapping("/healthCheck")
+ @ResponseBody
+ public String healthCheck() throws IOException, TTransportException {
+ if (status.compareAndSet(0, 1)) {
+ async = new AsyncClient(9091);
+ sync = new SyncClient(9090);
+ async.start();
+ sync.start();
+
+ initialized.countDown();
+ }
+ try {
+ initialized.await(2000, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new IOException("pending");
+ }
+ return SUCCESS;
+ }
+
+ private void call(IClient client, CountDownLatch latch) {
+ new Thread(() -> {
+ try {
+ client.echo("skywalking");
+ } catch (TException e) {
+ e.printStackTrace();
+ } finally {
+ latch.countDown();
+ }
+ }).start();
+ }
+
+}
\ No newline at end of file
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/service/AsyncClient.java b/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/service/AsyncClient.java
new file mode 100644
index 000000000..e7262e0e1
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/service/AsyncClient.java
@@ -0,0 +1,85 @@
+/*
+ * 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.thrift.client.service;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.skywalking.apm.testcase.thrift.protocol.GreeterService;
+import org.apache.thrift.TException;
+import org.apache.thrift.async.AsyncMethodCallback;
+import org.apache.thrift.async.TAsyncClientManager;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.transport.TNonblockingSocket;
+import org.apache.thrift.transport.TTransportException;
+
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class AsyncClient implements IClient {
+ private static final Logger logger = LogManager.getLogger(AsyncClient.class);
+
+ private final TNonblockingSocket transport;
+ private final GreeterService.AsyncClient client;
+
+ public AsyncClient(final int port) throws IOException {
+ this.transport = new TNonblockingSocket("localhost", port);
+ this.client = new GreeterService.AsyncClient(
+ TCompactProtocol::new,
+ new TAsyncClientManager(),
+ this.transport
+ );
+ }
+
+ @Override
+ public void start() throws TTransportException {
+
+ }
+
+ @Override
+ public String echo(final String message) throws TException {
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ AtomicReference resp = new AtomicReference<>();
+ client.echo(message, new AsyncMethodCallback() {
+ @Override
+ public void onComplete(final String response) {
+ resp.set(response);
+ latch.countDown();
+ }
+
+ @Override
+ public void onError(final Exception exception) {
+ latch.countDown();
+ logger.error("", exception);
+ }
+ });
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ logger.error("", e);
+ }
+ return resp.get();
+ }
+
+ @Override
+ public void close() {
+ transport.close();
+ }
+}
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/service/HttpClient.java b/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/service/HttpClient.java
new file mode 100644
index 000000000..936638f24
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/service/HttpClient.java
@@ -0,0 +1,51 @@
+/*
+ * 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.thrift.client.service;
+
+import org.apache.skywalking.apm.testcase.thrift.protocol.GreeterService;
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.transport.THttpClient;
+import org.apache.thrift.transport.TTransportException;
+
+public class HttpClient implements IClient {
+ private final THttpClient transport;
+ private final GreeterService.Client client;
+
+ public HttpClient() throws TTransportException {
+ transport = new THttpClient("http://localhost:9080/thrift");
+ client = new GreeterService.Client(new TCompactProtocol(transport));
+ }
+
+ @Override
+ public void start() throws TTransportException {
+ transport.open();
+ }
+
+ @Override
+ public void close() {
+ transport.close();
+ }
+
+
+ @Override
+ public String echo(String message) throws TException {
+ return client.echo(message);
+ }
+}
\ No newline at end of file
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/service/IClient.java b/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/service/IClient.java
new file mode 100644
index 000000000..fa983d7f6
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/service/IClient.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.thrift.client.service;
+
+import org.apache.skywalking.apm.testcase.thrift.protocol.GreeterService;
+import org.apache.thrift.transport.TTransportException;
+
+import java.io.IOException;
+
+public interface IClient extends GreeterService.Iface {
+ void start() throws TTransportException, IOException;
+
+ void close();
+}
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/service/SyncClient.java b/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/service/SyncClient.java
new file mode 100644
index 000000000..9ffff665a
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/java/org/apache/skywalking/apm/testcase/thrift/client/service/SyncClient.java
@@ -0,0 +1,51 @@
+/*
+ * 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.thrift.client.service;
+
+import org.apache.skywalking.apm.testcase.thrift.protocol.GreeterService;
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.transport.TSocket;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.transport.TTransportException;
+
+public class SyncClient implements IClient {
+ private final TTransport transport;
+ private final GreeterService.Client client;
+
+ public SyncClient(int port) throws TTransportException {
+ this.transport = new TSocket("localhost", port);
+ client = new GreeterService.Client(new TCompactProtocol(this.transport));
+ }
+
+ @Override
+ public void start() throws TTransportException {
+ this.transport.open();
+ }
+
+ @Override
+ public void close() {
+ transport.close();
+ }
+
+ @Override
+ public String echo(String message) throws TException {
+ return client.echo(message);
+ }
+}
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/resources/application.yaml b/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/resources/application.yaml
new file mode 100644
index 000000000..9b1211126
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/resources/application.yaml
@@ -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.
+#
+#
+server:
+ port: 8080
+ servlet:
+ context-path: /thrift-scenario
+logging:
+ config: classpath:log4j2.xml
\ No newline at end of file
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/resources/log4j2.xml b/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/resources/log4j2.xml
new file mode 100644
index 000000000..9849ed5a8
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-client/src/main/resources/log4j2.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-common/pom.xml b/test/plugin/scenarios/thrift-scenario/thrift-common/pom.xml
new file mode 100644
index 000000000..0771e2dcc
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-common/pom.xml
@@ -0,0 +1,106 @@
+
+
+
+
+ org.apache.skywalking.apm.testcase
+ thrift-scenario
+ 1.0.0
+
+ 4.0.0
+
+ thrift-common
+
+
+
+ javax.annotation
+ javax.annotation-api
+ 1.3.2
+
+
+ com.google.guava
+ guava
+ 29.0-jre
+
+
+
+
+
+
+ maven-compiler-plugin
+
+ ${compiler.version}
+ ${compiler.version}
+ ${project.build.sourceEncoding}
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+
+
+ add-source
+ generate-sources
+
+ add-source
+
+
+
+ ${project.basedir}/generated-sources
+
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.6.0
+
+
+ initialize
+
+ exec
+
+
+
+
+ docker
+
+ run
+ -v
+ ${project.basedir}/src/main/thrift:/data
+ -v
+ ${project.basedir}/generated-sources:/out
+ thrift:${thrift.version}
+ thrift
+ -o
+ /out
+ --gen
+ java
+ /data/greeter.thrift
+
+
+
+
+
+
+
+
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-common/src/main/thrift/greeter.thrift b/test/plugin/scenarios/thrift-scenario/thrift-common/src/main/thrift/greeter.thrift
new file mode 100644
index 000000000..003763c76
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-common/src/main/thrift/greeter.thrift
@@ -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.
+ *
+ */
+
+namespace java org.apache.skywalking.apm.testcase.thrift.protocol
+
+service GreeterService
+{
+ string echo(1:string message)
+}
\ No newline at end of file
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-dist/bin/startup.sh b/test/plugin/scenarios/thrift-scenario/thrift-dist/bin/startup.sh
new file mode 100644
index 000000000..fca20e1e8
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-dist/bin/startup.sh
@@ -0,0 +1,23 @@
+#!/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} "-Dskywalking.agent.service_name=thrift-server-scenario" ${home}/../libs/thrift-server.jar &
+
+java -jar ${agent_opts} "-Dskywalking.agent.service_name=thrift-client-scenario" ${home}/../libs/thrift-client.jar &
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-dist/pom.xml b/test/plugin/scenarios/thrift-scenario/thrift-dist/pom.xml
new file mode 100644
index 000000000..68f5e79bb
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-dist/pom.xml
@@ -0,0 +1,54 @@
+
+
+
+
+ org.apache.skywalking.apm.testcase
+ thrift-scenario
+ 1.0.0
+
+ 4.0.0
+
+ thrift-dist
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ assemble
+ package
+
+ single
+
+
+
+ src/main/assembly/assembly.xml
+
+ ../target/
+
+
+
+
+
+
+
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-dist/src/main/assembly/assembly.xml b/test/plugin/scenarios/thrift-scenario/thrift-dist/src/main/assembly/assembly.xml
new file mode 100644
index 000000000..8c15fc724
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-dist/src/main/assembly/assembly.xml
@@ -0,0 +1,46 @@
+
+
+
+
+ zip
+
+
+
+
+ ./bin
+ 0775
+
+
+
+
+
+ ${project.basedir}/../thrift-client/target/thrift-client.jar
+ ./libs
+ 0775
+
+
+ ${project.basedir}/../thrift-server/target/thrift-server.jar
+ ./libs
+ 0775
+
+
+
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-server/pom.xml b/test/plugin/scenarios/thrift-scenario/thrift-server/pom.xml
new file mode 100644
index 000000000..13596ea32
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-server/pom.xml
@@ -0,0 +1,87 @@
+
+
+
+
+ org.apache.skywalking.apm.testcase
+ thrift-scenario
+ 1.0.0
+
+ 4.0.0
+
+ thrift-server
+
+
+
+ org.apache.skywalking.apm.testcase
+ thrift-common
+ ${version}
+
+
+ org.eclipse.jetty
+ jetty-server
+ 9.4.31.v20200723
+
+
+ org.eclipse.jetty
+ jetty-servlet
+ 9.4.31.v20200723
+
+
+
+
+
+ thrift-server
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.1.0
+
+
+ package
+
+ shade
+
+
+
+
+ *:*
+
+ META-INF/*.SF
+ META-INF/*.DSA
+ META-INF/*.RSA
+
+
+
+
+
+ org.apache.skywalking.apm.testcase.thrift.server.Application
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/java/org/apache/skywalking/apm/testcase/thrift/server/Application.java b/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/java/org/apache/skywalking/apm/testcase/thrift/server/Application.java
new file mode 100644
index 000000000..da64aab1d
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/java/org/apache/skywalking/apm/testcase/thrift/server/Application.java
@@ -0,0 +1,29 @@
+/*
+ * 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.thrift.server;
+
+import org.apache.skywalking.apm.testcase.thrift.server.service.AsyncServer;
+import org.apache.skywalking.apm.testcase.thrift.server.service.SyncServer;
+
+public class Application {
+ public static void main(String[] args) throws Exception {
+ new AsyncServer().start();
+ new SyncServer().start();
+ }
+}
\ No newline at end of file
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/java/org/apache/skywalking/apm/testcase/thrift/server/service/AsyncServer.java b/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/java/org/apache/skywalking/apm/testcase/thrift/server/service/AsyncServer.java
new file mode 100644
index 000000000..ff5c5ebd2
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/java/org/apache/skywalking/apm/testcase/thrift/server/service/AsyncServer.java
@@ -0,0 +1,43 @@
+/*
+ * 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.thrift.server.service;
+
+import org.apache.skywalking.apm.testcase.thrift.protocol.GreeterService;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.server.TNonblockingServer;
+import org.apache.thrift.transport.TNonblockingServerSocket;
+import org.apache.thrift.transport.TTransportException;
+
+public class AsyncServer implements IServer {
+ TNonblockingServer server;
+
+ @Override
+ public void start() throws TTransportException {
+ TNonblockingServerSocket serverSocket = new TNonblockingServerSocket(9091);
+ server = new TNonblockingServer(new TNonblockingServer.Args(serverSocket)
+ .processor(new GreeterService.AsyncProcessor<>(new AsyncHandler()))
+ .protocolFactory(TCompactProtocol::new));
+ new Thread(() -> server.serve()).start();
+ }
+
+ @Override
+ public void close() {
+ server.stop();
+ }
+}
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/java/org/apache/skywalking/apm/testcase/thrift/server/service/HttpServer.java b/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/java/org/apache/skywalking/apm/testcase/thrift/server/service/HttpServer.java
new file mode 100644
index 000000000..e3c8b839c
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/java/org/apache/skywalking/apm/testcase/thrift/server/service/HttpServer.java
@@ -0,0 +1,54 @@
+/*
+ * 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.thrift.server.service;
+
+import org.apache.skywalking.apm.testcase.thrift.protocol.GreeterService;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.server.TServlet;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+
+import java.net.InetSocketAddress;
+
+public class HttpServer implements IServer {
+
+ public static void main(String[] args) throws Exception {
+ new HttpServer().start();
+ }
+
+ @Override
+ public void start() throws Exception {
+ Server jettyServer = new Server(new InetSocketAddress("0.0.0.0", Integer.valueOf(9080)));
+
+ ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
+ servletContextHandler.setContextPath("/");
+ servletContextHandler.addServlet(new ServletHolder(
+ new TServlet(new GreeterService.Processor<>(new Handler()), TCompactProtocol::new)),
+ "/thrift"
+ );
+ jettyServer.setHandler(servletContextHandler);
+ jettyServer.start();
+ }
+
+ @Override
+ public void close() {
+
+ }
+}
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/java/org/apache/skywalking/apm/testcase/thrift/server/service/IServer.java b/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/java/org/apache/skywalking/apm/testcase/thrift/server/service/IServer.java
new file mode 100644
index 000000000..10fab29a5
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/java/org/apache/skywalking/apm/testcase/thrift/server/service/IServer.java
@@ -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 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.thrift.server.service;
+
+import org.apache.skywalking.apm.testcase.thrift.protocol.GreeterService;
+import org.apache.thrift.TException;
+import org.apache.thrift.async.AsyncMethodCallback;
+
+public interface IServer {
+ void start() throws Exception;
+
+ void close() throws Exception;
+
+
+ final class AsyncHandler implements GreeterService.AsyncIface {
+
+ @Override
+ public void echo(final String message, final AsyncMethodCallback resultHandler) throws TException {
+ resultHandler.onComplete("echo async: " + message);
+ }
+ }
+
+ final class Handler implements GreeterService.Iface {
+
+ @Override
+ public String echo(final String message) throws TException {
+ return "echo sync: " + message;
+ }
+ }
+}
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/java/org/apache/skywalking/apm/testcase/thrift/server/service/SyncServer.java b/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/java/org/apache/skywalking/apm/testcase/thrift/server/service/SyncServer.java
new file mode 100644
index 000000000..272288e93
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/java/org/apache/skywalking/apm/testcase/thrift/server/service/SyncServer.java
@@ -0,0 +1,45 @@
+/*
+ * 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.thrift.server.service;
+
+import org.apache.skywalking.apm.testcase.thrift.protocol.GreeterService;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.server.TServer;
+import org.apache.thrift.server.TSimpleServer;
+import org.apache.thrift.transport.TServerSocket;
+import org.apache.thrift.transport.TServerTransport;
+import org.apache.thrift.transport.TTransportException;
+
+public class SyncServer implements IServer {
+ TSimpleServer server;
+
+ @Override
+ public void start() throws TTransportException {
+ TServerTransport transport = new TServerSocket(9090);
+ server = new TSimpleServer(new TServer.Args(transport)
+ .processor(new GreeterService.Processor<>(new Handler()))
+ .protocolFactory(TCompactProtocol::new));
+ new Thread(() -> server.serve()).start();
+ }
+
+ @Override
+ public void close() {
+ server.stop();
+ }
+}
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/resources/application.yaml b/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/resources/application.yaml
new file mode 100644
index 000000000..9b1211126
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/resources/application.yaml
@@ -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.
+#
+#
+server:
+ port: 8080
+ servlet:
+ context-path: /thrift-scenario
+logging:
+ config: classpath:log4j2.xml
\ No newline at end of file
diff --git a/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/resources/log4j2.xml b/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/resources/log4j2.xml
new file mode 100644
index 000000000..9849ed5a8
--- /dev/null
+++ b/test/plugin/scenarios/thrift-scenario/thrift-server/src/main/resources/log4j2.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file