From 41079a392e9fa09698e7d20e14b6421d5eca798c Mon Sep 17 00:00:00 2001 From: Woonduk Kang Date: Fri, 7 Sep 2012 05:44:13 +0000 Subject: [PATCH] =?UTF-8?q?[=EA=B0=95=EC=9A=B4=EB=8D=95]=20[LUCYSUS-1744]?= =?UTF-8?q?=20preparedStatement=20=EC=83=9D=EC=84=B1=EC=9D=98=20=EC=B6=94?= =?UTF-8?q?=EC=A0=81=EC=9D=B4=20=EA=B0=80=EB=8A=A5=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=B6=94=EA=B0=80.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://svn.bds.nhncorp.com/pe/hippo-tomcat-profiler/trunk@600 84d0f5b1-2673-498c-a247-62c4ff18d310 --- .../interceptor/bci/JavaAssistClass.java | 29 ++++++--- .../modifier/DefaultModifierRegistry.java | 9 +-- .../CloseConnectionInterceptor.java | 3 +- .../CreateConnectionInterceptor.java | 3 +- .../CreatePreparedStatementInterceptor.java | 3 +- .../CreateStatementInterceptor.java | 3 +- .../ExecuteQueryMethodInterceptor.java | 9 ++- .../PreparedStatementMethodInterceptor.java | 62 ++++++++++++++++++- .../java/com/profiler/util/MetaObject.java | 17 +++-- .../interceptor/bci/JavaAssistClassTest.java | 6 +- .../bci/MethodRenameInterceptorTest.java | 2 +- 11 files changed, 111 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/profiler/interceptor/bci/JavaAssistClass.java b/src/main/java/com/profiler/interceptor/bci/JavaAssistClass.java index 7c482fd92..07c4a6aee 100644 --- a/src/main/java/com/profiler/interceptor/bci/JavaAssistClass.java +++ b/src/main/java/com/profiler/interceptor/bci/JavaAssistClass.java @@ -100,9 +100,9 @@ public class JavaAssistClass implements InstrumentClass { ctClass.addMethod(getterMethod); } } catch (NotFoundException e) { - throw new InstrumentException("addTraceVariable fail. Cause:" + e.getMessage(), e); + throw new InstrumentException(variableName + " addTraceVariable fail. Cause:" + e.getMessage(), e); } catch (CannotCompileException e) { - throw new InstrumentException("addTraceVariable fail. Cause:" + e.getMessage(), e); + throw new InstrumentException(variableName + " addTraceVariable fail. Cause:" + e.getMessage(), e); } } @@ -172,11 +172,12 @@ public class JavaAssistClass implements InstrumentClass { String target = getTarget(behavior); String returnType = getReturnType(behavior); String parameterTypeString = JavaAssistUtils.getParameterDescription(behavior.getParameterTypes()); + String parameter = getParameter(behavior); CodeBuilder after = new CodeBuilder(); 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\", $args, %5$s);", target, ctClass.getName(), methodName, parameterTypeString, returnType); + 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)) { @@ -188,7 +189,7 @@ public class JavaAssistClass implements InstrumentClass { 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\", $args, $e);", target, ctClass.getName(), methodName, parameterTypeString); + 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(); @@ -222,13 +223,15 @@ public class JavaAssistClass implements InstrumentClass { private void addStaticBeforeInterceptor(String methodName, int id, CtBehavior behavior) throws CannotCompileException, NotFoundException { - CodeBuilder code = new CodeBuilder(); - code.begin(); - code.format(" %1$s interceptor = (%1$s) com.profiler.interceptor.InterceptorRegistry.getInterceptor(%2$d);", StaticBeforeInterceptor.class.getName(), id); String target = getTarget(behavior); // 인터셉터 호출시 최대한 연산량을 줄이기 위해서 정보는 가능한 정적 데이터로 생성한다. String parameterDescription = JavaAssistUtils.getParameterDescription(behavior.getParameterTypes()); - code.format(" interceptor.before(%1$s, \"%2$s\", \"%3$s\", \"%4$s\", $args);", target, ctClass.getName(), methodName, parameterDescription); + String parameter = getParameter(behavior); + + CodeBuilder code = new CodeBuilder(); + 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)) { @@ -242,7 +245,15 @@ public class JavaAssistClass implements InstrumentClass { } } - public boolean addDebugLogBeforeAfterMethod() { + private String getParameter(CtBehavior behavior) throws NotFoundException { + CtClass[] parameterTypes = behavior.getParameterTypes(); + if (parameterTypes.length == 0) { + return "null"; + } + return "$args"; + } + + public boolean addDebugLogBeforeAfterMethod() { String className = this.ctClass.getName(); LoggingInterceptor loggingInterceptor = new LoggingInterceptor(className); int id = InterceptorRegistry.addInterceptor(loggingInterceptor); diff --git a/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java b/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java index 26f02313e..ba91af0a3 100644 --- a/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java +++ b/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java @@ -30,6 +30,7 @@ import com.profiler.modifier.tomcat.TomcatStandardServiceModifier; public class DefaultModifierRegistry implements ModifierRegistry { // TODO 혹시 동시성을 고려 해야 되는지 검토. + // 왠간해서는 동시성 상황이 안나올것으로 보임. private Map registry = new HashMap(); private final ByteCodeInstrumentor byteCodeInstrumentor; @@ -102,7 +103,7 @@ public class DefaultModifierRegistry implements ModifierRegistry { } private void addMsSqlDriver() { - Map registry = this.registry; + Modifier mssqlConnectionModifier = new MSSQLConnectionModifier(byteCodeInstrumentor); addModifier(mssqlConnectionModifier); @@ -118,7 +119,7 @@ public class DefaultModifierRegistry implements ModifierRegistry { } private void addOracleDriver() { - Map registry = this.registry; + // TODO oracle의 경우 connection에 대한 impl이 없음. 확인필요. Modifier oraclePreparedStatementModifier = new OraclePreparedStatementModifier(byteCodeInstrumentor); addModifier(oraclePreparedStatementModifier); @@ -131,7 +132,7 @@ public class DefaultModifierRegistry implements ModifierRegistry { } private void addCubridDriver() { - Map registry = this.registry; + // TODO cubrid의 경우도 connection에 대한 impl이 없음. 확인필요. Modifier cubridStatementModifier = new CubridStatementModifier(byteCodeInstrumentor); addModifier(cubridStatementModifier); @@ -147,7 +148,7 @@ public class DefaultModifierRegistry implements ModifierRegistry { } private void addDbcpDriver() { - Map registry = this.registry; + // TODO cubrid의 경우도 connection에 대한 impl이 없음. 확인필요. Modifier dbcpBasicDataSourceModifier = new DBCPBasicDataSourceModifier(byteCodeInstrumentor); addModifier(dbcpBasicDataSourceModifier); diff --git a/src/main/java/com/profiler/modifier/db/mysql/interceptors/CloseConnectionInterceptor.java b/src/main/java/com/profiler/modifier/db/mysql/interceptors/CloseConnectionInterceptor.java index 472f2a444..17dba3a51 100644 --- a/src/main/java/com/profiler/modifier/db/mysql/interceptors/CloseConnectionInterceptor.java +++ b/src/main/java/com/profiler/modifier/db/mysql/interceptors/CloseConnectionInterceptor.java @@ -2,6 +2,7 @@ package com.profiler.modifier.db.mysql.interceptors; import com.profiler.interceptor.StaticBeforeInterceptor; import com.profiler.modifier.db.ConnectionTrace; +import com.profiler.util.StringUtils; import java.sql.Connection; import java.util.Arrays; @@ -14,7 +15,7 @@ public class CloseConnectionInterceptor implements StaticBeforeInterceptor { public void before(Object target, String className, String methodName, String parameterDescription, Object[] args) { if (logger.isLoggable(Level.INFO)) { - logger.info("before " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args)); + logger.info("before " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args)); } // close의 경우 호출이 실패하더라도 데이터를 삭제해야함. if (target instanceof Connection) { diff --git a/src/main/java/com/profiler/modifier/db/mysql/interceptors/CreateConnectionInterceptor.java b/src/main/java/com/profiler/modifier/db/mysql/interceptors/CreateConnectionInterceptor.java index 7215ed012..f4d6d565b 100644 --- a/src/main/java/com/profiler/modifier/db/mysql/interceptors/CreateConnectionInterceptor.java +++ b/src/main/java/com/profiler/modifier/db/mysql/interceptors/CreateConnectionInterceptor.java @@ -8,6 +8,7 @@ import java.util.logging.Logger; import com.profiler.interceptor.StaticAfterInterceptor; import com.profiler.modifier.db.ConnectionTrace; import com.profiler.util.InterceptorUtils; +import com.profiler.util.StringUtils; public class CreateConnectionInterceptor implements StaticAfterInterceptor { @@ -16,7 +17,7 @@ public class CreateConnectionInterceptor implements StaticAfterInterceptor { @Override public void after(Object target, String className, String methodName, String parameterDescription, Object[] args, Object result) { if (logger.isLoggable(Level.INFO)) { - logger.info("after " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args) + " result:" + result); + logger.info("after " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args) + " result:" + result); } if (!InterceptorUtils.isSuccess(result)) { return; diff --git a/src/main/java/com/profiler/modifier/db/mysql/interceptors/CreatePreparedStatementInterceptor.java b/src/main/java/com/profiler/modifier/db/mysql/interceptors/CreatePreparedStatementInterceptor.java index 9020a4d3a..19398e004 100644 --- a/src/main/java/com/profiler/modifier/db/mysql/interceptors/CreatePreparedStatementInterceptor.java +++ b/src/main/java/com/profiler/modifier/db/mysql/interceptors/CreatePreparedStatementInterceptor.java @@ -5,6 +5,7 @@ import com.profiler.interceptor.StaticAfterInterceptor; import com.profiler.modifier.db.ConnectionTrace; import com.profiler.util.InterceptorUtils; import com.profiler.util.MetaObject; +import com.profiler.util.StringUtils; import java.sql.Connection; import java.util.Arrays; @@ -20,7 +21,7 @@ public class CreatePreparedStatementInterceptor implements StaticAfterIntercepto @Override public void after(Object target, String className, String methodName, String parameterDescription, Object[] args, Object result) { if (logger.isLoggable(Level.INFO)) { - logger.info("after " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args) + " result:" + result); + logger.info("after " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args) + " result:" + result); } if(!InterceptorUtils.isSuccess(result)) { return; diff --git a/src/main/java/com/profiler/modifier/db/mysql/interceptors/CreateStatementInterceptor.java b/src/main/java/com/profiler/modifier/db/mysql/interceptors/CreateStatementInterceptor.java index e384bc997..98d8e5590 100644 --- a/src/main/java/com/profiler/modifier/db/mysql/interceptors/CreateStatementInterceptor.java +++ b/src/main/java/com/profiler/modifier/db/mysql/interceptors/CreateStatementInterceptor.java @@ -5,6 +5,7 @@ import com.profiler.interceptor.StaticAfterInterceptor; import com.profiler.modifier.db.ConnectionTrace; import com.profiler.util.InterceptorUtils; import com.profiler.util.MetaObject; +import com.profiler.util.StringUtils; import java.sql.Connection; import java.util.Arrays; @@ -20,7 +21,7 @@ public class CreateStatementInterceptor implements StaticAfterInterceptor { @Override public void after(Object target, String className, String methodName, String parameterDescription, Object[] args, Object result) { if (logger.isLoggable(Level.INFO)) { - logger.info("after " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args) + " result:" + result); + logger.info("after " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args) + " result:" + result); } if(!InterceptorUtils.isSuccess(result)) { return; diff --git a/src/main/java/com/profiler/modifier/db/mysql/interceptors/ExecuteQueryMethodInterceptor.java b/src/main/java/com/profiler/modifier/db/mysql/interceptors/ExecuteQueryMethodInterceptor.java index 4daf24aa8..60009adfa 100644 --- a/src/main/java/com/profiler/modifier/db/mysql/interceptors/ExecuteQueryMethodInterceptor.java +++ b/src/main/java/com/profiler/modifier/db/mysql/interceptors/ExecuteQueryMethodInterceptor.java @@ -4,7 +4,9 @@ import com.profiler.StopWatch; import com.profiler.context.Annotation; import com.profiler.context.Trace; import com.profiler.interceptor.StaticAroundInterceptor; +import com.profiler.util.InterceptorUtils; import com.profiler.util.MetaObject; +import com.profiler.util.StringUtils; import java.util.Arrays; import java.util.logging.Level; @@ -19,12 +21,12 @@ public class ExecuteQueryMethodInterceptor implements StaticAroundInterceptor { private final Logger logger = Logger.getLogger(ExecuteQueryMethodInterceptor.class.getName()); - private final MetaObject getUrl = new MetaObject("", "__getUrl"); + private final MetaObject getUrl = new MetaObject("", "__getUrl"); @Override public void before(Object target, String className, String methodName, String parameterDescription, Object[] args) { if (logger.isLoggable(Level.INFO)) { - logger.info("before " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args)); + logger.info("before " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args)); } if (Trace.getCurrentTraceId() == null) { @@ -58,7 +60,7 @@ public class ExecuteQueryMethodInterceptor implements StaticAroundInterceptor { @Override public void after(Object target, String className, String methodName, String parameterDescription, Object[] args, Object result) { if (logger.isLoggable(Level.INFO)) { - logger.info("after " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args) + " result:" + result); + logger.info("after " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args) + " result:" + result); } if (Trace.getCurrentTraceId() == null) { @@ -66,6 +68,7 @@ public class ExecuteQueryMethodInterceptor implements StaticAroundInterceptor { } Trace.traceBlockBegin(); + Trace.recordAttibute("Success", InterceptorUtils.isSuccess(result)); Trace.record(Annotation.ClientRecv, StopWatch.stopAndGetElapsed("ExecuteQueryMethodInterceptor")); Trace.traceBlockEnd(); } diff --git a/src/main/java/com/profiler/modifier/db/mysql/interceptors/PreparedStatementMethodInterceptor.java b/src/main/java/com/profiler/modifier/db/mysql/interceptors/PreparedStatementMethodInterceptor.java index c008ca5af..4e37080a5 100644 --- a/src/main/java/com/profiler/modifier/db/mysql/interceptors/PreparedStatementMethodInterceptor.java +++ b/src/main/java/com/profiler/modifier/db/mysql/interceptors/PreparedStatementMethodInterceptor.java @@ -1,10 +1,68 @@ package com.profiler.modifier.db.mysql.interceptors; +import com.mysql.jdbc.PreparedStatement; +import com.profiler.context.Annotation; +import com.profiler.context.Trace; import com.profiler.interceptor.StaticAfterInterceptor; +import com.profiler.interceptor.StaticAroundInterceptor; +import com.profiler.util.InterceptorUtils; +import com.profiler.util.MetaObject; +import com.profiler.util.StringUtils; + +import java.util.Arrays; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class PreparedStatementMethodInterceptor implements StaticAroundInterceptor { + + private final Logger logger = Logger.getLogger(PreparedStatementMethodInterceptor.class.getName()); + + private final MetaObject getSql = new MetaObject("__getSql"); + private final MetaObject getUrl = new MetaObject("__getUrl"); + + @Override + public void before(Object target, String className, String methodName, String parameterDescription, Object[] args) { + if (logger.isLoggable(Level.INFO)) { + logger.info("before " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args)); + } + if (Trace.getCurrentTraceId() == null) { + return; + } + Trace.traceBlockBegin(); + try { + String url = getUrl.invoke(target, null); + Trace.recordRpcName("mysql", url); + String sql = getSql.invoke(target, null); + Trace.recordAttibute("Query", sql); + Trace.record(Annotation.ClientSend); + } catch (Exception e) { + e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + } finally { + Trace.traceBlockEnd(); + } + + } -public class PreparedStatementMethodInterceptor implements StaticAfterInterceptor { @Override public void after(Object target, String className, String methodName, String parameterDescription, Object[] args, Object result) { - //To change body of implemented methods use File | Settings | File Templates. + if (logger.isLoggable(Level.INFO)) { + logger.info("after " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args) + " result:" + result); + } + if (Trace.getCurrentTraceId() == null) { + return; + } + + Trace.traceBlockBegin(); + try { + // TODO 일단 테스트로 실패일경우 종료 아닐경우 resultset fetch까지 계산. fetch count는 옵션으로 빼는게 좋을듯. + boolean success = InterceptorUtils.isSuccess(result); + Trace.recordAttibute("Success", success); + Trace.record(Annotation.ClientRecv); + } catch (Exception e) { + e.printStackTrace(); + } finally { + Trace.traceBlockEnd(); + } } + } diff --git a/src/main/java/com/profiler/util/MetaObject.java b/src/main/java/com/profiler/util/MetaObject.java index 7ef7f36d0..76961d0d5 100644 --- a/src/main/java/com/profiler/util/MetaObject.java +++ b/src/main/java/com/profiler/util/MetaObject.java @@ -2,11 +2,10 @@ package com.profiler.util; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; -public class MetaObject { +public class MetaObject { private final Logger logger = Logger.getLogger(MetaObject.class.getName()); @@ -15,20 +14,20 @@ public class MetaObject { // 이것을 class loading시 정적 타임에서 생성해 둘수 없는가? private Method methodRef; - private Object defaultReturnValue = null; + private R defaultReturnValue = null; public MetaObject(String methodName, Class... args) { this.methodName = methodName; this.args = args; } - public MetaObject(Object defaultReturnValue, String methodName, Class... args) { + public MetaObject(R defaultReturnValue, String methodName, Class... args) { this.methodName = methodName; this.args = args; this.defaultReturnValue = defaultReturnValue; } - public Object invoke(Object target, Object... args) { + public R invoke(Object target, Object... args) { if (target == null) { return defaultReturnValue; } @@ -43,12 +42,12 @@ public class MetaObject { return invoke(method, target, args); } - private Object invoke(Method method, Object target, Object[] args) { + private R invoke(Method method, Object target, Object[] args) { if (method == null) { return defaultReturnValue; } try { - return method.invoke(target, args); + return (R) method.invoke(target, args); } catch (IllegalAccessException e) { logger.log(Level.WARNING, "invoke fail", e); return defaultReturnValue; @@ -60,9 +59,9 @@ public class MetaObject { private Method getMethod(Class aClass) { try { - return aClass.getDeclaredMethod(this.methodName, this.args); + return aClass.getMethod(this.methodName, this.args); } catch (NoSuchMethodException e) { - logger.warning(this.methodName + Arrays.toString(this.args) + " not found cls:" + aClass); + logger.warning(this.methodName + JavaAssistUtils.getParameterDescription(this.args) + " not found cls:" + aClass); return null; } } diff --git a/src/test/java/com/profiler/interceptor/bci/JavaAssistClassTest.java b/src/test/java/com/profiler/interceptor/bci/JavaAssistClassTest.java index cabb4b7be..f28adca9f 100644 --- a/src/test/java/com/profiler/interceptor/bci/JavaAssistClassTest.java +++ b/src/test/java/com/profiler/interceptor/bci/JavaAssistClassTest.java @@ -34,7 +34,7 @@ public class JavaAssistClassTest { Assert.assertEquals(interceptor.call, 1); Assert.assertEquals(interceptor.className, "com.profiler.interceptor.bci.TestObject"); Assert.assertEquals(interceptor.methodName, methodName); - Assert.assertEquals(interceptor.args.length, 0); + Assert.assertEquals(interceptor.args, null); Assert.assertEquals(interceptor.target, testObject); } @@ -62,7 +62,7 @@ public class JavaAssistClassTest { Assert.assertEquals(callaInterceptor.call, 1); Assert.assertEquals(callaInterceptor.className, "com.profiler.interceptor.bci.TestObject2"); Assert.assertEquals(callaInterceptor.methodName, callA); - Assert.assertEquals(callaInterceptor.args.length, 0); + Assert.assertNull(callaInterceptor.args); Assert.assertEquals(callaInterceptor.target, testObject); Assert.assertEquals(callaInterceptor.result, result); @@ -72,7 +72,7 @@ public class JavaAssistClassTest { Assert.assertEquals(callbInterceptor.call, 1); Assert.assertEquals(callbInterceptor.className, "com.profiler.interceptor.bci.TestObject2"); Assert.assertEquals(callbInterceptor.methodName, callB); - Assert.assertEquals(callbInterceptor.args.length, 0); + Assert.assertNull(callbInterceptor.args); Assert.assertEquals(callbInterceptor.target, testObject); Assert.assertNull(callbInterceptor.result); diff --git a/src/test/java/com/profiler/interceptor/bci/MethodRenameInterceptorTest.java b/src/test/java/com/profiler/interceptor/bci/MethodRenameInterceptorTest.java index ebe502a34..614aecf86 100644 --- a/src/test/java/com/profiler/interceptor/bci/MethodRenameInterceptorTest.java +++ b/src/test/java/com/profiler/interceptor/bci/MethodRenameInterceptorTest.java @@ -21,7 +21,7 @@ public class MethodRenameInterceptorTest { } else { // add timing interceptor to the class addTiming(clas, methodName); - clas.writeFile(); + clas.writeFile("debug"); System.out.println("Added timing to method " + objectName + "." + methodName); }