diff --git a/src/main/java/com/profiler/context/AsyncTrace.java b/src/main/java/com/profiler/context/AsyncTrace.java index 037060ed1..3fbd4f4ad 100644 --- a/src/main/java/com/profiler/context/AsyncTrace.java +++ b/src/main/java/com/profiler/context/AsyncTrace.java @@ -14,6 +14,8 @@ import java.util.logging.Logger; */ public class AsyncTrace { private Logger logger = Logger.getLogger(this.getClass().getName()); + + public static final int NON_REGIST = -1; // 일단 c&p private static final AnnotationTranscoder transcoder = new AnnotationTranscoder(); // private int id; @@ -24,9 +26,10 @@ public class AsyncTrace { public static final int STATE_FIRE = 1; public static final int STATE_TIMEOUT = 2; + private final AtomicInteger state = new AtomicInteger(STATE_INIT); - private int asyncId; + private int asyncId = NON_REGIST; private Span span; private DataSender dataSender; private TimerTask timeoutTask; @@ -157,14 +160,14 @@ public class AsyncTrace { } public void timeout() { - if (state.compareAndSet(0, STATE_TIMEOUT)) { + if (state.compareAndSet(STATE_INIT, STATE_TIMEOUT)) { // TODO timeout span log 던지기. // 뭘 어떤 내용을 던져야 되는지 아직 모르겠음???? } } public boolean fire() { - if (state.compareAndSet(0, STATE_FIRE)) { + if (state.compareAndSet(STATE_INIT, STATE_FIRE)) { if (timeoutTask != null) { // timeout이 걸려 있는 asynctrace일 경우 호출해 준다. this.timeoutTask.cancel(); diff --git a/src/main/java/com/profiler/modifier/db/interceptor/DriverConnectInterceptor.java b/src/main/java/com/profiler/modifier/db/interceptor/DriverConnectInterceptor.java index b46391fa6..1a269d5d6 100644 --- a/src/main/java/com/profiler/modifier/db/interceptor/DriverConnectInterceptor.java +++ b/src/main/java/com/profiler/modifier/db/interceptor/DriverConnectInterceptor.java @@ -1,12 +1,15 @@ package com.profiler.modifier.db.interceptor; -import com.profiler.interceptor.StaticAfterInterceptor; +import com.profiler.context.Annotation; +import com.profiler.context.Trace; +import com.profiler.context.TraceContext; import com.profiler.interceptor.StaticAroundInterceptor; +import com.profiler.modifier.db.util.DatabaseInfo; +import com.profiler.modifier.db.util.JDBCUrlParser; import com.profiler.util.InterceptorUtils; import com.profiler.util.MetaObject; import com.profiler.util.StringUtils; -import java.sql.Connection; import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; @@ -17,7 +20,9 @@ import java.util.logging.Logger; public class DriverConnectInterceptor implements StaticAroundInterceptor { private final Logger logger = Logger.getLogger(DriverConnectInterceptor.class.getName()); - private final MetaObject setUrl = new MetaObject("__setUrl", String.class); + private final MetaObject setUrl = new MetaObject("__setUrl", Object.class); + + private JDBCUrlParser urlParser = new JDBCUrlParser(); @Override public void before(Object target, String className, String methodName, String parameterDescription, Object[] args) { @@ -25,6 +30,16 @@ public class DriverConnectInterceptor implements StaticAroundInterceptor { logger.info("before " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args)); } JDBCScope.pushScope(); + + TraceContext traceContext = TraceContext.getTraceContext(); + Trace trace = traceContext.currentTraceObject(); + if (trace == null) { + return; + } + trace.traceBlockBegin(); + trace.record(Annotation.ClientSend); + trace.markBeforeTime(); + } @Override @@ -32,19 +47,42 @@ public class DriverConnectInterceptor implements StaticAroundInterceptor { if (logger.isLoggable(Level.INFO)) { logger.info("after " + StringUtils.toString(target) + " " + className + "." + methodName + parameterDescription + " args:" + Arrays.toString(args) + " result:" + result); } + // 여기서는 trace context인지 아닌지 확인하면 안된다. trace 대상 thread가 아닌곳에서 connection이 생성될수 있음. JDBCScope.popScope(); - // TODO 생성 시간 측정시 아래 코드를 다시 생각해야 됨. - if (!InterceptorUtils.isSuccess(result)) { + + boolean success = InterceptorUtils.isSuccess(result); + // 여기서는 trace context인지 아닌지 확인하면 안된다. trace 대상 thread가 아닌곳에서 connection이 생성될수 있음. + DatabaseInfo databaseInfo = createDatabaseInfo((String) args[0]); + if (success) { + // 생성이 성공해야 result가 connection임. + this.setUrl.invoke(result, databaseInfo); + } + + TraceContext traceContext = TraceContext.getTraceContext(); + Trace trace = traceContext.currentTraceObject(); + if (trace == null) { return; } - // TODO before도 같이 후킹하여 Connection 생성시간도 측정해야 됨. - // datasource의 pool을 고려할것. - if (result instanceof Connection) { - Object url = args[0]; - if (url instanceof String) { - this.setUrl.invoke(result, url); - } + trace.recordRpcName(databaseInfo.getType() + "/" + databaseInfo.getDatabaseId(), databaseInfo.getUrl()); + trace.recordTerminalEndPoint(databaseInfo.getUrl()); + trace.recordAttribute("JDBCConnection", "create"); + if (success) { + trace.recordAttribute("Success", "true"); + } else { + Throwable th = (Throwable) result; + trace.recordAttribute("Success", "false"); + trace.recordAttribute("Exception", th.getMessage()); } + trace.record(Annotation.ClientRecv, trace.afterTime()); + trace.traceBlockEnd(); + } + + private DatabaseInfo createDatabaseInfo(String url) { + DatabaseInfo databaseInfo = urlParser.parse(url); + if (logger.isLoggable(Level.FINE)) { + logger.fine("parse DatabaseInfo:" + databaseInfo); + } + return databaseInfo; } diff --git a/src/main/java/com/profiler/modifier/db/interceptor/PreparedStatementCreateInterceptor.java b/src/main/java/com/profiler/modifier/db/interceptor/PreparedStatementCreateInterceptor.java index b45539461..77e790af4 100644 --- a/src/main/java/com/profiler/modifier/db/interceptor/PreparedStatementCreateInterceptor.java +++ b/src/main/java/com/profiler/modifier/db/interceptor/PreparedStatementCreateInterceptor.java @@ -3,6 +3,7 @@ package com.profiler.modifier.db.interceptor; import com.profiler.context.Trace; import com.profiler.context.TraceContext; import com.profiler.interceptor.StaticAfterInterceptor; +import com.profiler.modifier.db.util.DatabaseInfo; import com.profiler.util.InterceptorUtils; import com.profiler.util.MetaObject; import com.profiler.util.StringUtils; @@ -16,9 +17,9 @@ public class PreparedStatementCreateInterceptor implements StaticAfterIntercepto private final Logger logger = Logger.getLogger(PreparedStatementCreateInterceptor.class.getName()); // connection 용. - private final MetaObject getUrl = new MetaObject("__getUrl"); + private final MetaObject getUrl = new MetaObject("__getUrl"); + private final MetaObject setUrl = new MetaObject("__setUrl", Object.class); - private final MetaObject setUrl = new MetaObject("__setUrl", String.class); private final MetaObject setSql = new MetaObject("__setSql", String.class); @Override @@ -39,8 +40,8 @@ public class PreparedStatementCreateInterceptor implements StaticAfterIntercepto return; } if (target instanceof Connection) { - String connectionUrl = getUrl.invoke(target); - this.setUrl.invoke(result, connectionUrl); + DatabaseInfo databaseInfo = (DatabaseInfo) getUrl.invoke(target); + this.setUrl.invoke(result, databaseInfo); String sql = (String) args[0]; this.setSql.invoke(result, sql); } diff --git a/src/main/java/com/profiler/modifier/db/interceptor/PreparedStatementExecuteQueryInterceptor.java b/src/main/java/com/profiler/modifier/db/interceptor/PreparedStatementExecuteQueryInterceptor.java index 6d3765681..faba2b1d2 100644 --- a/src/main/java/com/profiler/modifier/db/interceptor/PreparedStatementExecuteQueryInterceptor.java +++ b/src/main/java/com/profiler/modifier/db/interceptor/PreparedStatementExecuteQueryInterceptor.java @@ -4,6 +4,7 @@ import com.profiler.context.Annotation; import com.profiler.context.Trace; import com.profiler.context.TraceContext; import com.profiler.interceptor.StaticAroundInterceptor; +import com.profiler.modifier.db.util.DatabaseInfo; import com.profiler.util.InterceptorUtils; import com.profiler.util.MetaObject; import com.profiler.util.StringUtils; @@ -20,7 +21,7 @@ public class PreparedStatementExecuteQueryInterceptor implements StaticAroundInt private final Logger logger = Logger.getLogger(PreparedStatementExecuteQueryInterceptor.class.getName()); private final MetaObject getSql = new MetaObject("__getSql"); - private final MetaObject getUrl = new MetaObject("__getUrl"); + private final MetaObject getUrl = new MetaObject("__getUrl"); private final MetaObject getBindValue = new MetaObject("__getBindValue"); private final MetaObject setBindValue = new MetaObject("__setBindValue", Map.class); @@ -41,9 +42,10 @@ public class PreparedStatementExecuteQueryInterceptor implements StaticAroundInt } trace.traceBlockBegin(); try { - String url = getUrl.invoke(target); - trace.recordRpcName("MYSQL", url); - trace.recordTerminalEndPoint(url); + DatabaseInfo databaseInfo = (DatabaseInfo) getUrl.invoke(target); +// trace.recordRpcName("MYSQL", url); + trace.recordRpcName(databaseInfo.getType() + "/" + databaseInfo.getDatabaseId(), databaseInfo.getUrl()); + trace.recordTerminalEndPoint(databaseInfo.getUrl()); String sql = getSql.invoke(target); trace.recordAttribute("PreparedStatement", sql); diff --git a/src/main/java/com/profiler/modifier/db/interceptor/StatementCreateInterceptor.java b/src/main/java/com/profiler/modifier/db/interceptor/StatementCreateInterceptor.java index 4bd07e9c7..0cb03bdd7 100644 --- a/src/main/java/com/profiler/modifier/db/interceptor/StatementCreateInterceptor.java +++ b/src/main/java/com/profiler/modifier/db/interceptor/StatementCreateInterceptor.java @@ -3,6 +3,7 @@ package com.profiler.modifier.db.interceptor; import com.profiler.context.Trace; import com.profiler.context.TraceContext; import com.profiler.interceptor.StaticAfterInterceptor; +import com.profiler.modifier.db.util.DatabaseInfo; import com.profiler.util.InterceptorUtils; import com.profiler.util.MetaObject; import com.profiler.util.StringUtils; @@ -17,9 +18,9 @@ public class StatementCreateInterceptor implements StaticAfterInterceptor { private final Logger logger = Logger.getLogger(StatementCreateInterceptor.class.getName()); // connection 용. - private final MetaObject getUrl = new MetaObject("__getUrl"); + private final MetaObject getUrl = new MetaObject("__getUrl"); - private final MetaObject setUrl = new MetaObject("__setUrl", String.class); + private final MetaObject setUrl = new MetaObject("__setUrl", Object.class); @Override public void after(Object target, String className, String methodName, String parameterDescription, Object[] args, Object result) { @@ -39,8 +40,8 @@ public class StatementCreateInterceptor implements StaticAfterInterceptor { return; } if (target instanceof Connection) { - String connectionUrl = getUrl.invoke(target); - setUrl.invoke(result, connectionUrl); + DatabaseInfo databaseInfo = (DatabaseInfo) getUrl.invoke(target); + setUrl.invoke(result, databaseInfo); } } diff --git a/src/main/java/com/profiler/modifier/db/interceptor/StatementExecuteQueryInterceptor.java b/src/main/java/com/profiler/modifier/db/interceptor/StatementExecuteQueryInterceptor.java index 9f405fa24..5bead04b9 100644 --- a/src/main/java/com/profiler/modifier/db/interceptor/StatementExecuteQueryInterceptor.java +++ b/src/main/java/com/profiler/modifier/db/interceptor/StatementExecuteQueryInterceptor.java @@ -4,6 +4,7 @@ import com.profiler.context.Annotation; import com.profiler.context.Trace; import com.profiler.context.TraceContext; import com.profiler.interceptor.StaticAroundInterceptor; +import com.profiler.modifier.db.util.DatabaseInfo; import com.profiler.util.InterceptorUtils; import com.profiler.util.MetaObject; import com.profiler.util.StringUtils; @@ -19,7 +20,7 @@ public class StatementExecuteQueryInterceptor implements StaticAroundInterceptor private final Logger logger = Logger.getLogger(StatementExecuteQueryInterceptor.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) { @@ -42,9 +43,9 @@ public class StatementExecuteQueryInterceptor implements StaticAroundInterceptor /** * If method was not called by request handler, we skip tagging. */ - String url = (String) this.getUrl.invoke(target); - trace.recordRpcName("MYSQL", url); - trace.recordTerminalEndPoint(url); + DatabaseInfo databaseInfo = (DatabaseInfo) this.getUrl.invoke(target); + trace.recordRpcName(databaseInfo.getType() + "/" + databaseInfo.getDatabaseId(), databaseInfo.getUrl()); + trace.recordTerminalEndPoint(databaseInfo.getUrl()); if (args.length > 0) { trace.recordAttribute("Statement", args[0]); } diff --git a/src/main/java/com/profiler/modifier/db/interceptor/StatementExecuteUpdateInterceptor.java b/src/main/java/com/profiler/modifier/db/interceptor/StatementExecuteUpdateInterceptor.java index 821a1c9df..c7719d123 100644 --- a/src/main/java/com/profiler/modifier/db/interceptor/StatementExecuteUpdateInterceptor.java +++ b/src/main/java/com/profiler/modifier/db/interceptor/StatementExecuteUpdateInterceptor.java @@ -4,6 +4,7 @@ import com.profiler.context.Annotation; import com.profiler.context.Trace; import com.profiler.context.TraceContext; import com.profiler.interceptor.StaticAroundInterceptor; +import com.profiler.modifier.db.util.DatabaseInfo; import com.profiler.util.MetaObject; import com.profiler.util.StringUtils; @@ -20,7 +21,7 @@ public class StatementExecuteUpdateInterceptor implements StaticAroundIntercepto private final Logger logger = Logger.getLogger(StatementExecuteUpdateInterceptor.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) { @@ -41,13 +42,15 @@ public class StatementExecuteUpdateInterceptor implements StaticAroundIntercepto trace.markBeforeTime(); try { if (args.length > 0) { - String url = (String) this.getUrl.invoke(target); - trace.recordRpcName("MYSQL", url); - trace.recordAttribute("Query", url); - trace.recordTerminalEndPoint(url); + DatabaseInfo databaseInfo = (DatabaseInfo) this.getUrl.invoke(target); + trace.recordRpcName(databaseInfo.getType() + "/" + databaseInfo.getDatabaseId(), databaseInfo.getUrl()); + trace.recordTerminalEndPoint(databaseInfo.getUrl()); + trace.recordAttribute("Query", args[0]); } else { - trace.recordRpcName("MYSQL", "UNKNOWN"); - trace.recordTerminalEndPoint("UNKNOWN"); + DatabaseInfo databaseInfo = (DatabaseInfo) this.getUrl.invoke(target); + trace.recordRpcName(databaseInfo.getType() + "/" + databaseInfo.getDatabaseId(), databaseInfo.getUrl()); + trace.recordTerminalEndPoint(databaseInfo.getUrl()); + trace.recordAttribute("Query", "args size is 0"); } trace.record(Annotation.ClientSend); diff --git a/src/main/java/com/profiler/modifier/db/interceptor/TransactionInterceptor.java b/src/main/java/com/profiler/modifier/db/interceptor/TransactionInterceptor.java index 1e0b9b9e2..5835ccfd9 100644 --- a/src/main/java/com/profiler/modifier/db/interceptor/TransactionInterceptor.java +++ b/src/main/java/com/profiler/modifier/db/interceptor/TransactionInterceptor.java @@ -9,6 +9,7 @@ import com.profiler.context.Annotation; import com.profiler.context.Trace; import com.profiler.context.TraceContext; import com.profiler.interceptor.StaticAroundInterceptor; +import com.profiler.modifier.db.util.DatabaseInfo; import com.profiler.util.InterceptorUtils; import com.profiler.util.MetaObject; import com.profiler.util.StringUtils; @@ -17,7 +18,7 @@ public class TransactionInterceptor implements StaticAroundInterceptor { private final Logger logger = Logger.getLogger(TransactionInterceptor.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) { @@ -73,12 +74,16 @@ public class TransactionInterceptor implements StaticAroundInterceptor { private void beforeStartTransaction(Trace trace, Connection target) { trace.traceBlockBegin(); - String connectionUrl = this.getUrl.invoke(target); - trace.recordRpcName("MYSQL", connectionUrl); - trace.recordTerminalEndPoint(connectionUrl); + DatabaseInfo databaseInfo = (DatabaseInfo) this.getUrl.invoke(target); + trace.recordRpcName(getRpcName(databaseInfo), databaseInfo.getUrl()); + trace.recordTerminalEndPoint(databaseInfo.getUrl()); trace.record(Annotation.ClientSend); } + private String getRpcName(DatabaseInfo databaseInfo) { + return databaseInfo.getType() + "/" + databaseInfo.getDatabaseId(); + } + private void afterStartTransaction(Trace trace, Connection target, Object arg, Object result) { try { Boolean autocommit = (Boolean) arg; @@ -114,18 +119,18 @@ public class TransactionInterceptor implements StaticAroundInterceptor { private void beforeCommit(Trace trace, Connection target) { trace.traceBlockBegin(); - String connectionUrl = this.getUrl.invoke(target); - trace.recordRpcName("MYSQL", connectionUrl); - trace.recordTerminalEndPoint(connectionUrl); + DatabaseInfo databaseInfo = (DatabaseInfo) this.getUrl.invoke(target); + trace.recordRpcName(getRpcName(databaseInfo), databaseInfo.getUrl()); + trace.recordTerminalEndPoint(databaseInfo.getUrl()); trace.record(Annotation.ClientSend); } private void afterCommit(Trace trace, Connection target, Object result) { try { - String connectionUrl = this.getUrl.invoke(target); - trace.recordRpcName("MYSQL", connectionUrl); - trace.recordTerminalEndPoint(connectionUrl); + DatabaseInfo databaseInfo = (DatabaseInfo) this.getUrl.invoke(target); + trace.recordRpcName(getRpcName(databaseInfo), databaseInfo.getUrl()); + trace.recordTerminalEndPoint(databaseInfo.getUrl()); boolean success = InterceptorUtils.isSuccess(result); if (success) { @@ -148,18 +153,18 @@ public class TransactionInterceptor implements StaticAroundInterceptor { private void beforeRollback(Trace trace, Connection target) { trace.traceBlockBegin(); - String connectionUrl = this.getUrl.invoke(target); - trace.recordRpcName("MYSQL", connectionUrl); - trace.recordTerminalEndPoint(connectionUrl); + DatabaseInfo databaseInfo = (DatabaseInfo) this.getUrl.invoke(target); + trace.recordRpcName(getRpcName(databaseInfo), databaseInfo.getUrl()); + trace.recordTerminalEndPoint(databaseInfo.getUrl()); trace.record(Annotation.ClientSend); } private void afterRollback(Trace trace, Connection target, Object result) { try { - String connectionUrl = this.getUrl.invoke(target); - trace.recordRpcName("MYSQL", connectionUrl); - trace.recordTerminalEndPoint(connectionUrl); + DatabaseInfo databaseInfo = (DatabaseInfo) this.getUrl.invoke(target); + trace.recordRpcName(getRpcName(databaseInfo), databaseInfo.getUrl()); + trace.recordTerminalEndPoint(databaseInfo.getUrl()); boolean success = InterceptorUtils.isSuccess(result); if (success) { diff --git a/src/main/java/com/profiler/modifier/db/mysql/MySQLConnectionImplModifier.java b/src/main/java/com/profiler/modifier/db/mysql/MySQLConnectionImplModifier.java index efecb8c8f..7fee7102a 100644 --- a/src/main/java/com/profiler/modifier/db/mysql/MySQLConnectionImplModifier.java +++ b/src/main/java/com/profiler/modifier/db/mysql/MySQLConnectionImplModifier.java @@ -33,7 +33,7 @@ public class MySQLConnectionImplModifier extends AbstractModifier { InstrumentClass mysqlConnection = byteCodeInstrumentor.getClass(javassistClassName); - mysqlConnection.addTraceVariable("__url", "__setUrl", "__getUrl", "java.lang.String"); + mysqlConnection.addTraceVariable("__url", "__setUrl", "__getUrl", "java.lang.Object"); // 해당 Interceptor를 공통클래스 만들경우 system에 로드해야 된다. // Interceptor createConnection = new ConnectionCreateInterceptor(); diff --git a/src/main/java/com/profiler/modifier/db/mysql/MySQLPreparedStatementModifier.java b/src/main/java/com/profiler/modifier/db/mysql/MySQLPreparedStatementModifier.java index fad2602d4..c468294aa 100644 --- a/src/main/java/com/profiler/modifier/db/mysql/MySQLPreparedStatementModifier.java +++ b/src/main/java/com/profiler/modifier/db/mysql/MySQLPreparedStatementModifier.java @@ -49,7 +49,7 @@ public class MySQLPreparedStatementModifier extends AbstractModifier { int id = preparedStatement.addInterceptor("executeQuery", null, interceptor); preparedStatement.reuseInterceptor("executeUpdate", null, id); - preparedStatement.addTraceVariable("__url", "__setUrl", "__getUrl", "java.lang.String"); + preparedStatement.addTraceVariable("__url", "__setUrl", "__getUrl", "java.lang.Object"); preparedStatement.addTraceVariable("__sql", "__setSql", "__getSql", "java.lang.String"); preparedStatement.addTraceVariable("__bindValue", "__setBindValue", "__getBindValue", "java.util.Map", "java.util.Collections.synchronizedMap(new java.util.HashMap());"); 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 ca5ee213f..641011ecd 100644 --- a/src/main/java/com/profiler/modifier/db/mysql/MySQLStatementModifier.java +++ b/src/main/java/com/profiler/modifier/db/mysql/MySQLStatementModifier.java @@ -40,7 +40,7 @@ public class MySQLStatementModifier extends AbstractModifier { Interceptor executeUpdate = newInterceptor(classLoader, protectedDomain, "com.profiler.modifier.db.interceptor.StatementExecuteUpdateInterceptor"); statementClass.addInterceptor("executeUpdate", new String[]{"java.lang.String", "boolean", "boolean"}, executeUpdate); - statementClass.addTraceVariable("__url", "__setUrl", "__getUrl", "java.lang.String"); + statementClass.addTraceVariable("__url", "__setUrl", "__getUrl", "java.lang.Object"); return statementClass.toBytecode(); } catch (InstrumentException e) { return null; diff --git a/src/main/java/com/profiler/modifier/db/util/DatabaseInfo.java b/src/main/java/com/profiler/modifier/db/util/DatabaseInfo.java new file mode 100644 index 000000000..7bf0e7cbf --- /dev/null +++ b/src/main/java/com/profiler/modifier/db/util/DatabaseInfo.java @@ -0,0 +1,60 @@ +package com.profiler.modifier.db.util; + +/** + * + */ +public class DatabaseInfo { + public enum DBType { + ORACLE, MYSQL, MSSQL, CUBRID, UNKOWN + } + + DBType type = DBType.UNKOWN; + String databaseId; + String url; + String host; + String port; + + + public DatabaseInfo(DBType type, String url, String host, String port, String databaseId) { + this.type = type; + this.url = url; + this.host = host; + this.port = port; + this.databaseId = databaseId; + } + + @Deprecated + public String getHost() { + // host와 port의 경우 replication 설정등으로 n개가 될수 있어 애매하다. + return host; + } + + @Deprecated + public String getPort() { + // host와 port의 경우 replication 설정등으로 n개가 될수 있어 애매하다. + return port; + } + + public String getDatabaseId() { + return databaseId; + } + + public String getUrl() { + return url; + } + + public DBType getType() { + return type; + } + + @Override + public String toString() { + return "DatabaseInfo{" + + "type=" + type + + ", databaseId='" + databaseId + '\'' + + ", url='" + url + '\'' + + ", host='" + host + '\'' + + ", port='" + port + '\'' + + '}'; + } +} diff --git a/src/main/java/com/profiler/modifier/db/util/JDBCUrlParser.java b/src/main/java/com/profiler/modifier/db/util/JDBCUrlParser.java new file mode 100644 index 000000000..3dcc07ac6 --- /dev/null +++ b/src/main/java/com/profiler/modifier/db/util/JDBCUrlParser.java @@ -0,0 +1,72 @@ +package com.profiler.modifier.db.util; + +import java.util.regex.Matcher; + +/** + * + */ +public class JDBCUrlParser { + public DatabaseInfo parse(String url) { + String lowCaseURL = url.toLowerCase(); + if (lowCaseURL.contains("jdbc:mysql")) { + return parseMysql(url); + } + + return new DatabaseInfo(DatabaseInfo.DBType.UNKOWN, url, "error", "error", "error"); +// else if (url.indexOf("jdbc:oracle") >= 0) { +// maker.lower().after("jdbc:oracle:").after(':'); +// info.type = TYPE.ORACLE; +// String description = maker.after('@').value().trim(); +// +// if (description.startsWith("(")) { +// Matcher matcher = oracleRAC.matcher(description); +// +// if (matcher.matches()) { +// info.host = matcher.group(1); +// info.port = matcher.group(2); +// info.databaseId = matcher.group(3); +// } else { +// info.databaseId = "ParsingFailed[" + System.currentTimeMillis() + ']'; +// } +// } else { +// info.host = maker.before(':').value(); +// info.port = maker.next().after(':').before(':').value(); +// info.databaseId = maker.next().afterLast(':').value(); +// } +// } else if (url.indexOf("jdbc:sqlserver") >= 0) { +// maker.lower().after("jdbc:sqlserver:"); +// info.type = TYPE.MSSQL; +// info.host = maker.after("//").before(';').value(); +// info.port = maker.currentTraceClear().after("port=").before(';').value(); +// info.databaseId = maker.currentTraceClear().after("databasename=").before(';').value(); +// } else if (url.indexOf("jdbc:jtds:sqlserver") >= 0) { +// maker.lower().after("jdbc:jtds:sqlserver:"); +// info.type = TYPE.MSSQL; +// info.host = maker.after("//").beforeLast('/').beforeLast(':').value(); +// info.port = maker.next().after(':').beforeLast('/').value(); +// info.databaseId = maker.next().afterLast('/').before(';').value(); +// } else if (url.indexOf("jdbc:cubrid") >= 0) { +// maker.lower().after("jdbc:cubrid"); +// info.type = TYPE.CUBRID; +// info.host = maker.after(':').before(':').value(); +// info.port = maker.next().after(':').before(':').value(); +// info.databaseId = maker.next().after(':').before(':').value(); +// } +// if ("".equals(info.databaseId)) { +// info.databaseId = info.host; +// } + +// return info; +// return null; + } + + private DatabaseInfo parseMysql(String url) { + // jdbc:mysql://10.98.133.22:3306/test_lucy_db + StringMaker maker = new StringMaker(url); + maker.after("jdbc:mysql:"); + 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); + } +} diff --git a/src/main/java/com/profiler/modifier/db/util/StringMaker.java b/src/main/java/com/profiler/modifier/db/util/StringMaker.java new file mode 100644 index 000000000..65f27b510 --- /dev/null +++ b/src/main/java/com/profiler/modifier/db/util/StringMaker.java @@ -0,0 +1,297 @@ +package com.profiler.modifier.db.util; + +/** + * + */ +public class StringMaker { + + /** + * The value. + */ + private String value; + + /** + * The indexing. + */ + private String indexing; + + /** + * The begin. + */ + private int begin; + + /** + * The end. + */ + private int end; + + /** + * Instantiates a new string maker. + * + * @param value the value + */ + public StringMaker(String value) { + this.value = value; + this.indexing = value; + this.end = value.length(); + } + + /** + * Instantiates a new string maker. + * + * @param value the value + * @param begin the begin + * @param end the end + */ + private StringMaker(String value, int begin, int end) { + this.value = value; + this.indexing = value; + this.begin = begin; + this.end = end; + } + + /** + * Lower. + * + * @return the string maker + */ + public StringMaker lower() { + indexing = indexing.toLowerCase(); + return this; + } + + /** + * Upper. + * + * @return the string maker + */ + public StringMaker upper() { + indexing = indexing.toUpperCase(); + return this; + } + + /** + * Reset. + * + * @return the string maker + */ + public StringMaker reset() { + indexing = value; + return this; + } + + /** + * After. + * + * @param ch the ch + * @return the string maker + */ + public StringMaker after(char ch) { + int index = indexing.indexOf(ch, begin); + + if (index < 0 || index > end) { + return this; + } + + begin = index + 1 > end ? end : index + 1; + return this; + } + + /** + * After. + * + * @param ch the ch + * @return the string maker + */ + public StringMaker after(String ch) { + int index = indexing.indexOf(ch, begin); + + if (index < 0 || index > end) { + return this; + } + + begin = index + ch.length() > end ? end : index + ch.length(); + return this; + } + + /** + * Before. + * + * @param ch the ch + * @return the string maker + */ + public StringMaker before(char ch) { + int index = indexing.indexOf(ch, begin); + + if (index < 0 || index > end) { + return this; + } + + end = index < begin ? begin : index; + return this; + } + + /** + * Before. + * + * @param ch the ch + * @return the string maker + */ + public StringMaker before(String ch) { + int index = indexing.indexOf(ch, begin); + + if (index < 0 || index > end) { + return this; + } + + end = index < begin ? begin : index; + return this; + } + + /** + * After last. + * + * @param ch the ch + * @return the string maker + */ + public StringMaker afterLast(char ch) { + int index = indexing.lastIndexOf(ch, end); + + if (index < begin) { + return this; + } + + begin = index + 1 > end ? end : index + 1; + return this; + } + + /** + * After last. + * + * @param ch the ch + * @return the string maker + */ + public StringMaker afterLast(String ch) { + int index = indexing.lastIndexOf(ch, end); + + if (index < begin) { + return this; + } + + begin = index + ch.length() > end ? end : index + ch.length(); + return this; + } + + /** + * Before last. + * + * @param ch the ch + * @return the string maker + */ + public StringMaker beforeLast(char ch) { + int index = indexing.lastIndexOf(ch, end); + + if (index < begin) { + return this; + } + + //end = index < begin ? begin : index; + //for Klocwork + + end = index; + return this; + } + + /** + * Before last. + * + * @param ch the ch + * @return the string maker + */ + public StringMaker beforeLast(String ch) { + int index = indexing.lastIndexOf(ch, end); + + if (index < begin) { + return this; + } + + //end = index < begin ? begin : index; + //for Klocwork + + end = index; + return this; + } + + /** + * Prev. + * + * @return the string maker + */ + public StringMaker prev() { + this.end = begin; + this.begin = 0; + return this; + } + + /** + * Next. + * + * @return the string maker + */ + public StringMaker next() { + this.begin = end; + this.end = indexing.length(); + return this; + } + + /** + * Clear. + * + * @return the string maker + */ + public StringMaker clear() { + begin = 0; + end = indexing.length(); + return this; + } + + /** + * Checks if is empty. + * + * @return true, if is empty + */ + public boolean isEmpty() { + return begin == end; + } + + /** + * Value. + * + * @return the string + */ + public String value() { + return value.substring(begin, end); + } + + /** + * Dulicate. + * + * @return the string maker + */ + public StringMaker duplicate() { + return new StringMaker(value, begin, end); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + + /** + * To string. + * + * @return value() String + */ + public String toString() { + return value(); + } +} \ No newline at end of file diff --git a/src/test/java/com/profiler/modifier/db/util/ConnectionStringParserTest.java b/src/test/java/com/profiler/modifier/db/util/ConnectionStringParserTest.java deleted file mode 100644 index 4e383f49d..000000000 --- a/src/test/java/com/profiler/modifier/db/util/ConnectionStringParserTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.profiler.modifier.db.util; - -import junit.framework.Assert; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.URI; - -/** - * - */ -public class ConnectionStringParserTest { - - private Logger logger = LoggerFactory.getLogger(ConnectionStringParserTest.class); - - @Test - public void testURIParse() throws Exception { - - URI uri = URI.create("mysql:replication://10.98.133.22:3306/test_lucy_db"); - logger.debug(uri.toString()); - logger.debug(uri.getScheme()); - - // URI로 파싱하는건 제한적임 한계가 있음. - try { - URI oracleRac = URI.create("jdbc:oracle:thin:@(DESCRIPTION=(LOAD_BALANCE=on)" + - "(ADDRESS=(PROTOCOL=TCP)(HOST=1.2.3.4) (PORT=1521))" + - "(ADDRESS=(PROTOCOL=TCP)(HOST=1.2.3.5) (PORT=1521))" + - "(CONNECT_DATA=(SERVICE_NAME=service)))"); - - logger.debug(oracleRac.toString()); - logger.debug(oracleRac.getScheme()); - Assert.fail(); - } catch (Exception e) { - } - } -} diff --git a/src/test/java/com/profiler/modifier/db/util/JDBCUrlParserTest.java b/src/test/java/com/profiler/modifier/db/util/JDBCUrlParserTest.java new file mode 100644 index 000000000..ba415e873 --- /dev/null +++ b/src/test/java/com/profiler/modifier/db/util/JDBCUrlParserTest.java @@ -0,0 +1,60 @@ +package com.profiler.modifier.db.util; + +import junit.framework.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.URI; + +/** + * + */ +public class JDBCUrlParserTest { + + private Logger logger = LoggerFactory.getLogger(JDBCUrlParserTest.class); + private JDBCUrlParser JDBCUrlParser = new JDBCUrlParser(); + + @Test + public void testURIParse() throws Exception { + + URI uri = URI.create("jdbc:mysql:replication://10.98.133.22:3306/test_lucy_db"); + logger.debug(uri.toString()); + logger.debug(uri.getScheme()); + + // URI로 파싱하는건 제한적임 한계가 있음. + try { + URI oracleRac = URI.create("jdbc:oracle:thin:@(DESCRIPTION=(LOAD_BALANCE=on)" + + "(ADDRESS=(PROTOCOL=TCP)(HOST=1.2.3.4) (PORT=1521))" + + "(ADDRESS=(PROTOCOL=TCP)(HOST=1.2.3.5) (PORT=1521))" + + "(CONNECT_DATA=(SERVICE_NAME=service)))"); + + logger.debug(oracleRac.toString()); + logger.debug(oracleRac.getScheme()); + Assert.fail(); + } catch (Exception e) { + } + } + + @Test + public void mysqlParse1() { + + DatabaseInfo dbInfo = JDBCUrlParser.parse("jdbc:mysql://ip_address:3306/database_name?useUnicode=yes&characterEncoding=UTF-8"); + Assert.assertEquals(dbInfo.getType(), DatabaseInfo.DBType.MYSQL); + Assert.assertEquals(dbInfo.getHost(), "ip_address"); + Assert.assertEquals(dbInfo.getPort(), "3306"); + Assert.assertEquals(dbInfo.getDatabaseId(), "database_name"); +// JDBCUrlParser.parse("jdbc:mysql://61.74.71.31/log?useUnicode=yes&characterEncoding=UTF-8") + + } + + @Test + public void mysqlParse2() { + + DatabaseInfo dbInfo = JDBCUrlParser.parse("jdbc:mysql://10.98.133.22:3306/test_lucy_db"); + Assert.assertEquals(dbInfo.getType(), DatabaseInfo.DBType.MYSQL); + Assert.assertEquals(dbInfo.getHost(), "10.98.133.22"); + Assert.assertEquals(dbInfo.getPort(), "3306"); + Assert.assertEquals(dbInfo.getDatabaseId(), "test_lucy_db"); + } +} diff --git a/src/test/java/com/profiler/util/TestClassLoader.java b/src/test/java/com/profiler/util/TestClassLoader.java index b60651536..a599d2fee 100644 --- a/src/test/java/com/profiler/util/TestClassLoader.java +++ b/src/test/java/com/profiler/util/TestClassLoader.java @@ -1,6 +1,5 @@ package com.profiler.util; -import com.profiler.StopWatch; import com.profiler.context.Annotation; import com.profiler.context.Trace; import com.profiler.interceptor.*; @@ -36,7 +35,7 @@ public class TestClassLoader extends Loader { return instrumentor; } - public Modifier addModifier(Modifier modifier){ + public Modifier addModifier(Modifier modifier) { return this.instrumentTranslator.addModifier(modifier); } @@ -49,7 +48,6 @@ public class TestClassLoader extends Loader { this.delegateLoadingOf(InterceptorRegistry.class.getName()); this.delegateLoadingOf(Trace.class.getName()); this.delegateLoadingOf(Annotation.class.getName()); - this.delegateLoadingOf(StopWatch.class.getName()); this.delegateLoadingOf(MetaObject.class.getName()); this.delegateLoadingOf(StringUtils.class.getName()); @@ -76,8 +74,7 @@ public class TestClassLoader extends Loader { Object o = c.newInstance(); try { c.getDeclaredMethod(methodName, null).invoke(o, null); - } - catch (java.lang.reflect.InvocationTargetException e) { + } catch (java.lang.reflect.InvocationTargetException e) { throw e.getTargetException(); } }