mirror of
https://github.com/wahyd4/pinpoint.git
synced 2026-08-25 04:35:59 +10:00
refactoring api
add testcase
This commit is contained in:
+89
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* *
|
||||
* * Copyright 2016 NAVER Corp.
|
||||
* * Licensed 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* *
|
||||
* * Copyright 2016 NAVER Corp.
|
||||
* * Licensed 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 com.navercorp.pinpoint.profiler.instrument;
|
||||
|
||||
import com.navercorp.pinpoint.exception.PinpointException;
|
||||
import com.navercorp.pinpoint.profiler.plugin.PluginConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* @author Woonduk Kang(emeroad)
|
||||
*/
|
||||
public class BootstrapClassLoaderHandler implements ClassInjector {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private final PluginConfig pluginConfig;
|
||||
|
||||
private final Object lock = new Object();
|
||||
private boolean injectedToRoot = false;
|
||||
|
||||
public BootstrapClassLoaderHandler(PluginConfig pluginConfig) {
|
||||
if (pluginConfig == null) {
|
||||
throw new NullPointerException("pluginConfig must not be null");
|
||||
}
|
||||
this.pluginConfig = pluginConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Class<? extends T> injectClass(ClassLoader classLoader, String className) {
|
||||
try {
|
||||
if (classLoader == null) {
|
||||
return (Class<T>)injectClass0(className);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to load plugin class {} with classLoader {}", className, classLoader, e);
|
||||
throw new PinpointException("Failed to load plugin class " + className + " with classLoader " + classLoader, e);
|
||||
}
|
||||
throw new PinpointException("invalid ClassLoader");
|
||||
}
|
||||
|
||||
private Class<?> injectClass0(String className) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, ClassNotFoundException {
|
||||
synchronized (lock) {
|
||||
if (this.injectedToRoot == false) {
|
||||
this.injectedToRoot = true;
|
||||
pluginConfig.getInstrumentation().appendToBootstrapClassLoaderSearch(pluginConfig.getPluginJarFile());
|
||||
pluginConfig.getClassPool().appendToBootstrapClassPath(pluginConfig.getPluginJarFile().getName());
|
||||
}
|
||||
}
|
||||
return Class.forName(className, false, null);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+11
-171
@@ -3,9 +3,9 @@
|
||||
* Licensed 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.
|
||||
@@ -14,20 +14,9 @@
|
||||
*/
|
||||
package com.navercorp.pinpoint.profiler.instrument;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.*;
|
||||
|
||||
import com.navercorp.pinpoint.profiler.plugin.ClassLoadingChecker;
|
||||
import com.navercorp.pinpoint.profiler.plugin.PluginConfig;
|
||||
import javassist.CannotCompileException;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.LoaderClassPath;
|
||||
import javassist.NotFoundException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -40,37 +29,18 @@ import com.navercorp.pinpoint.exception.PinpointException;
|
||||
*/
|
||||
public class JarProfilerPluginClassInjector implements ClassInjector {
|
||||
private final Logger logger = LoggerFactory.getLogger(JarProfilerPluginClassInjector.class);
|
||||
private final boolean isDebug = logger.isDebugEnabled();
|
||||
|
||||
private static final Method ADD_URL;
|
||||
private static final Method DEFINE_CLASS;
|
||||
|
||||
static {
|
||||
try {
|
||||
ADD_URL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
||||
ADD_URL.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new PinpointException("Cannot access URLClassLoader.addURL(URL)", e);
|
||||
}
|
||||
|
||||
try {
|
||||
DEFINE_CLASS = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
|
||||
DEFINE_CLASS.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new PinpointException("Cannot access ClassLoader.defineClass(String, byte[], int, int)", e);
|
||||
}
|
||||
}
|
||||
|
||||
private final PluginConfig pluginConfig;
|
||||
|
||||
private final Object lock = new Object();
|
||||
private boolean injectedToRoot = false;
|
||||
private final ClassInjector bootstrapClassLoaderHandler;
|
||||
private final ClassInjector urlClassLoaderHandler;
|
||||
private final ClassInjector plainClassLoaderHandler;
|
||||
|
||||
public JarProfilerPluginClassInjector(PluginConfig pluginConfig) {
|
||||
if (pluginConfig == null) {
|
||||
throw new NullPointerException("pluginConfig must not be null");
|
||||
}
|
||||
this.pluginConfig = pluginConfig;
|
||||
this.bootstrapClassLoaderHandler = new BootstrapClassLoaderHandler(pluginConfig);
|
||||
this.urlClassLoaderHandler = new URLClassLoaderHandler(pluginConfig);
|
||||
this.plainClassLoaderHandler = new PlainClassLoaderHandler(pluginConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,12 +48,12 @@ public class JarProfilerPluginClassInjector implements ClassInjector {
|
||||
public <T> Class<? extends T> injectClass(ClassLoader classLoader, String className) {
|
||||
try {
|
||||
if (classLoader == null) {
|
||||
return (Class<T>)injectToBootstrapClassLoader(className);
|
||||
return (Class<T>)bootstrapClassLoaderHandler.injectClass(null, className);
|
||||
} else if (classLoader instanceof URLClassLoader) {
|
||||
final URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
|
||||
return (Class<T>)injectToURLClassLoader(urlClassLoader, className);
|
||||
return (Class<T>)urlClassLoaderHandler.injectClass(urlClassLoader, className);
|
||||
} else {
|
||||
return (Class<T>)injectToPlainClassLoader(classLoader, className);
|
||||
return (Class<T>)plainClassLoaderHandler.injectClass(classLoader, className);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to load plugin class {} with classLoader {}", className, classLoader, e);
|
||||
@@ -91,134 +61,4 @@ public class JarProfilerPluginClassInjector implements ClassInjector {
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?> injectToBootstrapClassLoader(String className) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, ClassNotFoundException {
|
||||
synchronized (lock) {
|
||||
if (this.injectedToRoot == false) {
|
||||
this.injectedToRoot = true;
|
||||
pluginConfig.getInstrumentation().appendToBootstrapClassLoaderSearch(pluginConfig.getPluginJarFile());
|
||||
pluginConfig.getClassPool().appendToBootstrapClassPath(pluginConfig.getPluginJarFile().getName());
|
||||
}
|
||||
}
|
||||
|
||||
return Class.forName(className, false, null);
|
||||
}
|
||||
|
||||
private Class<?> injectToURLClassLoader(URLClassLoader classLoader, String className) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, ClassNotFoundException {
|
||||
final URL[] urls = classLoader.getURLs();
|
||||
if (urls != null) {
|
||||
|
||||
boolean hasPluginJar = false;
|
||||
for (URL url : urls) {
|
||||
// if (url.equals(pluginJarURL)) { fix very slow
|
||||
// http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html
|
||||
final String externalForm = url.toExternalForm();
|
||||
if (pluginConfig.getPluginJarURLExternalForm().equals(externalForm)) {
|
||||
hasPluginJar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasPluginJar) {
|
||||
ADD_URL.invoke(classLoader, pluginConfig.getPluginJar());
|
||||
}
|
||||
}
|
||||
|
||||
return classLoader.loadClass(className);
|
||||
}
|
||||
|
||||
private Class<?> injectToPlainClassLoader(ClassLoader classLoader, String className) throws NotFoundException, IllegalArgumentException, IOException, CannotCompileException, IllegalAccessException, InvocationTargetException {
|
||||
if (isDebug) {
|
||||
logger.debug("injectToPlainClassLoader className:{} cl:{}", className, classLoader);
|
||||
}
|
||||
logger.info("bootstrapCoreJarPath:{}", pluginConfig.getBootstrapCoreJarPath());
|
||||
|
||||
final ClassPool pool = createClassPool(classLoader);
|
||||
|
||||
// TODO ClassLoader + ClassName key?
|
||||
// TODO concurrent class loading
|
||||
final ClassLoadingChecker classLoadingChecker = new ClassLoadingChecker();
|
||||
return injectToPlainClassLoader(pool, classLoader, className, classLoadingChecker);
|
||||
}
|
||||
|
||||
private ClassPool createClassPool(ClassLoader classLoader) throws NotFoundException {
|
||||
final ClassPool pool = new ClassPool();
|
||||
pool.appendClassPath(pluginConfig.getBootstrapCoreJarPath());
|
||||
|
||||
pool.appendClassPath(new LoaderClassPath(classLoader));
|
||||
pool.appendClassPath(pluginConfig.getPluginJarFile().getName());
|
||||
return pool;
|
||||
}
|
||||
|
||||
private Class<?> injectToPlainClassLoader(ClassPool pool, ClassLoader classLoader, String className, ClassLoadingChecker classLoadingChecker) throws NotFoundException, IOException, CannotCompileException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
|
||||
if (pluginConfig.getProfilerPackageFilter().accept(className)) {
|
||||
if (isDebug) {
|
||||
logger.debug("ProfilerFilter skip class {}", className);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (!pluginConfig.getPluginPackageFilter().accept(className)) {
|
||||
if (isDebug) {
|
||||
logger.debug("PluginFilter skip class:{}", className);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (!classLoadingChecker.isFirstLoad(className)) {
|
||||
if (isDebug) {
|
||||
logger.debug("skip already loaded class:{}", className);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Class<?> c = null;
|
||||
try {
|
||||
c = classLoader.loadClass(className);
|
||||
if (isDebug) {
|
||||
logger.debug("loadClass:{}", className);
|
||||
}
|
||||
} catch (ClassNotFoundException ex) {
|
||||
if (isDebug) {
|
||||
logger.debug("ClassNotFound {}", ex.getMessage());
|
||||
}
|
||||
}
|
||||
if (c != null) {
|
||||
return c;
|
||||
}
|
||||
|
||||
final CtClass ct = pool.getOrNull(className);
|
||||
if (ct == null) {
|
||||
throw new NotFoundException(className);
|
||||
}
|
||||
|
||||
|
||||
final CtClass superClass = ct.getSuperclass();
|
||||
if (superClass != null) {
|
||||
if ("java.lang.Object".equals(superClass.getName())) {
|
||||
return null;
|
||||
}
|
||||
injectToPlainClassLoader(pool, classLoader, superClass.getName(), classLoadingChecker);
|
||||
}
|
||||
|
||||
final CtClass[] interfaces = ct.getInterfaces();
|
||||
for (CtClass ctInterface : interfaces) {
|
||||
injectToPlainClassLoader(pool, classLoader, ctInterface.getName(), classLoadingChecker);
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
final Collection<String> referenceClassList = ct.getRefClasses();
|
||||
if (isDebug) {
|
||||
logger.debug("target:{} referenceClassList:{}", className, referenceClassList);
|
||||
}
|
||||
for (String referenceClass : referenceClassList) {
|
||||
try {
|
||||
injectToPlainClassLoader(pool, classLoader, referenceClass, classLoadingChecker);
|
||||
} catch (NotFoundException e) {
|
||||
logger.warn("Skip a referenced class because of NotFoundException : {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("defineClass pluginClass:{} cl:{}", className, classLoader);
|
||||
}
|
||||
final byte[] bytes = ct.toBytecode();
|
||||
return (Class<?>)DEFINE_CLASS.invoke(classLoader, ct.getName(), bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* *
|
||||
* * Copyright 2016 NAVER Corp.
|
||||
* * Licensed 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* *
|
||||
* * Copyright 2016 NAVER Corp.
|
||||
* * Licensed 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 com.navercorp.pinpoint.profiler.instrument;
|
||||
|
||||
import com.navercorp.pinpoint.exception.PinpointException;
|
||||
import com.navercorp.pinpoint.profiler.plugin.ClassLoadingChecker;
|
||||
import com.navercorp.pinpoint.profiler.plugin.PluginConfig;
|
||||
import javassist.CannotCompileException;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.LoaderClassPath;
|
||||
import javassist.NotFoundException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author Woonduk Kang(emeroad)
|
||||
*/
|
||||
public class PlainClassLoaderHandler implements ClassInjector {
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
private final boolean isDebug = logger.isDebugEnabled();
|
||||
|
||||
private static final Method DEFINE_CLASS;
|
||||
|
||||
static {
|
||||
try {
|
||||
DEFINE_CLASS = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
|
||||
DEFINE_CLASS.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new PinpointException("Cannot access ClassLoader.defineClass(String, byte[], int, int)", e);
|
||||
}
|
||||
}
|
||||
|
||||
private final PluginConfig pluginConfig;
|
||||
|
||||
|
||||
public PlainClassLoaderHandler(PluginConfig pluginConfig) {
|
||||
if (pluginConfig == null) {
|
||||
throw new NullPointerException("pluginConfig must not be null");
|
||||
}
|
||||
this.pluginConfig = pluginConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Class<? extends T> injectClass(ClassLoader classLoader, String className) {
|
||||
try {
|
||||
return (Class<T>)injectClass0(classLoader, className);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to load plugin class {} with classLoader {}", className, classLoader, e);
|
||||
throw new PinpointException("Failed to load plugin class " + className + " with classLoader " + classLoader, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Class<?> injectClass0(ClassLoader classLoader, String className) throws NotFoundException, IllegalArgumentException, IOException, CannotCompileException, IllegalAccessException, InvocationTargetException {
|
||||
if (isDebug) {
|
||||
logger.debug("injectClass0 className:{} cl:{}", className, classLoader);
|
||||
}
|
||||
logger.info("bootstrapCoreJarPath:{}", pluginConfig.getBootstrapCoreJarPath());
|
||||
|
||||
final ClassPool pool = createClassPool(classLoader);
|
||||
|
||||
// TODO ClassLoader + ClassName key?
|
||||
// TODO concurrent class loading
|
||||
final ClassLoadingChecker classLoadingChecker = new ClassLoadingChecker();
|
||||
return injectClass0(pool, classLoader, className, classLoadingChecker);
|
||||
}
|
||||
|
||||
private ClassPool createClassPool(ClassLoader classLoader) throws NotFoundException {
|
||||
final ClassPool pool = new ClassPool();
|
||||
final String bootstrapCoreJarPath = pluginConfig.getBootstrapCoreJarPath();
|
||||
pool.appendClassPath(bootstrapCoreJarPath);
|
||||
|
||||
final LoaderClassPath loaderClassPath = new LoaderClassPath(classLoader);
|
||||
pool.appendClassPath(loaderClassPath);
|
||||
|
||||
final String pluginJarFileName = pluginConfig.getPluginJarFile().getName();
|
||||
pool.appendClassPath(pluginJarFileName);
|
||||
return pool;
|
||||
}
|
||||
|
||||
private Class<?> injectClass0(ClassPool pool, ClassLoader classLoader, String className, ClassLoadingChecker classLoadingChecker) throws NotFoundException, IOException, CannotCompileException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
|
||||
if (!pluginConfig.getPluginPackageFilter().accept(className)) {
|
||||
if (isDebug) {
|
||||
logger.debug("PluginFilter skip class:{}", className);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (!classLoadingChecker.isFirstLoad(className)) {
|
||||
if (isDebug) {
|
||||
logger.debug("skip already loaded class:{}", className);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Class<?> c = null;
|
||||
try {
|
||||
c = classLoader.loadClass(className);
|
||||
if (isDebug) {
|
||||
logger.debug("loadClass:{}", className);
|
||||
}
|
||||
} catch (ClassNotFoundException ex) {
|
||||
if (isDebug) {
|
||||
logger.debug("ClassNotFound {}", ex.getMessage());
|
||||
}
|
||||
}
|
||||
if (c != null) {
|
||||
return c;
|
||||
}
|
||||
|
||||
final CtClass ct = pool.getOrNull(className);
|
||||
if (ct == null) {
|
||||
throw new NotFoundException(className);
|
||||
}
|
||||
|
||||
|
||||
final CtClass superClass = ct.getSuperclass();
|
||||
if (superClass != null) {
|
||||
if ("java.lang.Object".equals(superClass.getName())) {
|
||||
return null;
|
||||
}
|
||||
injectClass0(pool, classLoader, superClass.getName(), classLoadingChecker);
|
||||
}
|
||||
|
||||
final CtClass[] interfaces = ct.getInterfaces();
|
||||
for (CtClass ctInterface : interfaces) {
|
||||
injectClass0(pool, classLoader, ctInterface.getName(), classLoadingChecker);
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
final Collection<String> referenceClassList = ct.getRefClasses();
|
||||
if (isDebug) {
|
||||
logger.debug("target:{} referenceClassList:{}", className, referenceClassList);
|
||||
}
|
||||
for (String referenceClass : referenceClassList) {
|
||||
try {
|
||||
injectClass0(pool, classLoader, referenceClass, classLoadingChecker);
|
||||
} catch (NotFoundException e) {
|
||||
logger.warn("Skip a referenced class because of NotFoundException : {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("defineClass pluginClass:{} cl:{}", className, classLoader);
|
||||
}
|
||||
final byte[] bytes = ct.toBytecode();
|
||||
return (Class<?>)DEFINE_CLASS.invoke(classLoader, ct.getName(), bytes, 0, bytes.length);
|
||||
}
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* *
|
||||
* * Copyright 2016 NAVER Corp.
|
||||
* * Licensed 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* *
|
||||
* * Copyright 2016 NAVER Corp.
|
||||
* * Licensed 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 com.navercorp.pinpoint.profiler.instrument;
|
||||
|
||||
import com.navercorp.pinpoint.exception.PinpointException;
|
||||
import com.navercorp.pinpoint.profiler.plugin.PluginConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
/**
|
||||
* @author Woonduk Kang(emeroad)
|
||||
*/
|
||||
public class URLClassLoaderHandler implements ClassInjector {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private static final Method ADD_URL;
|
||||
|
||||
static {
|
||||
try {
|
||||
ADD_URL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
||||
ADD_URL.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new PinpointException("Cannot access URLClassLoader.addURL(URL)", e);
|
||||
}
|
||||
}
|
||||
|
||||
private final URL pluginURL;
|
||||
private final String pluginURLString;
|
||||
|
||||
public URLClassLoaderHandler(PluginConfig pluginConfig) {
|
||||
if (pluginConfig == null) {
|
||||
throw new NullPointerException("pluginConfig must not be null");
|
||||
}
|
||||
this.pluginURL = pluginConfig.getPluginJar();
|
||||
this.pluginURLString = pluginURL.toExternalForm();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Class<? extends T> injectClass(ClassLoader classLoader, String className) {
|
||||
try {
|
||||
if (classLoader instanceof URLClassLoader) {
|
||||
final URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
|
||||
return (Class<T>)injectClass0(urlClassLoader, className);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to load plugin class {} with classLoader {}", className, classLoader, e);
|
||||
throw new PinpointException("Failed to load plugin class " + className + " with classLoader " + classLoader, e);
|
||||
}
|
||||
throw new PinpointException("invalid ClassLoader");
|
||||
}
|
||||
|
||||
|
||||
|
||||
private Class<?> injectClass0(URLClassLoader classLoader, String className) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, ClassNotFoundException {
|
||||
final URL[] urls = classLoader.getURLs();
|
||||
if (urls != null) {
|
||||
|
||||
final boolean hasPluginJar = hasPluginJar(urls);
|
||||
|
||||
if (!hasPluginJar) {
|
||||
logger.debug("add Jar:{}", pluginURLString);
|
||||
ADD_URL.invoke(classLoader, pluginURL);
|
||||
}
|
||||
}
|
||||
|
||||
return classLoader.loadClass(className);
|
||||
}
|
||||
|
||||
private boolean hasPluginJar(URL[] urls) {
|
||||
for (URL url : urls) {
|
||||
// if (url.equals(pluginJarURL)) { fix very slow
|
||||
// http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html
|
||||
final String externalForm = url.toExternalForm();
|
||||
if (pluginURLString.equals(externalForm)) {
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* *
|
||||
* * Copyright 2016 NAVER Corp.
|
||||
* * Licensed 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 com.navercorp.pinpoint.profiler.plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Woonduk Kang(emeroad)
|
||||
*/
|
||||
public class ClassNameFilterChain implements ClassNameFilter {
|
||||
|
||||
private final List<ClassNameFilter> filterChain;
|
||||
|
||||
public ClassNameFilterChain(List<ClassNameFilter> filterChain) {
|
||||
if (filterChain == null) {
|
||||
throw new NullPointerException("filterChain must not be null");
|
||||
}
|
||||
this.filterChain = new ArrayList<ClassNameFilter>(filterChain);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean accept(String className) {
|
||||
for (ClassNameFilter classNameFilter : this.filterChain) {
|
||||
if (!classNameFilter.accept(className)) {
|
||||
return REJECT;
|
||||
}
|
||||
}
|
||||
return ACCEPT;
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* *
|
||||
* * Copyright 2016 NAVER Corp.
|
||||
* * Licensed 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 com.navercorp.pinpoint.profiler.plugin;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Woonduk Kang(emeroad)
|
||||
*/
|
||||
public class PinpointProfilerPackageSkipFilter implements ClassNameFilter {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
private final List<String> packageList;
|
||||
|
||||
public PinpointProfilerPackageSkipFilter() {
|
||||
this(getPinpointPackageList());
|
||||
}
|
||||
|
||||
public PinpointProfilerPackageSkipFilter(List<String> packageList) {
|
||||
if (packageList == null) {
|
||||
throw new NullPointerException("packageList must not be null");
|
||||
}
|
||||
this.packageList = new ArrayList<String>(packageList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean accept(String className) {
|
||||
if (className == null) {
|
||||
throw new NullPointerException("className must not be null");
|
||||
}
|
||||
|
||||
for (String packageName : packageList) {
|
||||
if (className.startsWith(packageName)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.info("skip ProfilerPackage:{} Class:{}", packageName, className);
|
||||
}
|
||||
return REJECT;
|
||||
}
|
||||
}
|
||||
return ACCEPT;
|
||||
}
|
||||
|
||||
private static List<String> getPinpointPackageList() {
|
||||
List<String> pinpointPackageList = new ArrayList<String>();
|
||||
pinpointPackageList.add("com.navercorp.pinpoint.bootstrap");
|
||||
pinpointPackageList.add("com.navercorp.pinpoint.profiler");
|
||||
pinpointPackageList.add("com.navercorp.pinpoint.common");
|
||||
pinpointPackageList.add("com.navercorp.pinpoint.exception");
|
||||
// TODO move test package
|
||||
pinpointPackageList.add("com.navercorp.pinpoint.test");
|
||||
return pinpointPackageList;
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ package com.navercorp.pinpoint.profiler.plugin;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClassPool;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin;
|
||||
import com.navercorp.pinpoint.bootstrap.util.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -31,9 +30,7 @@ import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
/**
|
||||
* @author Woonduk Kang(emeroad)
|
||||
@@ -50,15 +47,14 @@ public class PluginConfig {
|
||||
private String pluginJarURLExternalForm;
|
||||
|
||||
private final ProfilerPlugin plugin;
|
||||
private final Manifest manifest;
|
||||
|
||||
private final Instrumentation instrumentation;
|
||||
private final InstrumentClassPool classPool;
|
||||
private final String bootstrapCoreJarPath;
|
||||
private final ClassNameFilter pluginPackageFilter;
|
||||
private final ClassNameFilter profilerPackageFilter;
|
||||
|
||||
public PluginConfig(URL pluginJar, ProfilerPlugin plugin, Instrumentation instrumentation, InstrumentClassPool classPool, String bootstrapCoreJarPath) {
|
||||
private final ClassNameFilter pluginPackageFilter;
|
||||
|
||||
public PluginConfig(URL pluginJar, ProfilerPlugin plugin, Instrumentation instrumentation, InstrumentClassPool classPool, String bootstrapCoreJarPath, ClassNameFilter pluginPackageFilter) {
|
||||
if (pluginJar == null) {
|
||||
throw new NullPointerException("pluginJar must not be null");
|
||||
}
|
||||
@@ -68,37 +64,16 @@ public class PluginConfig {
|
||||
this.pluginJar = pluginJar;
|
||||
this.pluginJarFile = createJarFile(pluginJar);
|
||||
this.plugin = plugin;
|
||||
this.manifest = this.getManifest();
|
||||
|
||||
this.instrumentation = instrumentation;
|
||||
this.classPool = classPool;
|
||||
this.bootstrapCoreJarPath = bootstrapCoreJarPath;
|
||||
|
||||
final List<String> pluginPackageList = getPluginPackage(manifest);
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("{} Plugin Package:{}", plugin.getClass(), pluginPackageList);
|
||||
}
|
||||
this.pluginPackageFilter = new PluginPackageFilter(pluginPackageList);
|
||||
this.profilerPackageFilter = new PinpointProfilerPackageFilter();
|
||||
this.pluginPackageFilter = pluginPackageFilter;
|
||||
}
|
||||
|
||||
private Manifest getManifest() {
|
||||
try {
|
||||
return pluginJarFile.getManifest();
|
||||
} catch (IOException e) {
|
||||
// return empty
|
||||
return new Manifest();
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getPluginPackage(Manifest manifest) {
|
||||
final Attributes attributes = manifest.getMainAttributes();
|
||||
final String pluginPackage = attributes.getValue(PINPOINT_PLUGIN_PACKAGE);
|
||||
if (pluginPackage == null) {
|
||||
return DEFAULT_PINPOINT_PLUGIN_PACKAGE_NAME;
|
||||
}
|
||||
return StringUtils.splitAndTrim(pluginPackage, ",");
|
||||
}
|
||||
|
||||
|
||||
public ProfilerPlugin getPlugin() {
|
||||
return plugin;
|
||||
@@ -146,7 +121,5 @@ public class PluginConfig {
|
||||
return pluginPackageFilter;
|
||||
}
|
||||
|
||||
public ClassNameFilter getProfilerPackageFilter() {
|
||||
return profilerPackageFilter;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+76
-6
@@ -14,14 +14,23 @@
|
||||
*/
|
||||
package com.navercorp.pinpoint.profiler.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.GuardInstrumentContext;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentContext;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplate;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.transformer.TransformTemplateAware;
|
||||
import com.navercorp.pinpoint.bootstrap.util.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -39,6 +48,8 @@ public class ProfilerPluginLoader {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
private final DefaultAgent agent;
|
||||
|
||||
private final ClassNameFilter profilerPackageFilter = new PinpointProfilerPackageSkipFilter();
|
||||
|
||||
public ProfilerPluginLoader(DefaultAgent agent) {
|
||||
if (agent == null) {
|
||||
throw new NullPointerException("agent must not be null");
|
||||
@@ -51,31 +62,87 @@ public class ProfilerPluginLoader {
|
||||
List<String> disabled = agent.getProfilerConfig().getDisabledPlugins();
|
||||
|
||||
for (URL jar : pluginJars) {
|
||||
List<ProfilerPlugin> plugins = PluginLoader.load(ProfilerPlugin.class, new URL[] { jar });
|
||||
|
||||
|
||||
final JarFile pluginJarFile = createJarFile(jar);
|
||||
final List<String> pluginPackageList = getPluginPackage(pluginJarFile);
|
||||
|
||||
final ClassNameFilter pluginFilterChain = createPluginFilterChain(pluginPackageList);
|
||||
|
||||
final List<ProfilerPlugin> plugins = PluginLoader.load(ProfilerPlugin.class, new URL[] { jar });
|
||||
|
||||
for (ProfilerPlugin plugin : plugins) {
|
||||
if (disabled.contains(plugin.getClass().getName())) {
|
||||
logger.info("Skip disabled plugin: {}", plugin.getClass().getName());
|
||||
continue;
|
||||
}
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("{} Plugin {}:{}", plugin.getClass(), PluginConfig.PINPOINT_PLUGIN_PACKAGE, pluginPackageList);
|
||||
}
|
||||
|
||||
logger.info("Loading plugin: {}", plugin.getClass().getName());
|
||||
logger.info("Loading plugin:{} pluginPackage:{}", plugin.getClass().getName(), plugin);
|
||||
|
||||
PluginConfig pluginConfig = new PluginConfig(jar, plugin, agent.getInstrumentation(), agent.getClassPool(), agent.getBootstrapCoreJar());
|
||||
PluginConfig pluginConfig = new PluginConfig(jar, plugin, agent.getInstrumentation(), agent.getClassPool(), agent.getBootstrapCoreJar(), pluginFilterChain);
|
||||
final DefaultProfilerPluginContext context = setupPlugin(pluginConfig);
|
||||
pluginContexts.add(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return pluginContexts;
|
||||
}
|
||||
|
||||
private ClassNameFilter createPluginFilterChain(List<String> packageList) {
|
||||
|
||||
final ClassNameFilter pluginPackageFilter = new PluginPackageFilter(packageList);
|
||||
|
||||
final List<ClassNameFilter> chain = Arrays.asList(profilerPackageFilter, pluginPackageFilter);
|
||||
|
||||
final ClassNameFilter filterChain = new ClassNameFilterChain(chain);
|
||||
|
||||
return filterChain;
|
||||
}
|
||||
|
||||
private JarFile createJarFile(URL pluginJar) {
|
||||
try {
|
||||
final URI uri = pluginJar.toURI();
|
||||
return new JarFile(new File(uri));
|
||||
} catch (URISyntaxException e) {
|
||||
throw new RuntimeException("URISyntax error. " + e.getCause(), e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("IO error. " + e.getCause(), e);
|
||||
}
|
||||
}
|
||||
private Manifest getManifest(JarFile pluginJarFile) {
|
||||
try {
|
||||
return pluginJarFile.getManifest();
|
||||
} catch (IOException ex) {
|
||||
logger.info("{} IoError :{}", pluginJarFile.getName(), ex.getMessage(), ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getPluginPackage(JarFile pluginJarFile) {
|
||||
|
||||
final Manifest manifest = getManifest(pluginJarFile);
|
||||
if (manifest == null) {
|
||||
return PluginConfig.DEFAULT_PINPOINT_PLUGIN_PACKAGE_NAME;
|
||||
}
|
||||
|
||||
final Attributes attributes = manifest.getMainAttributes();
|
||||
final String pluginPackage = attributes.getValue(PluginConfig.PINPOINT_PLUGIN_PACKAGE);
|
||||
if (pluginPackage == null) {
|
||||
return PluginConfig.DEFAULT_PINPOINT_PLUGIN_PACKAGE_NAME;
|
||||
}
|
||||
return StringUtils.splitAndTrim(pluginPackage, ",");
|
||||
}
|
||||
|
||||
|
||||
private GuardInstrumentContext preparePlugin(ProfilerPlugin plugin, InstrumentContext context) {
|
||||
|
||||
final GuardInstrumentContext guardInstrumentContext = new GuardInstrumentContext(context);
|
||||
if (plugin instanceof TransformTemplateAware) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("setTransformTemplate {}", plugin.getClass().getName());
|
||||
logger.debug("{}.setTransformTemplate", plugin.getClass().getName());
|
||||
}
|
||||
final TransformTemplate transformTemplate = new TransformTemplate(guardInstrumentContext);
|
||||
((TransformTemplateAware) plugin).setTransformTemplate(transformTemplate);
|
||||
@@ -92,6 +159,9 @@ public class ProfilerPluginLoader {
|
||||
try {
|
||||
// WARN external plugin api
|
||||
final ProfilerPlugin plugin = pluginConfig.getPlugin();
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("{} Plugin setup", plugin.getClass().getName());
|
||||
}
|
||||
plugin.setup(guardPluginContext);
|
||||
} finally {
|
||||
guardPluginContext.close();
|
||||
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* *
|
||||
* * Copyright 2016 NAVER Corp.
|
||||
* * Licensed 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* *
|
||||
* * Copyright 2016 NAVER Corp.
|
||||
* * Licensed 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 com.navercorp.pinpoint.profiler.instrument;
|
||||
|
||||
import com.navercorp.pinpoint.bootstrap.LibClass;
|
||||
import com.navercorp.pinpoint.bootstrap.PinpointURLClassLoader;
|
||||
import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClassPool;
|
||||
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin;
|
||||
import com.navercorp.pinpoint.profiler.plugin.PluginConfig;
|
||||
import com.navercorp.pinpoint.profiler.plugin.PluginPackageFilter;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.URL;
|
||||
import java.security.CodeSource;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author Woonduk Kang(emeroad)
|
||||
*/
|
||||
public class JarProfilerPluginClassInjectorTest {
|
||||
|
||||
public static final String CONTEXT_TYPE_MATCH_CLASS_LOADER = "org.springframework.context.support.ContextTypeMatchClassLoader";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Test
|
||||
public void testInjectClass() throws Exception {
|
||||
final URL sampleJar = getSampleJar(Logger.class);
|
||||
|
||||
final ClassLoader contextTypeMatchClassLoader = createContextTypeMatchClassLoader(new URL[]{sampleJar});
|
||||
|
||||
InstrumentClassPool pool = Mockito.mock(InstrumentClassPool.class);
|
||||
final Instrumentation instrumentation = Mockito.mock(Instrumentation.class);
|
||||
final ProfilerPlugin profilerPlugin = Mockito.mock(ProfilerPlugin.class);
|
||||
|
||||
|
||||
// final PluginPackageFilter filter = new PluginPackageFilter(Arrays.asList("test"));
|
||||
final String packageName = logger.getClass().getPackage().getName();
|
||||
final PluginPackageFilter filter = new PluginPackageFilter(Arrays.asList(packageName));
|
||||
PluginConfig pluginConfig = new PluginConfig(sampleJar, profilerPlugin, instrumentation, pool, sampleJar.getPath(), filter);
|
||||
|
||||
PlainClassLoaderHandler injector = new PlainClassLoaderHandler(pluginConfig);
|
||||
final Class<?> loggerClass = injector.injectClass(contextTypeMatchClassLoader, logger.getClass().getName());
|
||||
|
||||
logger.debug("ClassLoader{}", loggerClass.getClassLoader());
|
||||
Assert.assertEquals("check className", loggerClass.getName(), "org.slf4j.impl.Log4jLoggerAdapter");
|
||||
Assert.assertEquals("check ClassLoader", loggerClass.getClassLoader().getClass().getName(), CONTEXT_TYPE_MATCH_CLASS_LOADER);
|
||||
|
||||
}
|
||||
|
||||
private ClassLoader createContextTypeMatchClassLoader(URL[] urlArray) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, java.lang.reflect.InvocationTargetException {
|
||||
final ClassLoader classLoader = this.getClass().getClassLoader();
|
||||
final Class<ClassLoader> aClass = (Class<ClassLoader>) classLoader.loadClass(CONTEXT_TYPE_MATCH_CLASS_LOADER);
|
||||
final Constructor<ClassLoader> constructor = aClass.getConstructor(ClassLoader.class);
|
||||
ReflectionUtils.makeAccessible(constructor);
|
||||
|
||||
final LibClass libClassFilter = new LibClass() {
|
||||
@Override
|
||||
public boolean onLoadClass(String clazzName) {
|
||||
if (clazzName.startsWith("org.slf4j")) {
|
||||
logger.debug("Loading {}", clazzName);
|
||||
return ON_LOAD_CLASS;
|
||||
}
|
||||
return DELEGATE_PARENT;
|
||||
}
|
||||
};
|
||||
PinpointURLClassLoader testClassLoader = new PinpointURLClassLoader(urlArray, ClassLoader.getSystemClassLoader(), libClassFilter);
|
||||
|
||||
final ClassLoader contextTypeMatchClassLoader = constructor.newInstance(testClassLoader);
|
||||
|
||||
logger.debug("cl:{}",contextTypeMatchClassLoader);
|
||||
|
||||
// final Method excludePackage = aClass.getMethod("excludePackage", String.class);
|
||||
// ReflectionUtils.invokeMethod(excludePackage, contextTypeMatchClassLoader, "org.slf4j");
|
||||
|
||||
|
||||
return contextTypeMatchClassLoader;
|
||||
}
|
||||
|
||||
|
||||
private URL getSampleJar(Class clazz) {
|
||||
final CodeSource codeSource = clazz.getProtectionDomain().getCodeSource();
|
||||
final URL location = codeSource.getLocation();
|
||||
|
||||
logger.debug("url:{}", location);
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* *
|
||||
* * Copyright 2016 NAVER Corp.
|
||||
* * Licensed 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 com.navercorp.pinpoint.profiler.plugin;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author Woonduk Kang(emeroad)
|
||||
*/
|
||||
public class ClassNameFilterChainTest {
|
||||
|
||||
@Test
|
||||
public void testAccept() throws Exception {
|
||||
PluginPackageFilter include = new PluginPackageFilter(Arrays.asList("com.include"));
|
||||
PinpointProfilerPackageSkipFilter exclude = new PinpointProfilerPackageSkipFilter(Arrays.asList("com.exclude"));
|
||||
|
||||
ClassNameFilterChain chain = new ClassNameFilterChain(Arrays.asList(include, exclude));
|
||||
|
||||
|
||||
Assert.assertTrue(chain.accept("com.include"));
|
||||
Assert.assertFalse(chain.accept("com.exclude"));
|
||||
|
||||
Assert.assertFalse(chain.accept("unknown"));
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* *
|
||||
* * Copyright 2016 NAVER Corp.
|
||||
* * Licensed 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 com.navercorp.pinpoint.profiler.plugin;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Woonduk Kang(emeroad)
|
||||
*/
|
||||
public class PinpointProfilerPackageSkipFilterTest {
|
||||
|
||||
@Test
|
||||
public void testAccept() throws Exception {
|
||||
|
||||
PinpointProfilerPackageSkipFilter filter = new PinpointProfilerPackageSkipFilter();
|
||||
Assert.assertFalse("skip", filter.accept("com.navercorp.pinpoint.bootstrap.test.class"));
|
||||
|
||||
Assert.assertTrue("include", filter.accept("test"));
|
||||
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* *
|
||||
* * Copyright 2016 NAVER Corp.
|
||||
* * Licensed 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 com.navercorp.pinpoint.profiler.plugin;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Woonduk Kang(emeroad)
|
||||
*/
|
||||
public class PluginPackageFilterTest {
|
||||
|
||||
@Test
|
||||
public void testAccept() throws Exception {
|
||||
PluginPackageFilter filter = new PluginPackageFilter(Arrays.asList("com.plugin"));
|
||||
|
||||
Assert.assertTrue(filter.accept("com.plugin.test.module"));
|
||||
|
||||
Assert.assertFalse(filter.accept("test"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user