You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2019/12/16 16:12:22 UTC
[skywalking] branch master updated: [Feature] Add Java agent plugin
for Jdk Threading classes (#4067)
This is an automated email from the ASF dual-hosted git repository.
wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git
The following commit(s) were added to refs/heads/master by this push:
new 3f48790 [Feature] Add Java agent plugin for Jdk Threading classes (#4067)
3f48790 is described below
commit 3f48790c36b6887fe849a1fc9a419debbf5c6782
Author: kezhenxu94 <ke...@apache.org>
AuthorDate: Tue Dec 17 00:12:14 2019 +0800
[Feature] Add Java agent plugin for Jdk Threading classes (#4067)
* Add Java agent plugin for Jdk Threading
* Fix expected data according to changes in master
* Update agent.config
* Fix failed plugin test
---
.github/workflows/plugins-test.yaml | 4 +-
.../network/trace/component/ComponentsDefine.java | 2 +
.../skywalking/apm/agent/core/conf/Config.java | 11 ++
.../agent/core/plugin/match/HierarchyMatch.java | 3 +-
.../apm/agent/core/plugin/match/PrefixMatch.java | 70 ++++++++++++
.../core/plugin/match/logical/LogicalAndMatch.java | 68 ++++++++++++
.../match/logical/LogicalMatchOperation.java | 36 ++++++
.../core/plugin/match/logical/LogicalOrMatch.java | 68 ++++++++++++
.../bootstrap-plugins/jdk-threading-plugin/pom.xml | 46 ++++++++
.../apm/plugin/jdk/threading/ThreadingConfig.java | 64 +++++++++++
.../threading/ThreadingConstructorInterceptor.java | 37 +++++++
.../jdk/threading/ThreadingMethodInterceptor.java | 88 +++++++++++++++
.../threading/define/CallableInstrumentation.java | 106 ++++++++++++++++++
.../threading/define/RunnableInstrumentation.java | 106 ++++++++++++++++++
.../src/main/resources/skywalking-plugin.def | 18 +++
apm-sniffer/bootstrap-plugins/pom.xml | 1 +
apm-sniffer/config/agent.config | 8 +-
docs/en/setup/service-agent/java-agent/README.md | 2 +
.../src/main/resources/component-libraries.yml | 3 +
.../jdk-threading-scenario/bin/startup.sh | 21 ++++
.../config/expectedData.yaml | 121 +++++++++++++++++++++
.../jdk-threading-scenario/configuration.yml | 23 ++++
.../scenarios/jdk-threading-scenario/pom.xml | 88 +++++++++++++++
.../src/main/assembly/assembly.xml | 41 +++++++
.../apm/testcase/jdk/threading/Application.java | 84 ++++++++++++++
.../src/main/resources/application.yaml | 19 ++++
.../jdk-threading-scenario/support-version.list | 17 +++
27 files changed, 1149 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/plugins-test.yaml b/.github/workflows/plugins-test.yaml
index 15b9844..9cb28d5 100644
--- a/.github/workflows/plugins-test.yaml
+++ b/.github/workflows/plugins-test.yaml
@@ -446,7 +446,7 @@ jobs:
- name: Run elasticsearch-6.x-scenario 6.7.1-6.8.4 (7)
run: bash test/plugin/run.sh elasticsearch-6.x-scenario
- Oracle_Kafka_JdkHttp:
+ Oracle_Kafka_JdkHttp_JdkThreading:
runs-on: ubuntu-18.04
timeout-minutes: 90
strategy:
@@ -477,6 +477,8 @@ jobs:
run: bash test/plugin/run.sh kafka-scenario
- name: Run jdk http (1)
run: bash test/plugin/run.sh jdk-http-scenario
+ - name: Run jdk threading (1)
+ run: bash test/plugin/run.sh jdk-threading-scenario
MySQL:
runs-on: ubuntu-18.04
diff --git a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
index 8ac1799..1ec2dec 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
@@ -149,4 +149,6 @@ public class ComponentsDefine {
public static final OfficialComponent SPRING_TX = new OfficialComponent(78, "spring-tx");
public static final OfficialComponent ARMERIA = new OfficialComponent(79, "Armeria");
+
+ public static final OfficialComponent JDK_THREADING = new OfficialComponent(80, "JdkThreading");
}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java
index 2bc276c..0b0842c 100755
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java
@@ -342,5 +342,16 @@ public class Config {
*/
public static boolean SIMPLIFY_TRANSACTION_DEFINITION_NAME = false;
}
+
+ public static class JdkThreading {
+
+ /**
+ * Threading classes ({@link java.lang.Runnable} and {@link java.util.concurrent.Callable}
+ * and their subclasses, including anonymous inner classes)
+ * whose name matches any one of the {@code THREADING_CLASS_PREFIXES} (splitted by ,)
+ * will be instrumented
+ */
+ public static String THREADING_CLASS_PREFIXES = "";
+ }
}
}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/HierarchyMatch.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/HierarchyMatch.java
index f134d38..314c4b3 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/HierarchyMatch.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/HierarchyMatch.java
@@ -22,6 +22,7 @@ package org.apache.skywalking.apm.agent.core.plugin.match;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.description.type.TypeList;
import net.bytebuddy.matcher.ElementMatcher;
@@ -101,7 +102,7 @@ public class HierarchyMatch implements IndirectMatch {
}
- public static ClassMatch byHierarchyMatch(String[] parentTypes) {
+ public static IndirectMatch byHierarchyMatch(String... parentTypes) {
return new HierarchyMatch(parentTypes);
}
}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/PrefixMatch.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/PrefixMatch.java
new file mode 100644
index 0000000..d2cb78f
--- /dev/null
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/PrefixMatch.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+package org.apache.skywalking.apm.agent.core.plugin.match;
+
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+
+/**
+ * Match classes by any one of the given {@link #prefixes}
+ *
+ * @author kezhenxu94
+ */
+@SuppressWarnings("rawtypes")
+public class PrefixMatch implements IndirectMatch {
+ private String[] prefixes;
+
+ private PrefixMatch(String... prefixes) {
+ if (prefixes == null || prefixes.length == 0) {
+ throw new IllegalArgumentException("prefixes argument is null or empty");
+ }
+ this.prefixes = prefixes;
+ }
+
+ @Override
+ public ElementMatcher.Junction buildJunction() {
+ ElementMatcher.Junction junction = null;
+
+ for (String prefix : prefixes) {
+ if (junction == null) {
+ junction = ElementMatchers.nameStartsWith(prefix);
+ } else {
+ junction = junction.and(ElementMatchers.nameStartsWith(prefix));
+ }
+ }
+
+ return junction;
+ }
+
+ @Override
+ public boolean isMatch(TypeDescription typeDescription) {
+ for (final String prefix : prefixes) {
+ if (typeDescription.getName().startsWith(prefix)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static PrefixMatch nameStartsWith(final String... prefixes) {
+ return new PrefixMatch(prefixes);
+ }
+}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalAndMatch.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalAndMatch.java
new file mode 100644
index 0000000..dc523ae
--- /dev/null
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalAndMatch.java
@@ -0,0 +1,68 @@
+/*
+ * 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.agent.core.plugin.match.logical;
+
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.match.IndirectMatch;
+
+/**
+ * Match classes by multiple criteria with AND conjunction
+ *
+ * @author kezhenxu94
+ */
+public class LogicalAndMatch implements IndirectMatch {
+ private final IndirectMatch[] indirectMatches;
+
+ /**
+ * Don't instantiate this class directly, use {@link LogicalMatchOperation} instead
+ *
+ * @param indirectMatches the matching criteria to conjunct with AND
+ */
+ LogicalAndMatch(final IndirectMatch... indirectMatches) {
+ this.indirectMatches = indirectMatches;
+ }
+
+ @Override
+ public ElementMatcher.Junction buildJunction() {
+ ElementMatcher.Junction junction = null;
+
+ for (final IndirectMatch indirectMatch : indirectMatches) {
+ if (junction == null) {
+ junction = indirectMatch.buildJunction();
+ } else {
+ junction = junction.and(indirectMatch.buildJunction());
+ }
+ }
+
+ return junction;
+ }
+
+ @Override
+ public boolean isMatch(final TypeDescription typeDescription) {
+ for (final IndirectMatch indirectMatch : indirectMatches) {
+ if (!indirectMatch.isMatch(typeDescription)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalMatchOperation.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalMatchOperation.java
new file mode 100644
index 0000000..0fa5b83
--- /dev/null
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalMatchOperation.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.agent.core.plugin.match.logical;
+
+import org.apache.skywalking.apm.agent.core.plugin.match.IndirectMatch;
+
+/**
+ * Util class to help to construct logical operations on {@link org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch}s
+ *
+ * @author kezhenxu94
+ */
+public class LogicalMatchOperation {
+ public static IndirectMatch and(final IndirectMatch... matches) {
+ return new LogicalAndMatch(matches);
+ }
+
+ public static IndirectMatch or(final IndirectMatch... matches) {
+ return new LogicalOrMatch(matches);
+ }
+}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalOrMatch.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalOrMatch.java
new file mode 100644
index 0000000..1a10a4f
--- /dev/null
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalOrMatch.java
@@ -0,0 +1,68 @@
+/*
+ * 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.agent.core.plugin.match.logical;
+
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.match.IndirectMatch;
+
+/**
+ * Match classes by multiple criteria with OR conjunction
+ *
+ * @author kezhenxu94
+ */
+public class LogicalOrMatch implements IndirectMatch {
+ private final IndirectMatch[] indirectMatches;
+
+ /**
+ * Don't instantiate this class directly, use {@link LogicalMatchOperation} instead
+ *
+ * @param indirectMatches the matching criteria to conjunct with OR
+ */
+ LogicalOrMatch(final IndirectMatch... indirectMatches) {
+ this.indirectMatches = indirectMatches;
+ }
+
+ @Override
+ public ElementMatcher.Junction buildJunction() {
+ ElementMatcher.Junction junction = null;
+
+ for (final IndirectMatch indirectMatch : indirectMatches) {
+ if (junction == null) {
+ junction = indirectMatch.buildJunction();
+ } else {
+ junction = junction.or(indirectMatch.buildJunction());
+ }
+ }
+
+ return junction;
+ }
+
+ @Override
+ public boolean isMatch(final TypeDescription typeDescription) {
+ for (final IndirectMatch indirectMatch : indirectMatches) {
+ if (indirectMatch.isMatch(typeDescription)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/pom.xml b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/pom.xml
new file mode 100755
index 0000000..b9d271a
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/pom.xml
@@ -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.
+ ~
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.skywalking</groupId>
+ <artifactId>bootstrap-plugins</artifactId>
+ <version>6.6.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>apm-jdk-threading-plugin</artifactId>
+ <packaging>jar</packaging>
+
+ <name>apm-jdk-threading-plugin</name>
+ <description>SkyWalking Java Agent Plugin for JDK threading classes, (Runnable, Callable)</description>
+ <url>https://github.com/apache/skywalking</url>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-deploy-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingConfig.java b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingConfig.java
new file mode 100644
index 0000000..97145a6
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingConfig.java
@@ -0,0 +1,64 @@
+/*
+ * 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.jdk.threading;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.skywalking.apm.agent.core.conf.Config;
+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.match.IndirectMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.logical.LogicalMatchOperation;
+import org.apache.skywalking.apm.agent.core.plugin.match.PrefixMatch;
+
+import static org.apache.skywalking.apm.agent.core.plugin.match.PrefixMatch.nameStartsWith;
+
+/**
+ * @author kezhenxu94
+ */
+public class ThreadingConfig {
+ private static final ILog LOGGER = LogManager.getLogger(ThreadingConfig.class);
+
+ public static IndirectMatch prefixesMatchesForJdkThreading() {
+ final String jointPrefixes = Config.Plugin.JdkThreading.THREADING_CLASS_PREFIXES;
+
+ if (jointPrefixes == null || jointPrefixes.trim().isEmpty()) {
+ return null;
+ }
+
+ final String[] prefixes = jointPrefixes.split(",");
+
+ final List<PrefixMatch> prefixMatches = new ArrayList<PrefixMatch>();
+
+ for (final String prefix : prefixes) {
+ if (prefix.startsWith("java.") || prefix.startsWith("javax.")) {
+ LOGGER.warn("prefix {} is ignored", prefix);
+ continue;
+ }
+ prefixMatches.add(nameStartsWith(prefix));
+ }
+
+ if (prefixMatches.size() == 0) {
+ return null;
+ }
+
+ return LogicalMatchOperation.or(prefixMatches.toArray(new PrefixMatch[0]));
+ }
+}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingConstructorInterceptor.java b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingConstructorInterceptor.java
new file mode 100644
index 0000000..3ca000e
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingConstructorInterceptor.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.jdk.threading;
+
+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;
+
+/**
+ * @author kezhenxu94
+ */
+public class ThreadingConstructorInterceptor implements InstanceConstructorInterceptor {
+
+ @Override
+ public void onConstruct(final EnhancedInstance objInst, final Object[] allArguments) {
+ if (ContextManager.isActive()) {
+ objInst.setSkyWalkingDynamicField(ContextManager.capture());
+ }
+ }
+
+}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingMethodInterceptor.java b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingMethodInterceptor.java
new file mode 100644
index 0000000..c1607da
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingMethodInterceptor.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdk.threading;
+
+import java.lang.reflect.Method;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+
+/**
+ * @author kezhenxu94
+ */
+public class ThreadingMethodInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(
+ final EnhancedInstance objInst,
+ final Method method,
+ final Object[] allArguments,
+ final Class<?>[] argumentsTypes,
+ final MethodInterceptResult result) {
+
+ AbstractSpan span = ContextManager.createLocalSpan(generateOperationName(objInst, method));
+ span.setComponent(ComponentsDefine.JDK_THREADING);
+
+ final Object storedField = objInst.getSkyWalkingDynamicField();
+ if (storedField != null) {
+ final ContextSnapshot contextSnapshot = (ContextSnapshot) storedField;
+ ContextManager.continued(contextSnapshot);
+ }
+
+ }
+
+ @Override
+ public Object afterMethod(
+ final EnhancedInstance objInst,
+ final Method method,
+ final Object[] allArguments,
+ final Class<?>[] argumentsTypes,
+ final Object ret) {
+
+ final Object storedField = objInst.getSkyWalkingDynamicField();
+ if (storedField != null) {
+ ContextManager.stopSpan();
+ }
+
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(
+ final EnhancedInstance objInst,
+ final Method method,
+ final Object[] allArguments,
+ final Class<?>[] argumentsTypes,
+ final Throwable t) {
+
+ if (ContextManager.isActive()) {
+ ContextManager.activeSpan().errorOccurred().log(t);
+ }
+ }
+
+ private String generateOperationName(final EnhancedInstance objInst, final Method method) {
+ return "Threading/" + objInst.getClass().getName() + "/" + method.getName();
+ }
+
+}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/define/CallableInstrumentation.java b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/define/CallableInstrumentation.java
new file mode 100644
index 0000000..a32560e
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/define/CallableInstrumentation.java
@@ -0,0 +1,106 @@
+/*
+ * 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.jdk.threading.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.IndirectMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.logical.LogicalMatchOperation;
+import org.apache.skywalking.apm.plugin.jdk.threading.ThreadingConfig;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+import static org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch.byHierarchyMatch;
+
+/**
+ * @author kezhenxu94
+ */
+public class CallableInstrumentation extends ClassEnhancePluginDefine {
+ private static final String CALLABLE_CLASS = "java.util.concurrent.Callable";
+ private static final String CALLABLE_CLASS_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdk.threading.ThreadingConstructorInterceptor";
+
+ private static final String CALLABLE_CALL_METHOD = "call";
+ private static final String CALLABLE_CALL_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdk.threading.ThreadingMethodInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ final IndirectMatch prefixMatches = ThreadingConfig.prefixesMatchesForJdkThreading();
+
+ if (prefixMatches == null) {
+ return null;
+ }
+
+ return LogicalMatchOperation.and(prefixMatches, byHierarchyMatch(CALLABLE_CLASS));
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[]{
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher<MethodDescription> getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return CALLABLE_CLASS_INTERCEPTOR;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher<MethodDescription> getMethodsMatcher() {
+ return named(CALLABLE_CALL_METHOD).and(takesArguments(0));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return CALLABLE_CALL_METHOD_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
+ return new StaticMethodsInterceptPoint[0];
+ }
+
+ @Override
+ public boolean isBootstrapInstrumentation() {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/define/RunnableInstrumentation.java b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/define/RunnableInstrumentation.java
new file mode 100644
index 0000000..c77e256
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/define/RunnableInstrumentation.java
@@ -0,0 +1,106 @@
+/*
+ * 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.jdk.threading.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.IndirectMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.logical.LogicalMatchOperation;
+import org.apache.skywalking.apm.plugin.jdk.threading.ThreadingConfig;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+import static org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch.byHierarchyMatch;
+
+/**
+ * @author kezhenxu94
+ */
+public class RunnableInstrumentation extends ClassEnhancePluginDefine {
+ private static final String RUNNABLE_CLASS = "java.lang.Runnable";
+ private static final String RUNNABLE_CLASS_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdk.threading.ThreadingConstructorInterceptor";
+
+ private static final String RUNNABLE_RUN_METHOD = "run";
+ private static final String RUNNABLE_RUN_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdk.threading.ThreadingMethodInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ final IndirectMatch prefixMatches = ThreadingConfig.prefixesMatchesForJdkThreading();
+
+ if (prefixMatches == null) {
+ return null;
+ }
+
+ return LogicalMatchOperation.and(prefixMatches, byHierarchyMatch(RUNNABLE_CLASS));
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[]{
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher<MethodDescription> getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return RUNNABLE_CLASS_INTERCEPTOR;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher<MethodDescription> getMethodsMatcher() {
+ return named(RUNNABLE_RUN_METHOD).and(takesArguments(0));
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return RUNNABLE_RUN_METHOD_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
+ return new StaticMethodsInterceptPoint[0];
+ }
+
+ @Override
+ public boolean isBootstrapInstrumentation() {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000..06aaee3
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+jdk-threading-plugin=org.apache.skywalking.apm.plugin.jdk.threading.define.RunnableInstrumentation
+jdk-threading-plugin=org.apache.skywalking.apm.plugin.jdk.threading.define.CallableInstrumentation
\ No newline at end of file
diff --git a/apm-sniffer/bootstrap-plugins/pom.xml b/apm-sniffer/bootstrap-plugins/pom.xml
index b421ee1..eef4583 100644
--- a/apm-sniffer/bootstrap-plugins/pom.xml
+++ b/apm-sniffer/bootstrap-plugins/pom.xml
@@ -42,6 +42,7 @@
<modules>
<module>jdk-http-plugin</module>
+ <module>jdk-threading-plugin</module>
</modules>
<dependencies>
diff --git a/apm-sniffer/config/agent.config b/apm-sniffer/config/agent.config
index 6e03ff2..dfa6aee 100644
--- a/apm-sniffer/config/agent.config
+++ b/apm-sniffer/config/agent.config
@@ -28,14 +28,14 @@ agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
# agent.authentication = ${SW_AGENT_AUTHENTICATION:xxxx}
# The max amount of spans in a single segment.
-# Through this config item, skywalking keep your application memory cost estimated.
+# Through this config item, SkyWalking keep your application memory cost estimated.
# agent.span_limit_per_segment=${SW_AGENT_SPAN_LIMIT:300}
# Ignore the segments if their operation names end with these suffix.
# agent.ignore_suffix=${SW_AGENT_IGNORE_SUFFIX:.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg}
-# If true, skywalking agent will save all instrumented classes files in `/debugging` folder.
-# Skywalking team may ask for these files in order to resolve compatible problem.
+# If true, SkyWalking agent will save all instrumented classes files in `/debugging` folder.
+# SkyWalking team may ask for these files in order to resolve compatible problem.
# agent.is_open_debugging_class = ${SW_AGENT_OPEN_DEBUG:true}
# The operationName max length
@@ -61,4 +61,4 @@ logging.level=${SW_LOGGING_LEVEL:DEBUG}
# logging.max_history_files=${SW_LOGGING_MAX_HISTORY_FILES:-1}
# mysql plugin configuration
-# plugin.mysql.trace_sql_parameters=${SW_MYSQL_TRACE_SQL_PARAMETERS:false}
\ No newline at end of file
+# plugin.mysql.trace_sql_parameters=${SW_MYSQL_TRACE_SQL_PARAMETERS:false}
diff --git a/docs/en/setup/service-agent/java-agent/README.md b/docs/en/setup/service-agent/java-agent/README.md
index 787d90e..c316651 100755
--- a/docs/en/setup/service-agent/java-agent/README.md
+++ b/docs/en/setup/service-agent/java-agent/README.md
@@ -117,6 +117,7 @@ property key | Description | Default |
`plugin.light4j.trace_handler_chain`|If true, trace all middleware/business handlers that are part of the Light4J handler chain for a request.|false|
`plugin.opgroup.*`|Support operation name customize group rules in different plugins. Read [Group rule supported plugins](op_name_group_rule.md)|Not set|
`plugin.springtransaction.simplify_transaction_definition_name`|If true, the transaction definition name will be simplified.|false|
+`plugin.jdkthreading.threading_class_prefixes` | Threading classes (`java.lang.Runnable` and `java.util.concurrent.Callable`) and their subclasses, including anonymous inner classes whose name match any one of the `THREADING_CLASS_PREFIXES` (splitted by `,`) will be instrumented, make sure to only specify as narrow prefixes as what you're expecting to instrument, (`java.` and `javax.` will be ignored due to safety issues) | Not set |
## Optional Plugins
Java agent plugins are all pluggable. Optional plugins could be provided in `optional-plugins` folder under agent or 3rd party repositories.
@@ -140,6 +141,7 @@ For using these plugins, you need to put the target plugin jar file into `/plugi
Now, we have the following known bootstrap plugins.
* Plugin of JDK HttpURLConnection. Agent is compatible with JDK 1.6+
+* Plugin of JDK Callable and Runnable. Agent is compatible with JDK 1.6+
## Advanced Features
* Set the settings through system properties for config file override. Read [setting override](Setting-override.md).
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 90e1d65..bac1b0c 100755
--- a/oap-server/server-bootstrap/src/main/resources/component-libraries.yml
+++ b/oap-server/server-bootstrap/src/main/resources/component-libraries.yml
@@ -266,6 +266,9 @@ spring-tx:
Armeria:
id: 79
languages: Java
+JdkThreading:
+ id: 80
+ languages: Java
# .NET/.NET Core components
# [3000, 4000) for C#/.NET only
diff --git a/test/plugin/scenarios/jdk-threading-scenario/bin/startup.sh b/test/plugin/scenarios/jdk-threading-scenario/bin/startup.sh
new file mode 100644
index 0000000..98bfae7
--- /dev/null
+++ b/test/plugin/scenarios/jdk-threading-scenario/bin/startup.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+home="$(cd "$(dirname $0)"; pwd)"
+
+java -Dskywalking.plugin.jdkthreading.threading_class_prefixes=test.org.apache.skywalking. -jar ${agent_opts} ${home}/../libs/jdk-threading-scenario.jar &
\ No newline at end of file
diff --git a/test/plugin/scenarios/jdk-threading-scenario/config/expectedData.yaml b/test/plugin/scenarios/jdk-threading-scenario/config/expectedData.yaml
new file mode 100644
index 0000000..c4c492d
--- /dev/null
+++ b/test/plugin/scenarios/jdk-threading-scenario/config/expectedData.yaml
@@ -0,0 +1,121 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+registryItems:
+ applications:
+ - {jdk-threading-scenario: 2}
+ instances:
+ - {jdk-threading-scenario: 1}
+ operationNames:
+ - jdk-threading-scenario: ['/greet/{username}']
+ heartbeat: []
+
+segmentItems:
+ - applicationCode: jdk-threading-scenario
+ segmentSize: ge 4
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: /greet/{username}
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 14
+ componentName: ''
+ isError: false
+ spanType: Entry
+ peer: ''
+ peerId: 0
+ tags:
+ - {key: url, value: 'http://localhost:8080/greet/skywalking'}
+ - {key: http.method, value: GET}
+
+ - segmentId: not null
+ spans:
+ - operationName: /apache/skywalking
+ operationId: 0
+ parentSpanId: 0
+ spanId: 1
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 13
+ componentName: ''
+ isError: false
+ spanType: Exit
+ peer: github.com:443
+ peerId: 0
+ tags:
+ - {key: url, value: 'https://github.com:-1/apache/skywalking'}
+ - {key: http.method, value: GET}
+ - operationName: Threading/test.org.apache.skywalking.apm.testcase.jdk.threading.Application$TestController$1/run
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Unknown
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 80
+ componentName: ''
+ isError: false
+ spanType: Local
+ peer: ''
+ peerId: 0
+ refs:
+ - {parentEndpointId: 0, parentEndpoint: '/greet/{username}', networkAddressId: 0,
+ entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, parentTraceSegmentId: not null,
+ parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: '/greet/{username}',
+ entryServiceInstanceId: 1}
+
+ - segmentId: not null
+ spans:
+ - operationName: /apache/skywalking
+ operationId: 0
+ parentSpanId: 0
+ spanId: 1
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 13
+ componentName: ''
+ isError: false
+ spanType: Exit
+ peer: github.com:443
+ peerId: 0
+ tags:
+ - {key: url, value: 'https://github.com:-1/apache/skywalking'}
+ - {key: http.method, value: GET}
+ - operationName: Threading/test.org.apache.skywalking.apm.testcase.jdk.threading.Application$TestController$2/call
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Unknown
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 80
+ componentName: ''
+ isError: false
+ spanType: Local
+ peer: ''
+ peerId: 0
+ refs:
+ - {parentEndpointId: 0, parentEndpoint: '/greet/{username}', networkAddressId: 0,
+ entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, parentTraceSegmentId: not null,
+ parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: '/greet/{username}',
+ entryServiceInstanceId: 1}
\ No newline at end of file
diff --git a/test/plugin/scenarios/jdk-threading-scenario/configuration.yml b/test/plugin/scenarios/jdk-threading-scenario/configuration.yml
new file mode 100644
index 0000000..b129cc2
--- /dev/null
+++ b/test/plugin/scenarios/jdk-threading-scenario/configuration.yml
@@ -0,0 +1,23 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+type: jvm
+entryService: http://localhost:8080/greet/skywalking
+healthCheck: http://localhost:8080/healthCheck
+runningMode: with_bootstrap
+withPlugins: apm-jdk-threading-plugin-*.jar
+startScript: ./bin/startup.sh
+framework: jdk-threading-scenario
diff --git a/test/plugin/scenarios/jdk-threading-scenario/pom.xml b/test/plugin/scenarios/jdk-threading-scenario/pom.xml
new file mode 100644
index 0000000..42b68ac
--- /dev/null
+++ b/test/plugin/scenarios/jdk-threading-scenario/pom.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.skywalking</groupId>
+ <artifactId>jdk-threading-scenario</artifactId>
+ <version>5.0.0</version>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <compiler.version>1.6</compiler.version>
+ <spring.boot.version>2.1.6.RELEASE</spring.boot.version>
+ </properties>
+
+ <name>skywalking-jdk-threading-scenario</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ <version>${spring.boot.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <finalName>jdk-threading-scenario</finalName>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ <version>${spring.boot.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>repackage</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.8.1</version>
+ <configuration>
+ <source>${compiler.version}</source>
+ <target>${compiler.version}</target>
+ <encoding>${project.build.sourceEncoding}</encoding>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>assemble</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>src/main/assembly/assembly.xml</descriptor>
+ </descriptors>
+ <outputDirectory>./target/</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
diff --git a/test/plugin/scenarios/jdk-threading-scenario/src/main/assembly/assembly.xml b/test/plugin/scenarios/jdk-threading-scenario/src/main/assembly/assembly.xml
new file mode 100644
index 0000000..a733286
--- /dev/null
+++ b/test/plugin/scenarios/jdk-threading-scenario/src/main/assembly/assembly.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ ~
+ -->
+<assembly
+ xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <fileSets>
+ <fileSet>
+ <directory>./bin</directory>
+ <fileMode>0775</fileMode>
+ </fileSet>
+ </fileSets>
+
+ <files>
+ <file>
+ <source>./target/jdk-threading-scenario.jar</source>
+ <outputDirectory>./libs</outputDirectory>
+ <fileMode>0775</fileMode>
+ </file>
+ </files>
+</assembly>
\ No newline at end of file
diff --git a/test/plugin/scenarios/jdk-threading-scenario/src/main/java/test/org/apache/skywalking/apm/testcase/jdk/threading/Application.java b/test/plugin/scenarios/jdk-threading-scenario/src/main/java/test/org/apache/skywalking/apm/testcase/jdk/threading/Application.java
new file mode 100644
index 0000000..1cbdedb
--- /dev/null
+++ b/test/plugin/scenarios/jdk-threading-scenario/src/main/java/test/org/apache/skywalking/apm/testcase/jdk/threading/Application.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package test.org.apache.skywalking.apm.testcase.jdk.threading;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author kezhenxu94
+ */
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+ @Bean
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+
+ @RestController
+ static class TestController {
+ private final RestTemplate restTemplate;
+ private final ExecutorService executorService;
+
+ public TestController(final RestTemplate restTemplate) {
+ this.restTemplate = restTemplate;
+ this.executorService = Executors.newSingleThreadScheduledExecutor();
+ }
+
+ @GetMapping("/healthCheck")
+ public String healthCheck() {
+ return "Success";
+ }
+
+ @GetMapping("/greet/{username}")
+ public String testCase(@PathVariable final String username) throws ExecutionException, InterruptedException {
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ restTemplate.getForEntity("https://github.com/apache/skywalking", String.class);
+ }
+ };
+
+ executorService.execute(runnable);
+
+ executorService.submit(new Callable<String>() {
+ @Override
+ public String call() {
+ return restTemplate.getForEntity("https://github.com/apache/skywalking", String.class).getBody();
+ }
+ }).get();
+
+ return username;
+ }
+ }
+}
diff --git a/test/plugin/scenarios/jdk-threading-scenario/src/main/resources/application.yaml b/test/plugin/scenarios/jdk-threading-scenario/src/main/resources/application.yaml
new file mode 100644
index 0000000..6ff39eb8
--- /dev/null
+++ b/test/plugin/scenarios/jdk-threading-scenario/src/main/resources/application.yaml
@@ -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 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
+
diff --git a/test/plugin/scenarios/jdk-threading-scenario/support-version.list b/test/plugin/scenarios/jdk-threading-scenario/support-version.list
new file mode 100644
index 0000000..feef03c
--- /dev/null
+++ b/test/plugin/scenarios/jdk-threading-scenario/support-version.list
@@ -0,0 +1,17 @@
+# 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.
+
+all
\ No newline at end of file