提交 3f48790c 编写于 作者: K kezhenxu94 提交者: wu-sheng

[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
上级 a6d0366c
......@@ -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
......
......@@ -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");
}
......@@ -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 = "";
}
}
}
......@@ -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);
}
}
/*
* 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);
}
}
/*
* 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;
}
}
/*
* 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);
}
}
/*
* 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;
}
}
<!--
~ 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>
/*
* 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]));
}
}
/*
* 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());
}
}
}
/*
* 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();
}
}
/*
* 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
/*
* 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
# 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
......@@ -42,6 +42,7 @@
<modules>
<module>jdk-http-plugin</module>
<module>jdk-threading-plugin</module>
</modules>
<dependencies>
......
......@@ -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}
......@@ -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).
......
......@@ -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
......
#!/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
# 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
# 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
<?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
<?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
/*
* 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;
}
}
}
# 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
# 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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册