mirror of
https://github.com/wahyd4/pinpoint.git
synced 2026-08-19 01:35:58 +10:00
[강운덕] [LUCYSUS-1744] oracle jdbc 프로파일링 추가 - statment도 구현해야 함.
git-svn-id: http://svn.bds.nhncorp.com/pe/hippo-tomcat-profiler/trunk@1728 84d0f5b1-2673-498c-a247-62c4ff18d310
This commit is contained in:
@@ -29,9 +29,7 @@ import com.profiler.modifier.db.mysql.MySQLNonRegisteringDriverModifier;
|
||||
import com.profiler.modifier.db.mysql.MySQLPreparedStatementJDBC4Modifier;
|
||||
import com.profiler.modifier.db.mysql.MySQLPreparedStatementModifier;
|
||||
import com.profiler.modifier.db.mysql.MySQLStatementModifier;
|
||||
import com.profiler.modifier.db.oracle.OraclePreparedStatementModifier;
|
||||
import com.profiler.modifier.db.oracle.OracleResultSetModifier;
|
||||
import com.profiler.modifier.db.oracle.OracleStatementModifier;
|
||||
import com.profiler.modifier.db.oracle.*;
|
||||
import com.profiler.modifier.method.MethodModifier;
|
||||
import com.profiler.modifier.servlet.FilterModifier;
|
||||
import com.profiler.modifier.servlet.HttpServletModifier;
|
||||
@@ -189,16 +187,20 @@ public class DefaultModifierRegistry implements ModifierRegistry {
|
||||
}
|
||||
|
||||
private void addOracleDriver() {
|
||||
Modifier oracleDriverModifier = new OracleDriverModifier(byteCodeInstrumentor, agent);
|
||||
addModifier(oracleDriverModifier);
|
||||
|
||||
// TODO oracle의 경우 connection에 대한 impl이 없음. 확인필요.
|
||||
Modifier mssqlConnectionModifier = new PhysicalConnectionModifier(byteCodeInstrumentor, agent);
|
||||
addModifier(mssqlConnectionModifier);
|
||||
//
|
||||
Modifier oraclePreparedStatementModifier = new OraclePreparedStatementModifier(byteCodeInstrumentor, agent);
|
||||
addModifier(oraclePreparedStatementModifier);
|
||||
|
||||
Modifier oracleStatement = new OracleStatementModifier(byteCodeInstrumentor, agent);
|
||||
addModifier(oracleStatement);
|
||||
|
||||
Modifier oracleResultSetModifier = new OracleResultSetModifier(byteCodeInstrumentor, agent);
|
||||
addModifier(oracleResultSetModifier);
|
||||
//
|
||||
// Modifier oracleStatement = new OracleStatementModifier(byteCodeInstrumentor, agent);
|
||||
// addModifier(oracleStatement);
|
||||
//
|
||||
// Modifier oracleResultSetModifier = new OracleResultSetModifier(byteCodeInstrumentor, agent);
|
||||
// addModifier(oracleResultSetModifier);
|
||||
}
|
||||
|
||||
private void addCubridDriver() {
|
||||
|
||||
+2
@@ -68,6 +68,8 @@ public class PreparedStatementExecuteQueryInterceptor implements SimpleAroundInt
|
||||
trace.recordApi(descriptor);
|
||||
// trace.recordApi(apiId);
|
||||
// clean 타이밍을 변경해야 될듯 하다.
|
||||
// clearParameters api가 따로 있으나, 구지 캡쳐 하지 않아도 될듯함.시간남으면 하면 좋기는 함.
|
||||
// ibatis 등에서 확인해봐도 cleanParameters 의 경우 대부분의 경우 일부러 호출하지 않음.
|
||||
clean(target);
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.profiler.modifier.db.oracle;
|
||||
|
||||
import com.profiler.Agent;
|
||||
import com.profiler.interceptor.Interceptor;
|
||||
import com.profiler.interceptor.bci.ByteCodeInstrumentor;
|
||||
import com.profiler.interceptor.bci.InstrumentClass;
|
||||
import com.profiler.interceptor.bci.InstrumentException;
|
||||
import com.profiler.logging.Logger;
|
||||
import com.profiler.logging.LoggerFactory;
|
||||
import com.profiler.modifier.AbstractModifier;
|
||||
import com.profiler.modifier.db.interceptor.DriverConnectInterceptor;
|
||||
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class OracleDriverModifier extends AbstractModifier {
|
||||
|
||||
// oracle.jdbc.driver
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
public OracleDriverModifier(ByteCodeInstrumentor byteCodeInstrumentor, Agent agent) {
|
||||
super(byteCodeInstrumentor, agent);
|
||||
}
|
||||
|
||||
public String getTargetClass() {
|
||||
return "oracle/jdbc/driver/OracleDriver";
|
||||
}
|
||||
|
||||
public byte[] modify(ClassLoader classLoader, String javassistClassName, ProtectionDomain protectedDomain, byte[] classFileBuffer) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Modifing. " + javassistClassName);
|
||||
}
|
||||
this.byteCodeInstrumentor.checkLibrary(classLoader, javassistClassName);
|
||||
try {
|
||||
InstrumentClass mysqlConnection = byteCodeInstrumentor.getClass(javassistClassName);
|
||||
|
||||
|
||||
Interceptor createConnection = new DriverConnectInterceptor();
|
||||
String[] params = new String[]{
|
||||
"java.lang.String", "java.util.Properties"
|
||||
};
|
||||
mysqlConnection.addInterceptor("connect", params, createConnection);
|
||||
|
||||
printClassConvertComplete(javassistClassName);
|
||||
|
||||
return mysqlConnection.toBytecode();
|
||||
} catch (InstrumentException e) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(this.getClass().getSimpleName() + " modify fail. Cause:" + e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
-57
@@ -1,89 +1,89 @@
|
||||
package com.profiler.modifier.db.oracle;
|
||||
|
||||
import com.profiler.Agent;
|
||||
import com.profiler.DefaultAgent;
|
||||
import com.profiler.config.ProfilerConstant;
|
||||
import com.profiler.interceptor.Interceptor;
|
||||
import com.profiler.interceptor.bci.ByteCodeInstrumentor;
|
||||
import com.profiler.interceptor.bci.InstrumentClass;
|
||||
import com.profiler.interceptor.bci.InstrumentException;
|
||||
import com.profiler.interceptor.bci.NotFoundInstrumentException;
|
||||
import com.profiler.logging.Logger;
|
||||
import com.profiler.logging.LoggerFactory;
|
||||
import com.profiler.modifier.AbstractModifier;
|
||||
import com.profiler.trace.DatabaseRequestTracer;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtConstructor;
|
||||
import javassist.CtMethod;
|
||||
import com.profiler.modifier.db.interceptor.PreparedStatementBindVariableInterceptor;
|
||||
import com.profiler.modifier.db.interceptor.PreparedStatementExecuteQueryInterceptor;
|
||||
import com.profiler.util.JavaAssistUtils;
|
||||
import com.profiler.util.PreparedStatementUtils;
|
||||
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.ProtectionDomain;
|
||||
import com.profiler.logging.Logger;
|
||||
import java.util.List;
|
||||
|
||||
public class OraclePreparedStatementModifier extends AbstractModifier {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(OraclePreparedStatementModifier.class);
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
public OraclePreparedStatementModifier(ByteCodeInstrumentor byteCodeInstrumentor, Agent agent) {
|
||||
super(byteCodeInstrumentor, agent);
|
||||
}
|
||||
|
||||
public String getTargetClass() {
|
||||
return "oracle/jdbc/driver/OraclePreparedStatement";
|
||||
return "oracle/jdbc/driver/OraclePreparedStatementWrapper";
|
||||
}
|
||||
|
||||
public byte[] modify(ClassLoader classLoader, String javassistClassName, ProtectionDomain protectedDomain, byte[] classFileBuffer) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Modifing. " + javassistClassName);
|
||||
}
|
||||
|
||||
this.byteCodeInstrumentor.checkLibrary(classLoader, javassistClassName);
|
||||
return changeMethod(javassistClassName, classFileBuffer);
|
||||
}
|
||||
|
||||
private byte[] changeMethod(String javassistClassName, byte[] classfileBuffer) {
|
||||
try {
|
||||
CtClass cc = null;
|
||||
updateSetInternalMethod(cc);
|
||||
updateExecuteMethod(cc);
|
||||
updateConstructor(cc);
|
||||
InstrumentClass preparedStatement = byteCodeInstrumentor.getClass(javassistClassName);
|
||||
|
||||
printClassConvertComplete(javassistClassName);
|
||||
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);
|
||||
|
||||
return cc.toBytecode();
|
||||
} catch (Exception e) {
|
||||
preparedStatement.addTraceVariable("__url", "__setUrl", "__getUrl", "java.lang.Object");
|
||||
preparedStatement.addTraceVariable("__sql", "__setSql", "__getSql", "java.lang.Object");
|
||||
|
||||
preparedStatement.addTraceVariable("__bindValue", "__setBindValue", "__getBindValue", "java.util.Map", "java.util.Collections.synchronizedMap(new java.util.HashMap());");
|
||||
bindVariableIntercept(preparedStatement, classLoader, protectedDomain);
|
||||
|
||||
return preparedStatement.toBytecode();
|
||||
} catch (InstrumentException e) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
logger.warn(this.getClass().getSimpleName() + " modify fail. Cause:" + e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void bindVariableIntercept(InstrumentClass preparedStatement, ClassLoader classLoader, ProtectionDomain protectedDomain) throws InstrumentException {
|
||||
List<Method> bindMethod = PreparedStatementUtils.findBindVariableSetMethod();
|
||||
|
||||
Interceptor interceptor = new PreparedStatementBindVariableInterceptor();
|
||||
int interceptorId = -1;
|
||||
for (Method method : bindMethod) {
|
||||
String methodName = method.getName();
|
||||
String[] parameterType = JavaAssistUtils.getParameterType(method.getParameterTypes());
|
||||
try {
|
||||
if (interceptorId == -1) {
|
||||
interceptorId = preparedStatement.addInterceptor(methodName, parameterType, interceptor);
|
||||
} else {
|
||||
preparedStatement.reuseInterceptor(methodName, parameterType, interceptorId);
|
||||
}
|
||||
} catch (NotFoundInstrumentException e) {
|
||||
// bind variable setter메소드를 못찾을 경우는 그냥 경고만 표시, 에러 아님.
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("bindVariable api not found. Cause:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
private void updateSetInternalMethod(CtClass cc) throws Exception {
|
||||
CtClass[] params1 = new CtClass[2];
|
||||
params1[0] = null;
|
||||
params1[1] = null;
|
||||
CtMethod serviceMethod1 = cc.getDeclaredMethod("setStringInternal", params1);
|
||||
|
||||
serviceMethod1.insertBefore("{" + DatabaseRequestTracer.FQCN + ".putSqlParam($1,$2); }");
|
||||
|
||||
// CtClass[] params2 = new CtClass[2];
|
||||
// params2[0] = classPool.getCtClass("int");
|
||||
// params2[1] = classPool.getCtClass("byte[]");
|
||||
// CtMethod serviceMethod2 = cc.getDeclaredMethod("setInternal",
|
||||
// params2);
|
||||
//
|
||||
// serviceMethod2.insertBefore("{" +
|
||||
// RequestDataTracer.FQCN +
|
||||
// ".putSqlParam($1,$2); {");
|
||||
}
|
||||
|
||||
private void updateConstructor(CtClass cc) throws Exception {
|
||||
CtConstructor[] constructorList = cc.getConstructors();
|
||||
|
||||
for (CtConstructor constructor : constructorList) {
|
||||
CtClass params[] = constructor.getParameterTypes();
|
||||
if (params.length == 6) {
|
||||
constructor.insertBefore("{" + DatabaseRequestTracer.FQCN + ".putSqlQuery(" + ProfilerConstant.REQ_DATA_TYPE_DB_QUERY + ",$2); }");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateExecuteMethod(CtClass cc) throws Exception {
|
||||
CtMethod method = cc.getDeclaredMethod("execute", null);
|
||||
method.insertAfter("{" + DatabaseRequestTracer.FQCN + ".put(" + ProfilerConstant.REQ_DATA_TYPE_DB_EXECUTE_QUERY + "); }");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.profiler.modifier.db.oracle;
|
||||
|
||||
import com.profiler.Agent;
|
||||
import com.profiler.interceptor.Interceptor;
|
||||
import com.profiler.interceptor.bci.ByteCodeInstrumentor;
|
||||
import com.profiler.interceptor.bci.InstrumentClass;
|
||||
import com.profiler.interceptor.bci.InstrumentException;
|
||||
import com.profiler.interceptor.bci.Type;
|
||||
import com.profiler.logging.Logger;
|
||||
import com.profiler.logging.LoggerFactory;
|
||||
import com.profiler.modifier.AbstractModifier;
|
||||
import com.profiler.modifier.db.interceptor.ConnectionCloseInterceptor;
|
||||
import com.profiler.modifier.db.interceptor.PreparedStatementCreateInterceptor;
|
||||
import com.profiler.modifier.db.interceptor.StatementCreateInterceptor;
|
||||
import com.profiler.modifier.db.interceptor.TransactionInterceptor;
|
||||
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
public class PhysicalConnectionModifier extends AbstractModifier {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
public PhysicalConnectionModifier(ByteCodeInstrumentor byteCodeInstrumentor, Agent agent) {
|
||||
super(byteCodeInstrumentor, agent);
|
||||
}
|
||||
|
||||
public String getTargetClass() {
|
||||
// T4C , T2C (OCI: T2C를 상속해서 만듬) 의 최상위 구현체가 있으나,
|
||||
// 해당 클래스는 PhysicalConnection 를 base로 하므로 PhysicalConnection 만 해도 될듯하다.
|
||||
return "oracle/jdbc/driver/PhysicalConnection";
|
||||
}
|
||||
|
||||
public byte[] modify(ClassLoader classLoader, String javassistClassName, ProtectionDomain protectedDomain, byte[] classFileBuffer) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Modifing. " + javassistClassName);
|
||||
}
|
||||
this.byteCodeInstrumentor.checkLibrary(classLoader, javassistClassName);
|
||||
try {
|
||||
InstrumentClass oracleConnection = byteCodeInstrumentor.getClass(javassistClassName);
|
||||
|
||||
|
||||
oracleConnection.addTraceVariable("__url", "__setUrl", "__getUrl", "java.lang.Object");
|
||||
|
||||
// 해당 Interceptor를 공통클래스 만들경우 system에 로드해야 된다.
|
||||
// Interceptor createConnection = new ConnectionCreateInterceptor();
|
||||
// String[] params = new String[] {
|
||||
// "java.lang.String", "int", "java.util.Properties", "java.lang.String", "java.lang.String"
|
||||
// };
|
||||
// mysqlConnection.addInterceptor("getInstance", params, createConnection);
|
||||
|
||||
|
||||
Interceptor closeConnection = new ConnectionCloseInterceptor();
|
||||
oracleConnection.addInterceptor("close", null, closeConnection, Type.before);
|
||||
|
||||
Interceptor createStatement = new StatementCreateInterceptor();
|
||||
oracleConnection.addInterceptor("createStatement", null, createStatement, Type.after);
|
||||
|
||||
|
||||
Interceptor preparedStatement = new PreparedStatementCreateInterceptor();
|
||||
oracleConnection.addInterceptor("prepareStatement", new String[]{"java.lang.String"}, preparedStatement);
|
||||
|
||||
|
||||
Interceptor setAutocommit = new TransactionInterceptor();
|
||||
oracleConnection.addInterceptor("setAutoCommit", new String[]{"boolean"}, setAutocommit);
|
||||
Interceptor commit = new TransactionInterceptor();
|
||||
oracleConnection.addInterceptor("commit", null, commit);
|
||||
Interceptor rollback = new TransactionInterceptor();
|
||||
oracleConnection.addInterceptor("rollback", null, rollback);
|
||||
|
||||
printClassConvertComplete(javassistClassName);
|
||||
|
||||
return oracleConnection.toBytecode();
|
||||
} catch (InstrumentException e) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(this.getClass().getSimpleName() + " modify fail. Cause:" + e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+6
-3
@@ -18,12 +18,13 @@ import com.profiler.util.NumberUtils;
|
||||
|
||||
public class StandardHostValveInvokeInterceptor implements SimpleAroundInterceptor, ByteCodeMethodDescriptorSupport, TraceContextSupport {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(StandardHostValveInvokeInterceptor.class.getName());
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
private final boolean isDebug = logger.isInfoEnabled();
|
||||
|
||||
private MethodDescriptor descriptor;
|
||||
|
||||
private TraceContext traceContext;
|
||||
// private ContainerAcceptor acceptor = new ContainerAcceptor(logger, ServiceType.TOMCAT);
|
||||
|
||||
@Override
|
||||
public void before(Object target, Object[] args) {
|
||||
@@ -37,6 +38,8 @@ public class StandardHostValveInvokeInterceptor implements SimpleAroundIntercept
|
||||
HttpServletRequest request = (HttpServletRequest) args[0];
|
||||
String requestURL = request.getRequestURI();
|
||||
String remoteAddr = request.getRemoteAddr();
|
||||
String port = Integer.toString(request.getServerPort());
|
||||
String endPoint = request.getServerName() + ":" + port;
|
||||
|
||||
// remote call에 sampling flag가 설정되어있을 경우는 샘플링 대상으로 삼지 않는다.
|
||||
boolean sampling = samplingEnable(request);
|
||||
@@ -83,8 +86,8 @@ public class StandardHostValveInvokeInterceptor implements SimpleAroundIntercept
|
||||
trace.recordServiceType(ServiceType.TOMCAT);
|
||||
trace.recordRpcName(requestURL);
|
||||
|
||||
int port = request.getServerPort();
|
||||
trace.recordEndPoint(request.getServerName() + ((port > 0) ? ":" + port : ""));
|
||||
|
||||
trace.recordEndPoint(endPoint);
|
||||
trace.recordRemoteAddr(remoteAddr);
|
||||
|
||||
// 서버 맵을 통계정보에서 조회하려면 remote로 호출되는 WAS의 관계를 알아야해서 부모의 application name을 전달받음.
|
||||
|
||||
Reference in New Issue
Block a user