Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/plugins-jdk14-test.0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ jobs:
- uses: actions/checkout@v2
with:
submodules: true
- uses: actions/setup-java@v1
- uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: 14
- name: Run Test
uses: ./.github/actions/run
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/plugins-test.0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,9 @@ jobs:
- uses: actions/checkout@v2
with:
submodules: true
- uses: actions/setup-java@v1
- uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: 8
- name: Run Plugin Test
uses: ./.github/actions/run
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/plugins-test.1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,9 @@ jobs:
- uses: actions/checkout@v2
with:
submodules: true
- uses: actions/setup-java@v1
- uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: 8
- name: Run Plugin Test
uses: ./.github/actions/run
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/plugins-test.2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ jobs:
- uses: actions/checkout@v2
with:
submodules: true
- uses: actions/setup-java@v1
- uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: 8
- name: Run Plugin Test
uses: ./.github/actions/run
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/plugins-test.3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,15 @@ jobs:
- hikaricp-scenario
- clickhouse-0.3.x-scenario
- kylin-jdbc-2.6.x-3.x-4.x-scenario
- extclassloader-scenario
steps:
- uses: actions/checkout@v2
with:
submodules: true
- uses: actions/setup-java@v1
- uses: actions/setup-java@v2
with:
java-version: 8
distribution: 'temurin'
- name: Install Oracle Libs
if: matrix.case == 'oracle-scenario'
run: |
Expand Down
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Release Notes.
8.9.0
------------------

* Add support for Java Extension Class Loader.
* Support `Transaction` and fix duplicated methods enhancements for `jedis-2.x` plugin.

#### Documentation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@

package org.apache.skywalking.apm.agent.core.conf;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.logging.core.LogLevel;
import org.apache.skywalking.apm.agent.core.logging.core.LogOutput;
Expand All @@ -30,6 +26,11 @@
import org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ClassCacheMode;
import org.apache.skywalking.apm.util.Length;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* This is the core config in sniffer agent.
*/
Expand Down Expand Up @@ -342,6 +343,13 @@ public static class Plugin {
* Mount the folders of the plugins. The folder path is relative to agent.jar.
*/
public static List<String> MOUNT = Arrays.asList("plugins", "activations");


/**
* Multiple values should be separated by `,`.
* Support wildcard "*",like "ehcache*"
*/
public static String PLUGINS_IN_EXT_CLASS_LOADER = "";
}

