[강운덕] [LUCYSUS-1744] span의 데이터를 api 를 기반으로 변경하기 위해 1차 적으로 정적으로 api정보를 수집받을수 있도록 수정함.

method의 parameter의 variablename을 획득할수 있도록 수정함. 단 디버그 컴파일 시만 간능함.

git-svn-id: http://svn.bds.nhncorp.com/pe/hippo-tomcat-profiler/trunk@871 84d0f5b1-2673-498c-a247-62c4ff18d310
This commit is contained in:
Woonduk Kang
2012-11-16 13:03:57 +00:00
parent 515b0237e7
commit b8c73bfdef
14 changed files with 657 additions and 291 deletions
@@ -68,9 +68,8 @@ public class SystemMonitor {
}
public void run() {
JVMInfoThriftDTO jvmInfo = new JVMInfoThriftDTO();
try {
jvmInfo = new JVMInfoThriftDTO();
JVMInfoThriftDTO jvmInfo = new JVMInfoThriftDTO();
jvmInfo.setAgentId(Agent.getInstance().getAgentId());
jvmInfo.setDataTime(System.currentTimeMillis());
@@ -49,4 +49,15 @@ public class StackFrame {
public Span getSpan() {
return span;
}
public void attachObject(Object object) {
}
public Object getAttachObject(Object object) {
return null;
}
public Object detachObject() {
return null;
}
}
@@ -90,10 +90,15 @@ public final class Trace {
}
public void markBeforeTime() {
StackFrame context = getCurrentStackFrame();
context.markBeforeTime();
StackFrame stackFrame = getCurrentStackFrame();
stackFrame.markBeforeTime();
}
// public void attachObject(Object object) {
// StackFrame stackFrame = getCurrentStackFrame();
// stackFrame.attachObject(object);
// }
public long afterTime() {
StackFrame context = getCurrentStackFrame();
return context.afterTime();
@@ -0,0 +1,8 @@
package com.profiler.interceptor;
/**
* precompile level의 methodDescriptor를 setting 받을수 있게 한다.
*/
public interface ByteCodeMethodDescriptorSupport {
void setMethodDescriptor(MethodDescriptor descriptor);
}
@@ -0,0 +1,106 @@
package com.profiler.interceptor;
/**
*
*/
public class DefaultMethodDescriptor implements MethodDescriptor {
private String className;
private String simpleClassName;
private String methodName;
private String[] parameterTypes;
private String[] simpleParameterTypes;
private String[] parameterVariableName;
private String parameterDescriptor;
private String simpleParameterDescriptor;
private int lineNumber;
public DefaultMethodDescriptor() {
}
public String getParameterDescriptor() {
return parameterDescriptor;
}
public void setParameterDescriptor(String parameterDescriptor) {
this.parameterDescriptor = parameterDescriptor;
}
public String getSimpleParameterDescriptor() {
return simpleParameterDescriptor;
}
public void setSimpleParameterDescriptor(String simpleParameterDescriptor) {
this.simpleParameterDescriptor = simpleParameterDescriptor;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public void setParameterTypes(String[] parameterTypes) {
this.parameterTypes = parameterTypes;
}
public void setParameterVariableName(String[] parameterVariableName) {
this.parameterVariableName = parameterVariableName;
}
public void setLineNumber(int lineNumber) {
this.lineNumber = lineNumber;
}
@Override
public String getMethodName() {
return methodName;
}
@Override
public String getClassName() {
return className;
}
@Override
public String getSimpleClassName() {
return simpleClassName;
}
public void setSimpleClassName(String simpleClassName) {
this.simpleClassName = simpleClassName;
}
public void setClassName(String className) {
this.className = className;
}
@Override
public String[] getParameterTypes() {
return parameterTypes;
}
@Override
public String[] getParameterVariableName() {
return parameterVariableName;
}
public String[] getSimpleParameterTypes() {
return simpleParameterTypes;
}
public void setSimpleParameterTypes(String[] simpleParameterTypes) {
this.simpleParameterTypes = simpleParameterTypes;
}
public int getLineNumber() {
return lineNumber;
}
}
@@ -0,0 +1,27 @@
package com.profiler.interceptor;
import java.lang.reflect.Method;
/**
*
*/
public interface MethodDescriptor {
String getMethodName();
String getClassName();
String getSimpleClassName();
String[] getParameterTypes();
String[] getSimpleParameterTypes();
String[] getParameterVariableName();
String getParameterDescriptor();
String getSimpleParameterDescriptor();
int getLineNumber();
}
@@ -4,87 +4,81 @@ import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.profiler.interceptor.*;
import com.profiler.util.JavaAssistUtils;
import javassist.*;
import com.profiler.interceptor.Interceptor;
import com.profiler.interceptor.InterceptorRegistry;
import com.profiler.interceptor.LoggingInterceptor;
import com.profiler.interceptor.StaticAfterInterceptor;
import com.profiler.interceptor.StaticAroundInterceptor;
import com.profiler.interceptor.StaticBeforeInterceptor;
public class JavaAssistClass implements InstrumentClass {
private final Logger logger = Logger.getLogger(this.getClass().getName());
private final Logger logger = Logger.getLogger(this.getClass().getName());
private JavaAssistByteCodeInstrumentor instrumentor;
private CtClass ctClass;
private JavaAssistByteCodeInstrumentor instrumentor;
private CtClass ctClass;
public JavaAssistClass(JavaAssistByteCodeInstrumentor instrumentor, CtClass ctClass) {
this.instrumentor = instrumentor;
this.ctClass = ctClass;
}
public JavaAssistClass(JavaAssistByteCodeInstrumentor instrumentor, CtClass ctClass) {
this.instrumentor = instrumentor;
this.ctClass = ctClass;
}
public CtClass getCtClass() {
return ctClass;
}
public CtClass getCtClass() {
return ctClass;
}
@Override
public boolean insertCodeBeforeConstructor(String[] args, String code) {
try {
CtConstructor constructor = getConstructor(args);
constructor.insertBefore(code);
return true;
} catch (Exception e) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, e.getMessage(), e);
}
return false;
}
}
@Override
public boolean insertCodeBeforeConstructor(String[] args, String code) {
try {
CtConstructor constructor = getConstructor(args);
constructor.insertBefore(code);
return true;
} catch (Exception e) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, e.getMessage(), e);
}
return false;
}
}
@Override
public boolean insertCodeAfterConstructor(String[] args, String code) {
try {
CtConstructor constructor = getConstructor(args);
constructor.insertAfter(code);
return true;
} catch (Exception e) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, e.getMessage(), e);
}
return false;
}
}
@Override
public boolean insertCodeAfterConstructor(String[] args, String code) {
try {
CtConstructor constructor = getConstructor(args);
constructor.insertAfter(code);
return true;
} catch (Exception e) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, e.getMessage(), e);
}
return false;
}
}
@Override
public boolean insertCodeBeforeMethod(String methodName, String[] args, String code) {
try {
CtMethod method = getMethod(methodName, args);
method.insertBefore(code);
return true;
} catch (Exception e) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, e.getMessage(), e);
}
return false;
}
}
@Override
public boolean insertCodeBeforeMethod(String methodName, String[] args, String code) {
try {
CtMethod method = getMethod(methodName, args);
method.insertBefore(code);
return true;
} catch (Exception e) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, e.getMessage(), e);
}
return false;
}
}
@Override
public boolean insertCodeAfterMethod(String methodName, String[] args, String code) {
try {
CtMethod method = getMethod(methodName, args);
method.insertAfter(code);
return true;
} catch (Exception e) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, e.getMessage(), e);
}
return false;
}
}
@Override
public boolean insertCodeAfterMethod(String methodName, String[] args, String code) {
try {
CtMethod method = getMethod(methodName, args);
method.insertAfter(code);
return true;
} catch (Exception e) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, e.getMessage(), e);
}
return false;
}
}
public void addTraceVariable(String variableName, String setterName, String getterName, String variableType, String initValue) throws InstrumentException {
addTraceVariable0(variableName, setterName, getterName, variableType, initValue);
@@ -118,34 +112,34 @@ public class JavaAssistClass implements InstrumentClass {
}
}
public int addConstructorInterceptor(String[] args, Interceptor interceptor) throws InstrumentException, NotFoundInstrumentException {
public int addConstructorInterceptor(String[] args, Interceptor interceptor) throws InstrumentException, NotFoundInstrumentException {
if (interceptor == null) {
throw new IllegalArgumentException("interceptor is null");
throw new IllegalArgumentException("interceptor is null");
}
return addInterceptor0(null, args, interceptor, -1, Type.auto);
}
@Override
public int addInterceptor(String methodName, String[] args, Interceptor interceptor) throws InstrumentException, NotFoundInstrumentException {
public int addInterceptor(String methodName, String[] args, Interceptor interceptor) throws InstrumentException, NotFoundInstrumentException {
if (interceptor == null) {
throw new IllegalArgumentException("interceptor is null");
throw new IllegalArgumentException("interceptor is null");
}
return addInterceptor0(methodName, args, interceptor, -1, Type.auto);
}
return addInterceptor0(methodName, args, interceptor, -1, Type.auto);
}
@Override
public int reuseInterceptor(String methodName, String[] args, int interceptorId) throws InstrumentException, NotFoundInstrumentException {
return addInterceptor0(methodName, args, null, interceptorId, Type.auto);
}
@Override
public int addInterceptor(String methodName, String[] args, Interceptor interceptor, Type type) throws InstrumentException, NotFoundInstrumentException {
@Override
public int addInterceptor(String methodName, String[] args, Interceptor interceptor, Type type) throws InstrumentException, NotFoundInstrumentException {
if (interceptor == null) {
throw new IllegalArgumentException("interceptor is null");
throw new IllegalArgumentException("interceptor is null");
}
return addInterceptor0(methodName, args, interceptor, -1, type);
}
}
private CtBehavior getBehavior(String methodName, String[] args) throws NotFoundException {
if (methodName == null) {
@@ -154,7 +148,7 @@ public class JavaAssistClass implements InstrumentClass {
return getMethod(methodName, args);
}
private int addInterceptor0(String methodName, String[] args, Interceptor interceptor, int interceptorId,Type type) throws InstrumentException, NotFoundInstrumentException {
private int addInterceptor0(String methodName, String[] args, Interceptor interceptor, int interceptorId, Type type) throws InstrumentException, NotFoundInstrumentException {
CtBehavior behavior = null;
try {
behavior = getBehavior(methodName, args);
@@ -169,9 +163,13 @@ public class JavaAssistClass implements InstrumentClass {
try {
if (interceptor != null) {
interceptorId = InterceptorRegistry.addInterceptor(interceptor);
if (interceptor instanceof ByteCodeMethodDescriptorSupport) {
setMethodDescriptor(behavior, (ByteCodeMethodDescriptorSupport) interceptor);
}
} else {
interceptor = InterceptorRegistry.getInterceptor(interceptorId);
}
if (type == Type.auto) {
if (interceptor instanceof StaticAroundInterceptor) {
addStaticAroundInterceptor(methodName, interceptorId, behavior);
@@ -191,96 +189,126 @@ public class JavaAssistClass implements InstrumentClass {
} else {
throw new IllegalArgumentException("unsupported");
}
return interceptorId;
return interceptorId;
} catch (NotFoundException e) {
throw new InstrumentException(interceptor.getClass().getSimpleName() + " add fail. Cause:" + e.getMessage(), e);
} catch (CannotCompileException e) {
throw new InstrumentException(interceptor.getClass().getSimpleName() + "add fail. Cause:" + e.getMessage(), e);
throw new InstrumentException(interceptor.getClass().getSimpleName() + "add fail. Cause:" + e.getMessage(), e);
}
}
private void addStaticAroundInterceptor(String methodName, int id, CtBehavior method) throws NotFoundException, CannotCompileException {
addStaticBeforeInterceptor(methodName, id, method);
addStaticAfterInterceptor(methodName, id, method);
}
private void setMethodDescriptor(CtBehavior behavior, ByteCodeMethodDescriptorSupport interceptor) throws NotFoundException {
DefaultMethodDescriptor methodDescriptor = new DefaultMethodDescriptor();
private void addStaticAfterInterceptor(String methodName, int id, CtBehavior behavior) throws NotFoundException, CannotCompileException {
String methodName = behavior.getName();
methodDescriptor.setMethodName(methodName);
methodDescriptor.setClassName(ctClass.getName());
methodDescriptor.setSimpleClassName(ctClass.getSimpleName());
CtClass[] parameterTypes = behavior.getParameterTypes();
String[] parameterType = JavaAssistUtils.getParameterType(parameterTypes);
methodDescriptor.setParameterTypes(parameterType);
String[] parameterSimpleType = JavaAssistUtils.getParameterSimpleType(parameterTypes);
methodDescriptor.setSimpleParameterTypes(parameterSimpleType);
String[] parameterVariableName = JavaAssistUtils.getParameterVariableName(behavior);
methodDescriptor.setParameterVariableName(parameterVariableName);
int lineNumber = JavaAssistUtils.getLineNumber(behavior);
methodDescriptor.setLineNumber(lineNumber);
String parameterDescription = JavaAssistUtils.mergeParameterVariableNameDescription(parameterType, parameterVariableName);
methodDescriptor.setParameterDescriptor(parameterDescription);
String simpleParameterDescription = JavaAssistUtils.mergeParameterVariableNameDescription(parameterType, parameterVariableName);
methodDescriptor.setSimpleParameterDescriptor(simpleParameterDescription);
interceptor.setMethodDescriptor(methodDescriptor);
}
private void addStaticAroundInterceptor(String methodName, int id, CtBehavior method) throws NotFoundException, CannotCompileException {
addStaticBeforeInterceptor(methodName, id, method);
addStaticAfterInterceptor(methodName, id, method);
}
private void addStaticAfterInterceptor(String methodName, int id, CtBehavior behavior) throws NotFoundException, CannotCompileException {
String target = getTarget(behavior);
String returnType = getReturnType(behavior);
String returnType = getReturnType(behavior);
String parameterTypeString = JavaAssistUtils.getParameterDescription(behavior.getParameterTypes());
String parameter = getParameter(behavior);
CodeBuilder after = new CodeBuilder();
after.begin();
after.begin();
after.format(" %1$s interceptor = (%1$s) com.profiler.interceptor.InterceptorRegistry.getInterceptor(%2$d);", StaticAfterInterceptor.class.getName(), id);
after.format(" interceptor.after(%1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s, %6$s);", target, ctClass.getName(), methodName, parameterTypeString, parameter,returnType);
after.end();
String buildAfter = after.toString();
if (logger.isLoggable(Level.INFO)) {
logger.info("addStaticAfterInterceptor after behavior:" + behavior.getLongName() + " code:" + buildAfter);
}
behavior.insertAfter(buildAfter);
after.format(" interceptor.after(%1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s, %6$s);", target, ctClass.getName(), methodName, parameterTypeString, parameter, returnType);
after.end();
String buildAfter = after.toString();
if (logger.isLoggable(Level.INFO)) {
logger.info("addStaticAfterInterceptor after behavior:" + behavior.getLongName() + " code:" + buildAfter);
}
behavior.insertAfter(buildAfter);
CodeBuilder catchCode = new CodeBuilder();
catchCode.begin();
CodeBuilder catchCode = new CodeBuilder();
catchCode.begin();
catchCode.format(" %1$s interceptor = (%1$s) com.profiler.interceptor.InterceptorRegistry.getInterceptor(%2$d);", StaticAfterInterceptor.class.getName(), id);
catchCode.format(" interceptor.after(%1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s, $e);", target, ctClass.getName(), methodName, parameterTypeString, parameter);
catchCode.append(" throw $e;");
catchCode.end();
String buildCatch = catchCode.toString();
if (logger.isLoggable(Level.INFO)) {
logger.info("addStaticAfterInterceptor catch behavior:" + behavior.getLongName() + " code:" + buildCatch);
}
CtClass th = instrumentor.getClassPool().get("java.lang.Throwable");
behavior.addCatch(buildCatch, th);
catchCode.append(" throw $e;");
catchCode.end();
String buildCatch = catchCode.toString();
if (logger.isLoggable(Level.INFO)) {
logger.info("addStaticAfterInterceptor catch behavior:" + behavior.getLongName() + " code:" + buildCatch);
}
CtClass th = instrumentor.getClassPool().get("java.lang.Throwable");
behavior.addCatch(buildCatch, th);
}
}
private String getTarget(CtBehavior behavior) {
boolean staticMethod = JavaAssistUtils.isStaticBehavior(behavior);
if (staticMethod) {
return "null";
} else {
return "this";
}
}
private String getTarget(CtBehavior behavior) {
boolean staticMethod = JavaAssistUtils.isStaticBehavior(behavior);
if (staticMethod) {
return "null";
} else {
return "this";
}
}
public String getReturnType(CtBehavior behavior) throws NotFoundException {
if (behavior instanceof CtMethod) {
CtClass returnType = ((CtMethod) behavior).getReturnType();
if (CtClass.voidType == returnType) {
return "null";
}
}
return "($w)$_";
}
public String getReturnType(CtBehavior behavior) throws NotFoundException {
if (behavior instanceof CtMethod) {
CtClass returnType = ((CtMethod) behavior).getReturnType();
if (CtClass.voidType == returnType) {
return "null";
}
}
return "($w)$_";
}
private void addStaticBeforeInterceptor(String methodName, int id, CtBehavior behavior) throws CannotCompileException, NotFoundException {
String target = getTarget(behavior);
private void addStaticBeforeInterceptor(String methodName, int id, CtBehavior behavior) throws CannotCompileException, NotFoundException {
String target = getTarget(behavior);
// 인터셉터 호출시 최대한 연산량을 줄이기 위해서 정보는 가능한 정적 데이터로 생성한다.
String parameterDescription = JavaAssistUtils.getParameterDescription(behavior.getParameterTypes());
String parameter = getParameter(behavior);
CodeBuilder code = new CodeBuilder();
code.begin();
code.begin();
code.format(" %1$s interceptor = (%1$s) com.profiler.interceptor.InterceptorRegistry.getInterceptor(%2$d);", StaticBeforeInterceptor.class.getName(), id);
code.format(" interceptor.before(%1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s);", target, ctClass.getName(), methodName, parameterDescription, parameter);
code.end();
String buildBefore = code.toString();
if (logger.isLoggable(Level.INFO)) {
logger.info("addStaticBeforeInterceptor catch behavior:" + behavior.getLongName() + " code:" + buildBefore);
}
code.end();
String buildBefore = code.toString();
if (logger.isLoggable(Level.INFO)) {
logger.info("addStaticBeforeInterceptor catch behavior:" + behavior.getLongName() + " code:" + buildBefore);
}
if (behavior instanceof CtConstructor) {
((CtConstructor) behavior).insertBeforeBody(buildBefore);
} else {
behavior.insertBefore(buildBefore);
}
}
if (behavior instanceof CtConstructor) {
((CtConstructor) behavior).insertBeforeBody(buildBefore);
} else {
behavior.insertBefore(buildBefore);
}
}
private String getParameter(CtBehavior behavior) throws NotFoundException {
CtClass[] parameterTypes = behavior.getParameterTypes();
@@ -291,123 +319,122 @@ public class JavaAssistClass implements InstrumentClass {
}
public boolean addDebugLogBeforeAfterMethod() {
String className = this.ctClass.getName();
LoggingInterceptor loggingInterceptor = new LoggingInterceptor(className);
int id = InterceptorRegistry.addInterceptor(loggingInterceptor);
try {
CtClass cc = this.instrumentor.getClassPool().get(className);
CtMethod[] methods = cc.getDeclaredMethods();
String className = this.ctClass.getName();
LoggingInterceptor loggingInterceptor = new LoggingInterceptor(className);
int id = InterceptorRegistry.addInterceptor(loggingInterceptor);
try {
CtClass cc = this.instrumentor.getClassPool().get(className);
CtMethod[] methods = cc.getDeclaredMethods();
for (CtMethod method : methods) {
if (method.isEmpty()) {
if (logger.isLoggable(Level.FINE)) {
logger.fine(method.getLongName() + " is empty.");
}
continue;
}
String methodName = method.getName();
for (CtMethod method : methods) {
if (method.isEmpty()) {
if (logger.isLoggable(Level.FINE)) {
logger.fine(method.getLongName() + " is empty.");
}
continue;
}
String methodName = method.getName();
// TODO method의 prameter type을 interceptor에 별도 추가해야 될것으로 보임.
String params = getParamsToString(method.getParameterTypes());
addStaticAroundInterceptor(methodName, id, method);
}
return true;
} catch (Exception e) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, e.getMessage(), e);
}
}
return false;
}
// TODO method의 prameter type을 interceptor에 별도 추가해야 될것으로 보임.
String params = getParamsToString(method.getParameterTypes());
addStaticAroundInterceptor(methodName, id, method);
}
return true;
} catch (Exception e) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, e.getMessage(), e);
}
}
return false;
}
/**
* 제대로 동작안함 다시 봐야 될것 같음. 생성자일경우의 bytecode 수정시 에러가 남.
*
* @return
*/
@Deprecated
public boolean addDebugLogBeforeAfterConstructor() {
String className = this.ctClass.getName();
LoggingInterceptor loggingInterceptor = new LoggingInterceptor(className);
int id = InterceptorRegistry.addInterceptor(loggingInterceptor);
try {
CtClass cc = this.instrumentor.getClassPool().get(className);
CtConstructor[] constructors = cc.getConstructors();
/**
* 제대로 동작안함 다시 봐야 될것 같음. 생성자일경우의 bytecode 수정시 에러가 남.
*
* @return
*/
@Deprecated
public boolean addDebugLogBeforeAfterConstructor() {
String className = this.ctClass.getName();
LoggingInterceptor loggingInterceptor = new LoggingInterceptor(className);
int id = InterceptorRegistry.addInterceptor(loggingInterceptor);
try {
CtClass cc = this.instrumentor.getClassPool().get(className);
CtConstructor[] constructors = cc.getConstructors();
for (CtConstructor constructor : constructors) {
if (constructor.isEmpty()) {
if (logger.isLoggable(Level.FINE)) {
logger.fine(constructor.getLongName() + " is empty.");
}
continue;
}
String constructorName = constructor.getName();
String params = getParamsToString(constructor.getParameterTypes());
for (CtConstructor constructor : constructors) {
if (constructor.isEmpty()) {
if (logger.isLoggable(Level.FINE)) {
logger.fine(constructor.getLongName() + " is empty.");
}
continue;
}
String constructorName = constructor.getName();
String params = getParamsToString(constructor.getParameterTypes());
// constructor.insertAfter("{System.out.println(\"*****" +
// constructorName + " Constructor:Param=(" + params +
// ") is finished. \" + $args);}");
// constructor.addCatch("{System.out.println(\"*****" +
// constructorName + " Constructor:Param=(" + params +
// ") is finished.\"); throw $e; }"
// , instrumentor.getClassPool().get("java.lang.Throwable"));
addStaticAroundInterceptor(constructorName, id, constructor);
}
return true;
} catch (Exception e) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, e.getMessage(), e);
}
}
return false;
}
// constructor.insertAfter("{System.out.println(\"*****" +
// constructorName + " Constructor:Param=(" + params +
// ") is finished. \" + $args);}");
// constructor.addCatch("{System.out.println(\"*****" +
// constructorName + " Constructor:Param=(" + params +
// ") is finished.\"); throw $e; }"
// , instrumentor.getClassPool().get("java.lang.Throwable"));
addStaticAroundInterceptor(constructorName, id, constructor);
}
return true;
} catch (Exception e) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, e.getMessage(), e);
}
}
return false;
}
private String getParamsToString(CtClass[] params) throws NotFoundException {
StringBuilder sb = new StringBuilder(512);
if (params.length != 0) {
int paramsLength = params.length;
for (int loop = paramsLength - 1; loop > 0; loop--) {
sb.append(params[loop].getName()).append(",");
}
}
String paramsStr = sb.toString();
if (logger.isLoggable(Level.FINE)) {
logger.fine("params type:" + paramsStr);
}
return paramsStr;
}
private String getParamsToString(CtClass[] params) throws NotFoundException {
StringBuilder sb = new StringBuilder(512);
if (params.length != 0) {
int paramsLength = params.length;
for (int loop = paramsLength - 1; loop > 0; loop--) {
sb.append(params[loop].getName()).append(",");
}
}
String paramsStr = sb.toString();
if (logger.isLoggable(Level.FINE)) {
logger.fine("params type:" + paramsStr);
}
return paramsStr;
}
private CtMethod getMethod(String methodName, String[] args) throws NotFoundException {
private CtMethod getMethod(String methodName, String[] args) throws NotFoundException {
CtClass[] params = JavaAssistUtils.getCtParameter(args, instrumentor.getClassPool());
// cttime에는 직접 구현클래스를 조작해야 되므로 상속관계의 method를 찾으면 안됨.
return ctClass.getDeclaredMethod(methodName, params);
}
private CtConstructor getConstructor(String[] args) throws NotFoundException {
private CtConstructor getConstructor(String[] args) throws NotFoundException {
CtClass[] params = JavaAssistUtils.getCtParameter(args, instrumentor.getClassPool());
return ctClass.getDeclaredConstructor(params);
}
}
@Override
public byte[] toBytecode() {
try {
return ctClass.toBytecode();
} catch (IOException e) {
logger.log(Level.INFO, "IoException class:" + ctClass.getName() + " " + e.getMessage(), e);
} catch (CannotCompileException e) {
logger.log(Level.INFO, "CannotCompileException class:" + ctClass.getName() + " " + e.getMessage(), e);
}
return null;
}
@Override
public byte[] toBytecode() {
try {
return ctClass.toBytecode();
} catch (IOException e) {
logger.log(Level.INFO, "IoException class:" + ctClass.getName() + " " + e.getMessage(), e);
} catch (CannotCompileException e) {
logger.log(Level.INFO, "CannotCompileException class:" + ctClass.getName() + " " + e.getMessage(), e);
}
return null;
}
public Class<?> toClass() {
try {
return ctClass.toClass();
} catch (CannotCompileException e) {
logger.log(Level.INFO, "CannotCompileException class:" + ctClass.getName() + " " + e.getMessage(), e);
}
return null;
}
public Class<?> toClass() {
try {
return ctClass.toClass();
} catch (CannotCompileException e) {
logger.log(Level.INFO, "CannotCompileException class:" + ctClass.getName() + " " + e.getMessage(), e);
}
return null;
}
}
@@ -3,6 +3,8 @@ package com.profiler.modifier.db.interceptor;
import com.profiler.context.Annotation;
import com.profiler.context.Trace;
import com.profiler.context.TraceContext;
import com.profiler.interceptor.ByteCodeMethodDescriptorSupport;
import com.profiler.interceptor.MethodDescriptor;
import com.profiler.interceptor.StaticAroundInterceptor;
import com.profiler.modifier.db.util.DatabaseInfo;
import com.profiler.util.InterceptorUtils;
@@ -16,7 +18,7 @@ import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
public class PreparedStatementExecuteQueryInterceptor implements StaticAroundInterceptor {
public class PreparedStatementExecuteQueryInterceptor implements StaticAroundInterceptor, ByteCodeMethodDescriptorSupport {
private final Logger logger = Logger.getLogger(PreparedStatementExecuteQueryInterceptor.class.getName());
@@ -25,6 +27,7 @@ public class PreparedStatementExecuteQueryInterceptor implements StaticAroundInt
private final MetaObject<Map> getBindValue = new MetaObject<Map>("__getBindValue");
private final MetaObject setBindValue = new MetaObject("__setBindValue", Map.class);
private MethodDescriptor descriptor;
@Override
public void before(Object target, String className, String methodName, String parameterDescription, Object[] args) {
@@ -37,6 +40,7 @@ public class PreparedStatementExecuteQueryInterceptor implements StaticAroundInt
}
TraceContext traceContext = TraceContext.getTraceContext();
Trace trace = traceContext.currentTraceObject();
if (trace == null) {
return;
}
@@ -52,6 +56,7 @@ public class PreparedStatementExecuteQueryInterceptor implements StaticAroundInt
Map bindValue = getBindValue.invoke(target);
String bindString = toBindVariable(bindValue);
trace.recordAttribute("BindValue", bindString);
trace.recordAttribute("API", descriptor.getClassName() + "." + descriptor.getMethodName() + descriptor.getSimpleParameterDescriptor());
clean(target);
@@ -113,4 +118,8 @@ public class PreparedStatementExecuteQueryInterceptor implements StaticAroundInt
}
}
@Override
public void setMethodDescriptor(MethodDescriptor descriptor) {
this.descriptor = descriptor;
}
}
@@ -45,9 +45,12 @@ public class MySQLPreparedStatementModifier extends AbstractModifier {
try {
InstrumentClass preparedStatement = byteCodeInstrumentor.getClass(javassistClassName);
Interceptor interceptor = new PreparedStatementExecuteQueryInterceptor();
int id = preparedStatement.addInterceptor("executeQuery", null, interceptor);
preparedStatement.reuseInterceptor("executeUpdate", null, id);
Interceptor execute = new PreparedStatementExecuteQueryInterceptor();
preparedStatement.addInterceptor("execute", null, execute);
Interceptor executeQuery = new PreparedStatementExecuteQueryInterceptor();
preparedStatement.addInterceptor("executeQuery", null, executeQuery);
Interceptor executeUpdate = new PreparedStatementExecuteQueryInterceptor();
preparedStatement.addInterceptor("executeUpdate", null, executeUpdate);
preparedStatement.addTraceVariable("__url", "__setUrl", "__getUrl", "java.lang.Object");
preparedStatement.addTraceVariable("__sql", "__setSql", "__getSql", "java.lang.String");
@@ -10,14 +10,17 @@ public class DatabaseInfo {
DBType type = DBType.UNKOWN;
String databaseId;
String url;
// 입력된 url을 보정하지 않은 값
String realUrl;
String normalizedUrl;
String host;
String port;
public DatabaseInfo(DBType type, String url, String host, String port, String databaseId) {
public DatabaseInfo(DBType type, String realUrl, String normalizedUrl, String host, String port, String databaseId) {
this.type = type;
this.url = url;
this.realUrl = realUrl;
this.normalizedUrl = normalizedUrl;
this.host = host;
this.port = port;
this.databaseId = databaseId;
@@ -39,8 +42,12 @@ public class DatabaseInfo {
return databaseId;
}
public String getRealUrl() {
return realUrl;
}
public String getUrl() {
return url;
return normalizedUrl;
}
public DBType getType() {
@@ -52,7 +59,8 @@ public class DatabaseInfo {
return "DatabaseInfo{" +
"type=" + type +
", databaseId='" + databaseId + '\'' +
", url='" + url + '\'' +
", realUrl='" + realUrl + '\'' +
", normalizedUrl='" + normalizedUrl + '\'' +
", host='" + host + '\'' +
", port='" + port + '\'' +
'}';
@@ -7,12 +7,15 @@ import java.util.regex.Matcher;
*/
public class JDBCUrlParser {
public DatabaseInfo parse(String url) {
String lowCaseURL = url.toLowerCase();
if (lowCaseURL.contains("jdbc:mysql")) {
String lowCaseURL = url.toLowerCase().trim();
if (lowCaseURL.startsWith("jdbc:mysql")) {
return parseMysql(url);
}
if (lowCaseURL.startsWith("jdbc:oracle")) {
return parseOracle(url);
}
return new DatabaseInfo(DatabaseInfo.DBType.UNKOWN, url, "error", "error", "error");
return new DatabaseInfo(DatabaseInfo.DBType.UNKOWN, url, url, "error", "error", "error");
// else if (url.indexOf("jdbc:oracle") >= 0) {
// maker.lower().after("jdbc:oracle:").after(':');
// info.type = TYPE.ORACLE;
@@ -60,6 +63,11 @@ public class JDBCUrlParser {
// return null;
}
private DatabaseInfo parseOracle(String url) {
return null;
}
private DatabaseInfo parseMysql(String url) {
// jdbc:mysql://10.98.133.22:3306/test_lucy_db
StringMaker maker = new StringMaker(url);
@@ -67,6 +75,7 @@ public class JDBCUrlParser {
String host = maker.after("//").before('/').before(':').value();
String port = maker.next().after(':').before('/').value();
String databaseId = maker.next().afterLast('/').before('?').value();
return new DatabaseInfo(DatabaseInfo.DBType.MYSQL, url, host, port, databaseId);
String normalizedUrl = maker.clear().before('?').value();
return new DatabaseInfo(DatabaseInfo.DBType.MYSQL, url, normalizedUrl, host, port, databaseId);
}
}
@@ -1,22 +1,25 @@
package com.profiler.util;
import javassist.*;
import javassist.bytecode.Descriptor;
import javassist.bytecode.*;
public class JavaAssistUtils {
private final static String NULL = "()";
private final static String EMTPY_ARRAY = "()";
private static String[] EMPTY_STRING_ARRAY = new String[0];
/**
* test(int, java.lang.String) 일경우
* (int, java.lang.String)로 생성된다.
*
* @param params
* @return
*/
public static String getParameterDescription(CtClass[] params) {
if(params == null) {
return NULL;
if (params == null) {
return EMTPY_ARRAY;
}
StringBuilder sb = new StringBuilder(64);
sb.append("(");
sb.append('(');
int end = params.length - 1;
for (int i = 0; i < params.length; i++) {
sb.append(params[i].getName());
@@ -24,10 +27,11 @@ public class JavaAssistUtils {
sb.append(", ");
}
}
sb.append(")");
sb.append(')');
return sb.toString();
}
public static String[] getParameterType(Class[] paramsClass) {
if (paramsClass == null) {
return null;
@@ -39,12 +43,34 @@ public class JavaAssistUtils {
return paramsString;
}
public static String[] getParameterSimpleType(CtClass[] paramsClass) {
if (paramsClass == null) {
return null;
}
String[] paramsString = new String[paramsClass.length];
for (int i = 0; i < paramsClass.length; i++) {
paramsString[i] = paramsClass[i].getSimpleName();
}
return paramsString;
}
public static String[] getParameterType(CtClass[] paramsClass) {
if (paramsClass == null) {
return null;
}
String[] paramsString = new String[paramsClass.length];
for (int i = 0; i < paramsClass.length; i++) {
paramsString[i] = paramsClass[i].getName();
}
return paramsString;
}
public static String getParameterDescription(Class[] params) {
if(params == null) {
return NULL;
if (params == null) {
return EMTPY_ARRAY;
}
StringBuilder sb = new StringBuilder(64);
sb.append("(");
sb.append('(');
int end = params.length - 1;
for (int i = 0; i < params.length; i++) {
sb.append(params[i].getName());
@@ -52,16 +78,40 @@ public class JavaAssistUtils {
sb.append(", ");
}
}
sb.append(")");
sb.append(')');
return sb.toString();
}
public static String mergeParameterVariableNameDescription(String[] paramterType, String[] variableName) {
if (paramterType.length != variableName.length) {
throw new IllegalArgumentException("args size not equal");
}
if (paramterType.length == 0) {
return EMTPY_ARRAY;
}
StringBuilder sb = new StringBuilder(64);
sb.append('(');
int end = paramterType.length - 1;
for (int i = 0; i < paramterType.length; i++) {
sb.append(paramterType[i]);
sb.append(' ');
sb.append(variableName[i]);
if (i < end) {
sb.append(", ");
}
}
sb.append(')');
return sb.toString();
}
public static String getParameterDescription(String[] params) {
if(params == null) {
return NULL;
if (params == null) {
return EMTPY_ARRAY;
}
StringBuilder sb = new StringBuilder(64);
sb.append("(");
sb.append('(');
int end = params.length - 1;
for (int i = 0; i < params.length; i++) {
sb.append(params[i]);
@@ -69,35 +119,94 @@ public class JavaAssistUtils {
sb.append(", ");
}
}
sb.append(")");
sb.append(')');
return sb.toString();
}
public static CtClass[] getCtParameter(String[] args, ClassPool pool) throws NotFoundException {
if (args == null) {
return null;
}
CtClass[] params = new CtClass[args.length];
for (int i = 0; i < args.length; i++) {
params[i] = pool.getCtClass(args[i]);
}
return params;
}
if (args == null) {
return null;
}
CtClass[] params = new CtClass[args.length];
for (int i = 0; i < args.length; i++) {
params[i] = pool.getCtClass(args[i]);
}
return params;
}
public static int getLineNumber(CtBehavior method) {
if (method == null) {
return -1;
}
return method.getMethodInfo().getLineNumber(0);
}
public CtMethod findAllMethod(CtClass ctClass, String methodName, String[] args) throws NotFoundException {
CtClass[] params = getCtParameter(args, ctClass.getClassPool());
String paramDescriptor = Descriptor.ofParameters(params);
CtMethod[] methods = ctClass.getMethods();
for (CtMethod method : methods) {
if(method.getName().equals(methodName) && method.getMethodInfo2().getDescriptor().startsWith(paramDescriptor)) {
if (method.getName().equals(methodName) && method.getMethodInfo2().getDescriptor().startsWith(paramDescriptor)) {
return method;
}
}
throw new NotFoundException(methodName+ "(..) is not found in " + ctClass.getName());
throw new NotFoundException(methodName + "(..) is not found in " + ctClass.getName());
}
public static boolean isStaticBehavior(CtBehavior behavior) {
int modifiers = behavior.getModifiers();
return java.lang.reflect.Modifier.isStatic(modifiers);
}
int modifiers = behavior.getModifiers();
return java.lang.reflect.Modifier.isStatic(modifiers);
}
public static String[] getParameterVariableName(CtBehavior method) throws NotFoundException {
LocalVariableAttribute localVariableAttribute = lookupLocalVariableAttribute(method);
return getParameterVariableName(method, localVariableAttribute);
}
/**
* LocalVariable 메모리 공간을 얻어 온다.
*
* @param method
* @return null일 경우 debug모드로 컴파일 되지 않아서 그럼.
*/
public static LocalVariableAttribute lookupLocalVariableAttribute(CtBehavior method) {
MethodInfo methodInfo = method.getMethodInfo();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
AttributeInfo localVariableTable = codeAttribute.getAttribute(LocalVariableAttribute.tag);
LocalVariableAttribute local = (LocalVariableAttribute) localVariableTable;
return local;
}
public static String[] getParameterVariableName(CtBehavior method, LocalVariableAttribute localVariableAttribute) throws NotFoundException {
// http://www.jarvana.com/jarvana/view/org/jboss/weld/servlet/weld-servlet/1.0.1-Final/weld-servlet-1.0.1-Final-sources.jar!/org/slf4j/instrumentation/JavassistHelper.java?format=ok
// 이거 참고함.
if (localVariableAttribute == null) {
// null이라는건 debug모드로 컴파일 되지 않았다는 의미이다.
// parameter class명을 default로 하자.
return null;
}
CtClass[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 0) {
return EMPTY_STRING_ARRAY;
}
String[] parameterVariableNames = new String[parameterTypes.length];
int firstIndex = 0;
int modifiers = method.getModifiers();
// 동기화 메소드라도 index를 증가시키면 안되는데. 참고 소스와는 뭔가 다름 나중에 문제가 생길수 있으니 일단 주석으로 적음.
// if (Modifier.isSynchronized(modifiers)) {
// firstIndex++;
// }
if (Modifier.isStatic(modifiers) == false) {
firstIndex++;
}
for (int i = 0; i < parameterTypes.length; i++) {
int accesIndex = firstIndex + i;
String variablename = localVariableAttribute.variableName(accesIndex);
parameterVariableNames[i] = variablename;
}
return parameterVariableNames;
}
}