diff --git a/.classpath b/.classpath index 62f65cbc9..adedb8f77 100644 --- a/.classpath +++ b/.classpath @@ -6,15 +6,19 @@ - + + - - + + + + + diff --git a/pom.xml b/pom.xml index 4c44274e3..91a3db812 100644 --- a/pom.xml +++ b/pom.xml @@ -59,6 +59,18 @@ 3.16.1-GA compile + + com.nhncorp.lucy + lucy-npc + 1.5.10 + compile + + + org.apache.httpcomponents + httpclient + 4.0.3 + compile + diff --git a/src/main/java/com/profiler/TomcatProfiler.java b/src/main/java/com/profiler/TomcatProfiler.java index 074cb1d13..1691e37bd 100644 --- a/src/main/java/com/profiler/TomcatProfiler.java +++ b/src/main/java/com/profiler/TomcatProfiler.java @@ -59,6 +59,7 @@ public class TomcatProfiler implements ClassFileTransformer { if (tomcatProfilerConfig.enableJdbcProfile()) { modifierRepository.addJdbcModifier(); } + modifierRepository.addConnectorModifier(); return modifierRepository; } diff --git a/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java b/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java index 28bb04e3d..b355bee53 100644 --- a/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java +++ b/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java @@ -4,7 +4,7 @@ import java.util.HashMap; import java.util.Map; import com.profiler.interceptor.bci.ByteCodeInstrumentor; - +import com.profiler.modifier.connector.HTTPClientModifier; import com.profiler.modifier.db.cubrid.CubridPreparedStatementModifier; import com.profiler.modifier.db.cubrid.CubridResultSetModifier; import com.profiler.modifier.db.cubrid.CubridStatementModifier; @@ -42,12 +42,17 @@ public class DefaultModifierRegistry implements ModifierRegistry { return registry.get(className); } - private void addModifier(Modifier modifier) { - Modifier old = registry.put(modifier.getTargetClass(), modifier); - if (old != null) { - throw new IllegalStateException("Modifier already exist new:" + modifier.getClass() + " old:" + old.getTargetClass()); - } - } + private void addModifier(Modifier modifier) { + Modifier old = registry.put(modifier.getTargetClass(), modifier); + if (old != null) { + throw new IllegalStateException("Modifier already exist new:" + modifier.getClass() + " old:" + old.getTargetClass()); + } + } + + public void addConnectorModifier() { + HTTPClientModifier httpClientModifier = new HTTPClientModifier(byteCodeInstrumentor); + addModifier(httpClientModifier); + } public void addTomcatModifier() { Modifier entryPointStandardHostValveModifier = new EntryPointStandardHostValveModifier(byteCodeInstrumentor); diff --git a/src/main/java/com/profiler/modifier/connector/HTTPClientModifier.java b/src/main/java/com/profiler/modifier/connector/HTTPClientModifier.java new file mode 100644 index 000000000..7749081bc --- /dev/null +++ b/src/main/java/com/profiler/modifier/connector/HTTPClientModifier.java @@ -0,0 +1,63 @@ +package com.profiler.modifier.connector; + +import java.security.ProtectionDomain; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javassist.ByteArrayClassPath; + +import com.profiler.interceptor.Interceptor; +import com.profiler.interceptor.bci.ByteCodeInstrumentor; +import com.profiler.interceptor.bci.InstrumentClass; +import com.profiler.modifier.AbstractModifier; + +/** + * Apache httpclient modifier + * + *
+ * http://grepcode.com/file/repo1.maven.org/maven2/org.apache.httpcomponents/httpclient/4.0.3/org/apache/http/impl/client/AbstractHttpClient.java#AbstractHttpClient.execute%28org.apache.http.HttpHost%2Corg.apache.http.HttpRequest%2Corg.apache.http.client.ResponseHandler%2Corg.apache.http.protocol.HttpContext%29
+ * 
+ * Hooking
+ * org.apache.http.impl.client.AbstractHttpClient.
+ * public  T execute(
+ *            final HttpHost target, 
+ *            final HttpRequest request,
+ *            final ResponseHandler responseHandler, 
+ *            final HttpContext context) 
+ *            throws IOException, ClientProtocolException {
+ * 
+ * + * @author netspider + * + */ +public class HTTPClientModifier extends AbstractModifier { + + private final Logger logger = Logger.getLogger(HTTPClientModifier.class.getName()); + + public HTTPClientModifier(ByteCodeInstrumentor byteCodeInstrumentor) { + super(byteCodeInstrumentor); + } + + public String getTargetClass() { + return "org/apache/http/impl/client/AbstractHttpClient"; + } + + public byte[] modify(ClassLoader classLoader, String javassistClassName, ProtectionDomain protectedDomain, byte[] classFileBuffer) { + if (logger.isLoggable(Level.INFO)) { + logger.info("Modifing. " + javassistClassName); + } + + Interceptor interceptor = newInterceptor(classLoader, protectedDomain, "com.profiler.modifier.connector.interceptors.ExecuteMethodInterceptor"); + if (interceptor == null) { + return null; + } + + byteCodeInstrumentor.checkLibrary(classLoader, javassistClassName); + classPool.insertClassPath(new ByteArrayClassPath(javassistClassName, classFileBuffer)); + + InstrumentClass aClass = byteCodeInstrumentor.getClass(javassistClassName); + aClass.addInterceptor("execute", new String[] { "org.apache.http.HttpHost", "org.apache.http.HttpRequest", "org.apache.http.client.ResponseHandler", "org.apache.http.protocol.HttpContext" }, interceptor); + + return aClass.toBytecode(); + } +} \ No newline at end of file diff --git a/src/main/java/com/profiler/modifier/connector/interceptors/ExecuteMethodInterceptor.java b/src/main/java/com/profiler/modifier/connector/interceptors/ExecuteMethodInterceptor.java new file mode 100644 index 000000000..15846a7aa --- /dev/null +++ b/src/main/java/com/profiler/modifier/connector/interceptors/ExecuteMethodInterceptor.java @@ -0,0 +1,43 @@ +package com.profiler.modifier.connector.interceptors; + +import com.profiler.interceptor.StaticAroundInterceptor; + +/** + * Method interceptor + * + *
+ * org.apache.http.impl.client.AbstractHttpClient.
+ * public  T execute(
+ *            final HttpHost target, 
+ *            final HttpRequest request,
+ *            final ResponseHandler responseHandler, 
+ *            final HttpContext context) 
+ *            throws IOException, ClientProtocolException {
+ * 
+ */ +public class ExecuteMethodInterceptor implements StaticAroundInterceptor { + + /** + *
+	 * args is...
+	 * 
+	 * org.apache.http.impl.client.AbstractHttpClient.
+	 * public  T execute(
+	 *            final HttpHost target, 
+	 *            final HttpRequest request,
+	 *            final ResponseHandler responseHandler, 
+	 *            final HttpContext context) 
+	 *            throws IOException, ClientProtocolException {
+	 * 
+ */ + @Override + public void before(Object target, String className, String methodName, Object[] args) { + System.out.println("\n\n\n\nHTTP BEFORE"); + // TODO : add header + } + + @Override + public void after(Object target, String className, String methodName, Object[] args, Object result) { + System.out.println("\n\n\n\nHTTP AFTER"); + } +} \ No newline at end of file diff --git a/src/main/java/com/profiler/modifier/db/mysql/MySQLStatementModifier.java b/src/main/java/com/profiler/modifier/db/mysql/MySQLStatementModifier.java index 4e9816fc4..fa96a6e4a 100644 --- a/src/main/java/com/profiler/modifier/db/mysql/MySQLStatementModifier.java +++ b/src/main/java/com/profiler/modifier/db/mysql/MySQLStatementModifier.java @@ -5,11 +5,15 @@ import java.util.logging.Level; import java.util.logging.Logger; import javassist.ByteArrayClassPath; +import javassist.CtClass; +import javassist.CtMethod; +import com.profiler.config.TomcatProfilerConstant; import com.profiler.interceptor.Interceptor; import com.profiler.interceptor.bci.ByteCodeInstrumentor; import com.profiler.interceptor.bci.InstrumentClass; import com.profiler.modifier.AbstractModifier; +import com.profiler.trace.DatabaseRequestTracer; public class MySQLStatementModifier extends AbstractModifier { @@ -45,37 +49,36 @@ public class MySQLStatementModifier extends AbstractModifier { // return changeMethod(javassistClassName, classFileBuffer); } - // private byte[] changeMethod(String javassistClassName, byte[] - // classfileBuffer) { - // try { - // CtClass cc = classPool.get(javassistClassName); - // - // updateExecuteQueryMethod(cc); - // - // printClassConvertComplete(javassistClassName); - // - // return cc.toBytecode(); - // } catch (Exception e) { - // if (logger.isLoggable(Level.WARNING)) { - // logger.log(Level.WARNING, e.getMessage(), e); - // } - // } - // return null; - // } - // - // private void updateExecuteQueryMethod(CtClass cc) throws Exception { - // CtClass[] params = new CtClass[1]; - // params[0] = classPool.getCtClass("java.lang.String"); - // CtMethod method = cc.getDeclaredMethod("executeQuery", params); - // - // StringBuilder sb = new StringBuilder(); - // sb.append("{"); - // sb.append(DatabaseRequestTracer.FQCN + ".putSqlQuery(" + - // TomcatProfilerConstant.REQ_DATA_TYPE_DB_QUERY + ",$1);"); - // sb.append(DatabaseRequestTracer.FQCN + ".put(" + - // TomcatProfilerConstant.REQ_DATA_TYPE_DB_EXECUTE_QUERY + ");"); - // sb.append("}"); - // - // method.insertAfter(sb.toString()); - // } + @Deprecated + private byte[] changeMethod(String javassistClassName, byte[] classfileBuffer) { + try { + CtClass cc = classPool.get(javassistClassName); + + updateExecuteQueryMethod(cc); + + printClassConvertComplete(javassistClassName); + + return cc.toBytecode(); + } catch (Exception e) { + if (logger.isLoggable(Level.WARNING)) { + logger.log(Level.WARNING, e.getMessage(), e); + } + } + return null; + } + + @Deprecated + private void updateExecuteQueryMethod(CtClass cc) throws Exception { + CtClass[] params = new CtClass[1]; + params[0] = classPool.getCtClass("java.lang.String"); + CtMethod method = cc.getDeclaredMethod("executeQuery", params); + + StringBuilder sb = new StringBuilder(); + sb.append("{"); + sb.append(DatabaseRequestTracer.FQCN + ".putSqlQuery(" + TomcatProfilerConstant.REQ_DATA_TYPE_DB_QUERY + ",$1);"); + sb.append(DatabaseRequestTracer.FQCN + ".put(" + TomcatProfilerConstant.REQ_DATA_TYPE_DB_EXECUTE_QUERY + ");"); + sb.append("}"); + + method.insertAfter(sb.toString()); + } } \ No newline at end of file