public static class Correlation {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ public abstract class AbstractClassEnhancePluginDefine {
*/
public static final String CONTEXT_ATTR_NAME = "_$EnhancedClassField_ws";

private boolean isExtClassLoaderLoaded = false;

/**
* Main entrance of enhancing the class.
*
Expand Down Expand Up @@ -166,6 +168,14 @@ public boolean isBootstrapInstrumentation() {
return false;
}

public boolean isExtClassLoaderLoaded() {
return isExtClassLoaderLoaded;
}

public void setExtClassLoaderLoaded(boolean isExtClassLoaderLoaded) {
this.isExtClassLoaderLoaded = isExtClassLoaderLoaded;
}

/**
* Constructor methods intercept point. See {@link ConstructorInterceptPoint}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@

package org.apache.skywalking.apm.agent.core.plugin;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.apache.skywalking.apm.agent.core.boot.AgentPackageNotFoundException;
import org.apache.skywalking.apm.agent.core.plugin.loader.AgentClassLoader;
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.loader.AgentClassLoader;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
* Plugins finder. Use {@link PluginResourcesResolver} to find all plugins, and ask {@link PluginCfg} to load all plugin
Expand Down Expand Up @@ -59,17 +60,7 @@ public List<AbstractClassEnhancePluginDefine> loadPlugins() throws AgentPackageN

List<PluginDefine> pluginClassList = PluginCfg.INSTANCE.getPluginClassList();

List<AbstractClassEnhancePluginDefine> plugins = new ArrayList<AbstractClassEnhancePluginDefine>();
for (PluginDefine pluginDefine : pluginClassList) {
try {
LOGGER.debug("loading plugin class {}.", pluginDefine.getDefineClass());
AbstractClassEnhancePluginDefine plugin = (AbstractClassEnhancePluginDefine) Class.forName(pluginDefine.getDefineClass(), true, AgentClassLoader
.getDefault()).newInstance();
plugins.add(plugin);
} catch (Throwable t) {
LOGGER.error(t, "load plugin [{}] failure.", pluginDefine.getDefineClass());
}
}
List<AbstractClassEnhancePluginDefine> plugins = PluginCreator.create(pluginClassList);

plugins.addAll(DynamicPluginLoader.INSTANCE.load(AgentClassLoader.getDefault()));

Expand Down
Original file line number Diff line number Diff line change
@@ -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.agent.core.plugin;

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.loader.AgentClassLoader;
import org.apache.skywalking.apm.util.StringUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
* The creator of AbstractClassEnhancePluginDefine instance according to {@link PluginDefine} and agent.config
*/
public class PluginCreator {

private static final ILog LOGGER = LogManager.getLogger(PluginCreator.class);

public static List<AbstractClassEnhancePluginDefine> create(List<PluginDefine> pluginDefines) {
String pluginMatchRule = Config.Plugin.PLUGINS_IN_EXT_CLASS_LOADER;
Pattern extLoadPluginMatchPattern = null;
if (StringUtil.isNotEmpty(pluginMatchRule)) {
extLoadPluginMatchPattern = Pattern.compile(pluginMatchRule.replace(",", "|")
.replace("*", ".*"));
}
List<AbstractClassEnhancePluginDefine> plugins = new ArrayList<>();
for (PluginDefine pluginDefine : pluginDefines) {
LOGGER.debug("loading plugin class {}.", pluginDefine.getDefineClass());
try {
AbstractClassEnhancePluginDefine pluginDefineInstance =
(AbstractClassEnhancePluginDefine) Class.forName(
pluginDefine.getDefineClass(), true, AgentClassLoader.getDefault()).newInstance();
if (extLoadPluginMatchPattern != null && extLoadPluginMatchPattern.matcher(pluginDefine.getName())
.matches()) {
pluginDefineInstance.setExtClassLoaderLoaded(true);
}
plugins.add(pluginDefineInstance);
} catch (Throwable t) {
LOGGER.error(t, "load plugin [{}] failure.", pluginDefine.getDefineClass());
}
}

return plugins;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
public class PluginFinder {
private final Map<String, LinkedList<AbstractClassEnhancePluginDefine>> nameMatchDefine = new HashMap<String, LinkedList<AbstractClassEnhancePluginDefine>>();
private final List<AbstractClassEnhancePluginDefine> signatureMatchDefine = new ArrayList<AbstractClassEnhancePluginDefine>();
private final List<AbstractClassEnhancePluginDefine> bootstrapClassMatchDefine = new ArrayList<AbstractClassEnhancePluginDefine>();
private final List<AbstractClassEnhancePluginDefine> bootstrapClassAndExtClassMatchDefine = new ArrayList<AbstractClassEnhancePluginDefine>();

public PluginFinder(List<AbstractClassEnhancePluginDefine> plugins) {
for (AbstractClassEnhancePluginDefine plugin : plugins) {
Expand All @@ -64,8 +64,8 @@ public PluginFinder(List<AbstractClassEnhancePluginDefine> plugins) {
signatureMatchDefine.add(plugin);
}

if (plugin.isBootstrapInstrumentation()) {
bootstrapClassMatchDefine.add(plugin);
if (plugin.isBootstrapInstrumentation() || plugin.isExtClassLoaderLoaded()) {
bootstrapClassAndExtClassMatchDefine.add(plugin);
}
}
}
Expand Down Expand Up @@ -104,7 +104,7 @@ public boolean matches(NamedElement target) {
return new ProtectiveShieldMatcher(judge);
}

public List<AbstractClassEnhancePluginDefine> getBootstrapClassMatchDefine() {
return bootstrapClassMatchDefine;
public List<AbstractClassEnhancePluginDefine> getBootstrapClassAndExtClassMatchDefine() {
return bootstrapClassAndExtClassMatchDefine;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ public static Class forInternalDelegateClass(String methodsInterceptor) {
private static boolean prepareJREInstrumentation(PluginFinder pluginFinder,
Map<String, byte[]> classesTypeMap) throws PluginException {
TypePool typePool = TypePool.Default.of(BootstrapInstrumentBoost.class.getClassLoader());
List<AbstractClassEnhancePluginDefine> bootstrapClassMatchDefines = pluginFinder.getBootstrapClassMatchDefine();
List<AbstractClassEnhancePluginDefine> bootstrapClassMatchDefines = pluginFinder.getBootstrapClassAndExtClassMatchDefine();
for (AbstractClassEnhancePluginDefine define : bootstrapClassMatchDefines) {
if (Objects.nonNull(define.getInstanceMethodsInterceptPoints())) {
for (InstanceMethodsInterceptPoint point : define.getInstanceMethodsInterceptPoints()) {
Expand Down Expand Up @@ -197,7 +197,7 @@ private static boolean prepareJREInstrumentation(PluginFinder pluginFinder,
private static boolean prepareJREInstrumentationV2(PluginFinder pluginFinder,
Map<String, byte[]> classesTypeMap) throws PluginException {
TypePool typePool = TypePool.Default.of(BootstrapInstrumentBoost.class.getClassLoader());
List<AbstractClassEnhancePluginDefine> bootstrapClassMatchDefines = pluginFinder.getBootstrapClassMatchDefine();
List<AbstractClassEnhancePluginDefine> bootstrapClassMatchDefines = pluginFinder.getBootstrapClassAndExtClassMatchDefine();
for (AbstractClassEnhancePluginDefine define : bootstrapClassMatchDefines) {
if (Objects.nonNull(define.getInstanceMethodsInterceptV2Points())) {
for (InstanceMethodsInterceptV2Point point : define.getInstanceMethodsInterceptV2Points()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ protected DynamicType.Builder<?> enhanceInstance(TypeDescription typeDescription
.to(new InstMethodsInterWithOverrideArgs(interceptor, classLoader)));
}
} else {
if (isBootstrapInstrumentation()) {
if (isBootstrapInstrumentation() || isExtClassLoaderLoaded()) {
newClassBuilder = newClassBuilder.method(junction)
.intercept(MethodDelegation.withDefaultConfiguration()
.to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor)));
Expand Down Expand Up @@ -189,7 +189,7 @@ protected DynamicType.Builder<?> enhanceClass(TypeDescription typeDescription, D
}

if (staticMethodsInterceptPoint.isOverrideArgs()) {
if (isBootstrapInstrumentation()) {
if (isBootstrapInstrumentation() || isExtClassLoaderLoaded()) {
newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
.intercept(MethodDelegation.withDefaultConfiguration()
.withBinders(Morph.Binder.install(OverrideCallable.class))
Expand All @@ -201,7 +201,7 @@ protected DynamicType.Builder<?> enhanceClass(TypeDescription typeDescription, D
.to(new StaticMethodsInterWithOverrideArgs(interceptor)));
}
} else {
if (isBootstrapInstrumentation()) {
if (isBootstrapInstrumentation() || isExtClassLoaderLoaded()) {
newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
.intercept(MethodDelegation.withDefaultConfiguration()
.to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ protected DynamicType.Builder<?> enhanceClass(TypeDescription typeDescription,
}

if (staticMethodsInterceptV2Point.isOverrideArgs()) {
if (isBootstrapInstrumentation()) {
if (isBootstrapInstrumentation() || isExtClassLoaderLoaded()) {
newClassBuilder = newClassBuilder.method(
isStatic().and(staticMethodsInterceptV2Point.getMethodsMatcher()))
.intercept(MethodDelegation.withDefaultConfiguration()
Expand All @@ -87,7 +87,7 @@ protected DynamicType.Builder<?> enhanceClass(TypeDescription typeDescription,
.to(new StaticMethodsInterV2WithOverrideArgs(interceptor)));
}
} else {
if (isBootstrapInstrumentation()) {
if (isBootstrapInstrumentation() || isExtClassLoaderLoaded()) {
newClassBuilder = newClassBuilder.method(
isStatic().and(staticMethodsInterceptV2Point.getMethodsMatcher()))
.intercept(MethodDelegation.withDefaultConfiguration()
Expand Down Expand Up @@ -165,7 +165,7 @@ protected DynamicType.Builder<?> enhanceInstance(TypeDescription typeDescription
junction = junction.and(ElementMatchers.<MethodDescription>isDeclaredBy(typeDescription));
}
if (instanceMethodsInterceptV2Point.isOverrideArgs()) {
if (isBootstrapInstrumentation()) {
if (isBootstrapInstrumentation() || isExtClassLoaderLoaded()) {
newClassBuilder = newClassBuilder.method(junction)
.intercept(MethodDelegation.withDefaultConfiguration()
.withBinders(Morph.Binder.install(OverrideCallable.class))
Expand All @@ -177,7 +177,7 @@ protected DynamicType.Builder<?> enhanceInstance(TypeDescription typeDescription
.to(new InstMethodsInterV2WithOverrideArgs(interceptor, classLoader)));
}
} else {
if (isBootstrapInstrumentation()) {
if (isBootstrapInstrumentation() || isExtClassLoaderLoaded()) {
newClassBuilder = newClassBuilder.method(junction)
.intercept(MethodDelegation.withDefaultConfiguration()
.to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor)));
Expand Down
2 changes: 2 additions & 0 deletions apm-sniffer/config/agent.config
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ plugin.mount=${SW_MOUNT_FOLDERS:plugins,activations}
plugin.peer_max_length=${SW_PLUGIN_PEER_MAX_LENGTH:200}
# Exclude some plugins define in plugins dir.Plugin names is defined in [Agent plugin list](Plugin-list.md)
plugin.exclude_plugins=${SW_EXCLUDE_PLUGINS:}
# Declare which plugins are for excClassloader.Multiple values should be separated by ",". Support wildcard "*",like "ehcache*".The plugin names are defined in [Agent plugin list](Plugin-list.md)
plugin.plugins_in_ext_class_loader=${SW_PLUGINS_IN_EXT_CLASS_LOADER:}
# If true, trace all the parameters in MongoDB access, default is false. Only trace the operation, not include parameters.
plugin.mongodb.trace_param=${SW_PLUGIN_MONGODB_TRACE_PARAM:false}
# If set to positive number, the `WriteRequest.params` would be truncated to this length, otherwise it would be completely saved, which may cause performance problem.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## Extension ClassLoader
**Extension ClassLoader**: The Extension ClassLoader is a child of Bootstrap ClassLoader and loads the extensions of core java classes from the respective JDK Extension library.
It loads files from jre/lib/ext directory or any other directory pointed by the system property java.ext.dirs.
User decides which parts of the service should be loaded by the extension classloader, so, we open `plugin.plugins_in_ext_class_loader=${SW_PLUGINS_IN_EXT_CLASS_LOADER:}` in the `agent.config` file.

Through this setting, users declare plugins are for excClassloader. Multiple values should be separated by ",".
Also support wildcard(`\*`),like `ehcache\*`. All plugin names are defined in [Agent plugin list](Plugin-list.md)
3 changes: 2 additions & 1 deletion docs/en/setup/service-agent/java-agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,5 @@ active it.
- All plugins in `/plugins` folder are active. Remove the plugin jar, it disabled.
- The default logging output folder is `/logs`.


If you are using `Extension ClassLoader` for Java services, please refer
to [Extension ClassLoader Setup](Extension-classloader.md) doc for more details.
1 change: 1 addition & 0 deletions docs/en/setup/service-agent/java-agent/configurations.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ property key | Description | Default |
`plugin.mount` | Mount the specific folders of the plugins. Plugins in mounted folders would work. | `plugins,activations` |
`plugin.peer_max_length `|Peer maximum description limit.|`200`|
`plugin.exclude_plugins `|Exclude some plugins define in plugins dir.Plugin names is defined in [Agent plugin list](Plugin-list.md)|`""`|
`plugin.plugins_in_ext_class_loader `|Declare which plugins are for excClassloader.Multiple values should be separated by ",". Support wildcard "\*",like "ehcache\*".The plugin names are defined in [Agent plugin list](Plugin-list.md)|`""`|
`plugin.mongodb.trace_param`|If true, trace all the parameters in MongoDB access, default is false. Only trace the operation, not include parameters.|`false`|
`plugin.mongodb.filter_length_limit`|If set to positive number, the `WriteRequest.params` would be truncated to this length, otherwise it would be completely saved, which may cause performance problem.|`256`|
`plugin.elasticsearch.trace_dsl`|If true, trace all the DSL(Domain Specific Language) in ElasticSearch access, default is false.|`false`|
Expand Down
Loading