mirror of
https://github.com/wahyd4/pinpoint.git
synced 2026-08-17 08:46:22 +10:00
[강운덕] [LUCYSUS-1744] mysql interceptor 추가, testcase작성이 가능한 testclassloader 추가.
git-svn-id: http://svn.bds.nhncorp.com/pe/hippo-tomcat-profiler/trunk@569 84d0f5b1-2673-498c-a247-62c4ff18d310
This commit is contained in:
@@ -9,8 +9,6 @@ public class InterceptorRegistry {
|
||||
|
||||
private final AtomicInteger id = new AtomicInteger(0);
|
||||
private final Interceptor[] index;
|
||||
// private final ConcurrentMap<String, List<Integer>> nameToIndex = new
|
||||
// ConcurrentHashMap<String, List<Integer>>();
|
||||
|
||||
public static final InterceptorRegistry REGISTRY = new InterceptorRegistry();
|
||||
|
||||
@@ -23,6 +21,7 @@ public class InterceptorRegistry {
|
||||
this.index = new Interceptor[max];
|
||||
}
|
||||
|
||||
|
||||
int addInterceptor0(Interceptor interceptor) {
|
||||
if (interceptor == null) {
|
||||
return -1;
|
||||
@@ -47,4 +46,5 @@ public class InterceptorRegistry {
|
||||
public static Interceptor getInterceptor(int key) {
|
||||
return REGISTRY.getInterceptor0(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import com.profiler.interceptor.Interceptor;
|
||||
public interface InstrumentClass {
|
||||
boolean addInterceptor(String methodName, String[] args, Interceptor interceptor);
|
||||
|
||||
boolean addInterceptor(String methodName, String[] args, Interceptor interceptor, Type type);
|
||||
|
||||
boolean addDebugLogBeforeAfterMethod();
|
||||
|
||||
boolean addDebugLogBeforeAfterConstructor();
|
||||
|
||||
@@ -118,6 +118,9 @@ public class JavaAssistByteCodeInstrumentor implements ByteCodeInstrumentor {
|
||||
logger.info("Loaded " + filePath + " library.");
|
||||
}
|
||||
} catch (NotFoundException e) {
|
||||
if (logger.isLoggable(Level.WARNING)) {
|
||||
logger.log(Level.WARNING, "lib not fail. " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,21 +30,42 @@ public class JavaAssistClass implements InstrumentClass {
|
||||
this.ctClass = ctClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public boolean addInterceptor(String methodName, String[] args, Interceptor interceptor) {
|
||||
return addInterceptor(methodName, args, interceptor, Type.auto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addInterceptor(String methodName, String[] args, Interceptor interceptor, Type type) {
|
||||
if (interceptor == null)
|
||||
return false;
|
||||
|
||||
|
||||
CtMethod method = getMethod(methodName, args);
|
||||
if(method == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int id = InterceptorRegistry.addInterceptor(interceptor);
|
||||
try {
|
||||
CtMethod method = getMethod(methodName, args);
|
||||
if (interceptor instanceof StaticAroundInterceptor) {
|
||||
addAroundInterceptor(methodName, id, method);
|
||||
} else if (interceptor instanceof StaticBeforeInterceptor) {
|
||||
addStaticBeforeInterceptor(methodName, id, method);
|
||||
} else if (interceptor instanceof StaticAfterInterceptor) {
|
||||
addStaticAfterInterceptor(methodName, id, method);
|
||||
}
|
||||
if(type == Type.auto) {
|
||||
if (interceptor instanceof StaticAroundInterceptor) {
|
||||
addStaticAroundInterceptor(methodName, id, method);
|
||||
} else if (interceptor instanceof StaticBeforeInterceptor) {
|
||||
addStaticBeforeInterceptor(methodName, id, method);
|
||||
} else if (interceptor instanceof StaticAfterInterceptor) {
|
||||
addStaticAfterInterceptor(methodName, id, method);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if(type == Type.around && interceptor instanceof StaticAroundInterceptor) {
|
||||
addStaticAroundInterceptor(methodName, id, method);
|
||||
} else if(type == Type.before && interceptor instanceof StaticBeforeInterceptor) {
|
||||
addStaticBeforeInterceptor(methodName, id, method);
|
||||
} else if(type == Type.after && interceptor instanceof StaticAfterInterceptor) {
|
||||
addStaticAfterInterceptor(methodName, id, method);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (NotFoundException e) {
|
||||
if (logger.isLoggable(Level.WARNING)) {
|
||||
@@ -58,7 +79,7 @@ public class JavaAssistClass implements InstrumentClass {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void addAroundInterceptor(String methodName, int id, CtBehavior method) throws NotFoundException, CannotCompileException {
|
||||
private void addStaticAroundInterceptor(String methodName, int id, CtBehavior method) throws NotFoundException, CannotCompileException {
|
||||
addStaticBeforeInterceptor(methodName, id, method);
|
||||
addStaticAfterInterceptor(methodName, id, method);
|
||||
}
|
||||
@@ -67,7 +88,8 @@ public class JavaAssistClass implements InstrumentClass {
|
||||
StringBuilder after = new StringBuilder(1024);
|
||||
after.append("{");
|
||||
addGetStaticAfterInterceptor(after, id);
|
||||
after.append(" interceptor.after(this, \"" + ctClass.getName() + "\", \"" + methodName + "\", $args, ($w)$_);");
|
||||
String target = getTarget(behavior);
|
||||
after.append(" interceptor.after(" + target + ", \"" + ctClass.getName() + "\", \"" + methodName + "\", $args, ($w)$_);");
|
||||
after.append("}");
|
||||
String buildAfter = after.toString();
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
@@ -78,7 +100,7 @@ public class JavaAssistClass implements InstrumentClass {
|
||||
StringBuilder catchCode = new StringBuilder(1024);
|
||||
catchCode.append("{");
|
||||
addGetStaticAfterInterceptor(catchCode, id);
|
||||
catchCode.append(" interceptor.after(this, \"" + ctClass.getName() + "\", \"" + methodName + "\", $args, $e);");
|
||||
catchCode.append(" interceptor.after(" + target + ", \"" + ctClass.getName() + "\", \"" + methodName + "\", $args, $e);");
|
||||
catchCode.append(" throw $e;");
|
||||
catchCode.append("}");
|
||||
String buildCatch = catchCode.toString();
|
||||
@@ -90,7 +112,21 @@ public class JavaAssistClass implements InstrumentClass {
|
||||
|
||||
}
|
||||
|
||||
private void addGetStaticAfterInterceptor(StringBuilder after, int id) {
|
||||
private String getTarget(CtBehavior behavior) {
|
||||
boolean staticMethod = isStatic(behavior);
|
||||
if(staticMethod) {
|
||||
return "null";
|
||||
} else {
|
||||
return "this";
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isStatic(CtBehavior behavior) {
|
||||
int modifiers = behavior.getModifiers();
|
||||
return java.lang.reflect.Modifier.isStatic(modifiers);
|
||||
}
|
||||
|
||||
private void addGetStaticAfterInterceptor(StringBuilder after, int id) {
|
||||
after.append(" com.profiler.interceptor.StaticAfterInterceptor interceptor = " + "(com.profiler.interceptor.StaticAfterInterceptor) com.profiler.interceptor.InterceptorRegistry.getInterceptor(");
|
||||
after.append(id);
|
||||
after.append(");");
|
||||
@@ -100,7 +136,8 @@ public class JavaAssistClass implements InstrumentClass {
|
||||
StringBuilder code = new StringBuilder(1024);
|
||||
code.append("{");
|
||||
addGetBeforeInterceptor(id, code);
|
||||
code.append(" interceptor.before(this, \"" + ctClass.getName() + "\", \"" + methodName + "\", $args);");
|
||||
String target = getTarget(behavior);
|
||||
code.append(" interceptor.before(" + target + ", \"" + ctClass.getName() + "\", \"" + methodName + "\", $args);");
|
||||
code.append("}");
|
||||
String buildBefore = code.toString();
|
||||
if (logger.isLoggable(Level.INFO)) {
|
||||
@@ -139,7 +176,7 @@ public class JavaAssistClass implements InstrumentClass {
|
||||
|
||||
// TODO method의 prameter type을 interceptor에 별도 추가해야 될것으로 보임.
|
||||
String params = getParamsToString(method.getParameterTypes());
|
||||
addAroundInterceptor(methodName, id, method);
|
||||
addStaticAroundInterceptor(methodName, id, method);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
@@ -181,7 +218,7 @@ public class JavaAssistClass implements InstrumentClass {
|
||||
// constructorName + " Constructor:Param=(" + params +
|
||||
// ") is finished.\"); throw $e; }"
|
||||
// , instrumentor.getClassPool().get("java.lang.Throwable"));
|
||||
addAroundInterceptor(constructorName, id, constructor);
|
||||
addStaticAroundInterceptor(constructorName, id, constructor);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
@@ -207,10 +244,17 @@ public class JavaAssistClass implements InstrumentClass {
|
||||
return paramsStr;
|
||||
}
|
||||
|
||||
private CtMethod getMethod(String methodName, String[] args) throws NotFoundException {
|
||||
CtClass[] params = getCtParameter(args);
|
||||
return ctClass.getDeclaredMethod(methodName, params);
|
||||
}
|
||||
private CtMethod getMethod(String methodName, String[] args) {
|
||||
try {
|
||||
CtClass[] params = getCtParameter(args);
|
||||
return ctClass.getDeclaredMethod(methodName, params);
|
||||
} catch (NotFoundException e) {
|
||||
if (logger.isLoggable(Level.WARNING)) {
|
||||
logger.log(Level.WARNING, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private CtClass[] getCtParameter(String[] args) throws NotFoundException {
|
||||
if (args == null) {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.profiler.interceptor.bci;
|
||||
|
||||
public enum Type {
|
||||
around, before, after, auto
|
||||
}
|
||||
@@ -34,7 +34,7 @@ public abstract class AbstractModifier implements Modifier {
|
||||
protected Interceptor newInterceptor(ClassLoader classLoader, ProtectionDomain protectedDomain, String interceptorFQCN) {
|
||||
Class<?> aClass = this.byteCodeInstrumentor.defineClass(classLoader, interceptorFQCN, protectedDomain);
|
||||
try {
|
||||
return (Interceptor) aClass.newInstance();
|
||||
return (Interceptor) aClass.newInstance();
|
||||
} catch (InstantiationException e) {
|
||||
if (logger.isLoggable(Level.WARNING)) {
|
||||
logger.log(Level.WARNING, e.getMessage(), e);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.profiler.modifier.db;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
public class ConnectionTrace {
|
||||
|
||||
public ConcurrentMap<Connection, String> connectionMap = new ConcurrentHashMap<Connection, String>();
|
||||
|
||||
private static ConnectionTrace CONNECTION_TRACE = new ConnectionTrace();
|
||||
|
||||
public static ConnectionTrace getConnectionTrace() {
|
||||
return CONNECTION_TRACE;
|
||||
}
|
||||
|
||||
public void createConnection(Connection connection, String url) {
|
||||
this.connectionMap.put(connection, url);
|
||||
}
|
||||
|
||||
|
||||
public void closeConnection(Connection connection) {
|
||||
this.connectionMap.remove(connection);
|
||||
}
|
||||
|
||||
public Set<Connection> getConnectionList() {
|
||||
return connectionMap.keySet();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.profiler.modifier.db.mysql;
|
||||
|
||||
import com.profiler.interceptor.Interceptor;
|
||||
import com.profiler.interceptor.bci.ByteCodeInstrumentor;
|
||||
import com.profiler.interceptor.bci.InstrumentClass;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtMethod;
|
||||
|
||||
@@ -29,20 +31,33 @@ public class MySQLConnectionImplModifier extends AbstractModifier {
|
||||
logger.info("Modifing. " + javassistClassName);
|
||||
}
|
||||
checkLibrary(classLoader, javassistClassName);
|
||||
return changeMethods(javassistClassName, classFileBuffer);
|
||||
}
|
||||
|
||||
private byte[] changeMethods(String javassistClassName, byte[] classfileBuffer) {
|
||||
try {
|
||||
CtClass cc = classPool.get(javassistClassName);
|
||||
|
||||
updateGetInstanceMethod(cc);
|
||||
updateCreateStatementMethod(cc);
|
||||
updateCloseMethod(cc);
|
||||
InstrumentClass mysqlConnection = byteCodeInstrumentor.getClass(javassistClassName);
|
||||
if (mysqlConnection == null) {
|
||||
return null;
|
||||
}
|
||||
String[] params = new String[] {
|
||||
"java.lang.String", "int", "java.util.Properties", "java.lang.String", "java.lang.String"
|
||||
};
|
||||
Interceptor createConnection = newInterceptor(classLoader, protectedDomain, "com.profiler.modifier.db.mysql.interceptors.CreateConnectionInterceptor");
|
||||
if (createConnection == null) {
|
||||
return null;
|
||||
}
|
||||
Interceptor closeConnection = newInterceptor(classLoader, protectedDomain, "com.profiler.modifier.db.mysql.interceptors.CloseConnectionInterceptor");
|
||||
if (closeConnection == null) {
|
||||
return null;
|
||||
}
|
||||
Interceptor createStatement = newInterceptor(classLoader, protectedDomain, "com.profiler.modifier.db.mysql.interceptors.CreateStatementInterceptor");
|
||||
if (createStatement == null) {
|
||||
return null;
|
||||
}
|
||||
mysqlConnection.addInterceptor("getInstance", params, createConnection);
|
||||
mysqlConnection.addInterceptor("close", null, closeConnection);
|
||||
mysqlConnection.addInterceptor("createStatement", null, createStatement);
|
||||
|
||||
printClassConvertComplete(javassistClassName);
|
||||
|
||||
return cc.toBytecode();
|
||||
return mysqlConnection.toBytecode();
|
||||
} catch (Exception e) {
|
||||
if (logger.isLoggable(Level.WARNING)) {
|
||||
logger.log(Level.WARNING, e.getMessage(), e);
|
||||
@@ -51,6 +66,7 @@ public class MySQLConnectionImplModifier extends AbstractModifier {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private void updateCreateStatementMethod(CtClass cc) throws Exception {
|
||||
CtMethod method = cc.getDeclaredMethod("createStatement", null);
|
||||
method.insertAfter("{" + DatabaseRequestTracer.FQCN + ".put(" + TomcatProfilerConstant.REQ_DATA_TYPE_DB_CREATE_STATEMENT + "); }");
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.profiler.modifier.db.mysql.interceptors;
|
||||
|
||||
import com.profiler.interceptor.StaticAfterInterceptor;
|
||||
import com.profiler.interceptor.StaticAroundInterceptor;
|
||||
import com.profiler.interceptor.StaticBeforeInterceptor;
|
||||
import com.profiler.modifier.db.ConnectionTrace;
|
||||
import com.profiler.util.InterceptorUtils;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
|
||||
public class CloseConnectionInterceptor implements StaticBeforeInterceptor {
|
||||
|
||||
public void before(Object target, String className, String methodName, Object[] args) {
|
||||
if(!(target instanceof Connection)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ConnectionTrace connectionTrace = ConnectionTrace.getConnectionTrace();
|
||||
connectionTrace.closeConnection((Connection) target);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.profiler.modifier.db.mysql.interceptors;
|
||||
|
||||
import com.profiler.interceptor.StaticAfterInterceptor;
|
||||
import com.profiler.modifier.db.ConnectionTrace;
|
||||
import com.profiler.util.InterceptorUtils;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
public class CreateConnectionInterceptor implements StaticAfterInterceptor {
|
||||
|
||||
@Override
|
||||
public void after(Object target, String className, String methodName, Object[] args, Object result) {
|
||||
if (InterceptorUtils.isThrowable(result)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(result instanceof Connection)) {
|
||||
return;
|
||||
}
|
||||
String url = (String) args[4];
|
||||
if (url instanceof String) {
|
||||
ConnectionTrace connectionTrace = ConnectionTrace.getConnectionTrace();
|
||||
connectionTrace.createConnection((Connection)result, url);
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.profiler.modifier.db.mysql.interceptors;
|
||||
|
||||
import com.profiler.context.Trace;
|
||||
import com.profiler.interceptor.StaticAfterInterceptor;
|
||||
import com.profiler.interceptor.StaticBeforeInterceptor;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
public class CreateStatementInterceptor implements StaticAfterInterceptor {
|
||||
|
||||
@Override
|
||||
public void after(Object target, String className, String methodName, Object[] args, Object result) {
|
||||
if (Trace.getCurrentTraceId() == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -5,6 +5,8 @@ import com.profiler.context.Annotation;
|
||||
import com.profiler.context.Trace;
|
||||
import com.profiler.interceptor.StaticAroundInterceptor;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author netspider
|
||||
@@ -22,7 +24,7 @@ public class ExecuteQueryMethodInterceptor implements StaticAroundInterceptor {
|
||||
return;
|
||||
}
|
||||
|
||||
Trace.recordRpcName("mysql", "");
|
||||
Trace.recordRpcName("mysql", "url*****");
|
||||
|
||||
//
|
||||
// TODO: add destination address
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.profiler.util;
|
||||
|
||||
public class InterceptorUtils {
|
||||
public static boolean isThrowable(Object result) {
|
||||
if (result instanceof Throwable) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isSuccess(Object result) {
|
||||
return !isThrowable(result);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user