diff --git a/.github/workflows/plugins-test.yaml b/.github/workflows/plugins-test.yaml index 15b9844eef3fbf06aea35425c0c06c9dab0b6522..9cb28d526441ec5cb536b4293c627976fac79edd 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 8ac1799458c0890ad0c827d96baa96895898df68..1ec2dec08a42d66e17c8821951873dfb431d2e1a 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 2bc276c3b58edb6d7bc0862fa9574437fbfc169e..0b0842cf9386c3acc466a85b19a2e071cbaca2c3 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 f134d383a734a5dcd8debc3267e8961f335e39fc..314c4b3cc5aca697c4e7d60fd34040bdf8f657c0 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 0000000000000000000000000000000000000000..d2cb78f65734475f35c7e4bb58dda95971c44d6d --- /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 0000000000000000000000000000000000000000..dc523aebebe1933ef873c3424dc35eccb51d5234 --- /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 0000000000000000000000000000000000000000..0fa5b83f50f328d58dd366c9f8b0df94fda9429c --- /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 0000000000000000000000000000000000000000..1a10a4fb772f06980223d2d7fd12de0b6a22c679 --- /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 0000000000000000000000000000000000000000..b9d271a1e4f8798e364078c27ee1d0c3ee260be3 --- /dev/null +++ b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/pom.xml @@ -0,0 +1,46 @@ + + + + + org.apache.skywalking + bootstrap-plugins + 6.6.0-SNAPSHOT + + 4.0.0 + + apm-jdk-threading-plugin + jar + + apm-jdk-threading-plugin + SkyWalking Java Agent Plugin for JDK threading classes, (Runnable, Callable) + https://github.com/apache/skywalking + + + UTF-8 + + + + + + maven-deploy-plugin + + + + 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 0000000000000000000000000000000000000000..97145a6c72c125d56cffe1f9aa0efcc063c96686 --- /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 prefixMatches = new ArrayList(); + + 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 0000000000000000000000000000000000000000..3ca000e6c4dec8ebd887df214fa860fc14017e93 --- /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 0000000000000000000000000000000000000000..c1607daac0eb68bf6b2dcf4315d12794b4148e95 --- /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 0000000000000000000000000000000000000000..a32560e8a2094b8207770f8142246902e3c37d47 --- /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 getConstructorMatcher() { + return any(); + } + + @Override + public String getConstructorInterceptor() { + return CALLABLE_CLASS_INTERCEPTOR; + } + } + }; + } + + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[]{ + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher 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 0000000000000000000000000000000000000000..c77e256d55a95d354c32373dda87abc06257ef1b --- /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 getConstructorMatcher() { + return any(); + } + + @Override + public String getConstructorInterceptor() { + return RUNNABLE_CLASS_INTERCEPTOR; + } + } + }; + } + + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[]{ + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher 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 0000000000000000000000000000000000000000..06aaee35e1e23c5fde8461b23e40804219084def --- /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 b421ee1c1faa26fe44653bee5fd72b46dead6e31..eef458376e07ea8f76e5270bffc4eae003dbaa85 100644 --- a/apm-sniffer/bootstrap-plugins/pom.xml +++ b/apm-sniffer/bootstrap-plugins/pom.xml @@ -42,6 +42,7 @@ jdk-http-plugin + jdk-threading-plugin diff --git a/apm-sniffer/config/agent.config b/apm-sniffer/config/agent.config index 6e03ff2807759c091625989986aa509ce293c051..dfa6aeee9e9d1c1cc193cbca7cae96b38ae45850 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 787d90ea3f99190f25948203e9d40c766e43fc16..c316651ba5650898859610c1de72df873f8ae8a9 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 90e1d65980224d770d36ac43ac02de239c2188b7..bac1b0ce19d2209d33a69ce0f64f04ec01e57b62 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 0000000000000000000000000000000000000000..98bfae7053c9860a8687d86d124fec5f95b598ff --- /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 0000000000000000000000000000000000000000..c4c492d3d7c8ef943bd83083d389af3012de484c --- /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 0000000000000000000000000000000000000000..b129cc2a1ff1010ae1e061a40555fb780656b904 --- /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 0000000000000000000000000000000000000000..42b68ac9b88492d58251f03dc1873577e6334214 --- /dev/null +++ b/test/plugin/scenarios/jdk-threading-scenario/pom.xml @@ -0,0 +1,88 @@ + + + + 4.0.0 + + org.apache.skywalking + jdk-threading-scenario + 5.0.0 + + + UTF-8 + 1.6 + 2.1.6.RELEASE + + + skywalking-jdk-threading-scenario + + + + org.springframework.boot + spring-boot-starter-web + ${spring.boot.version} + + + + + jdk-threading-scenario + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + + repackage + + + + + + maven-compiler-plugin + 3.8.1 + + ${compiler.version} + ${compiler.version} + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-assembly-plugin + + + assemble + package + + single + + + + src/main/assembly/assembly.xml + + ./target/ + + + + + + + \ 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 0000000000000000000000000000000000000000..a73328614cdf987477515c98de6930b6dbb0661d --- /dev/null +++ b/test/plugin/scenarios/jdk-threading-scenario/src/main/assembly/assembly.xml @@ -0,0 +1,41 @@ + + + + + zip + + + + + ./bin + 0775 + + + + + + ./target/jdk-threading-scenario.jar + ./libs + 0775 + + + \ 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 0000000000000000000000000000000000000000..1cbdedbb545d084e60a78e8a09bd5df6c11f6a6c --- /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() { + @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 0000000000000000000000000000000000000000..6ff39eb8eafc6f543aaac7dd8d7992d71041fea8 --- /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 0000000000000000000000000000000000000000..feef03cdea9d00b52f68d88fc4bd5773cc072290 --- /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