mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
improve LogFilter
This commit is contained in:
@@ -19,6 +19,9 @@ import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Savepoint;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.druid.filter.FilterChain;
|
||||
import com.alibaba.druid.filter.FilterEventAdapter;
|
||||
@@ -31,6 +34,7 @@ import com.alibaba.druid.proxy.jdbc.JdbcParameter;
|
||||
import com.alibaba.druid.proxy.jdbc.PreparedStatementProxy;
|
||||
import com.alibaba.druid.proxy.jdbc.ResultSetProxy;
|
||||
import com.alibaba.druid.proxy.jdbc.StatementProxy;
|
||||
import com.alibaba.druid.sql.SQLUtils;
|
||||
import com.alibaba.druid.util.JdbcUtils;
|
||||
|
||||
/**
|
||||
@@ -57,6 +61,7 @@ public abstract class LogFilter extends FilterEventAdapter implements LogFilterM
|
||||
private boolean statementExecuteQueryAfterLogEnable = true;
|
||||
private boolean statementExecuteUpdateAfterLogEnable = true;
|
||||
private boolean statementExecuteBatchAfterLogEnable = true;
|
||||
private boolean statementExecutableSqlLogEnable = false;
|
||||
|
||||
private boolean statementCloseAfterLogEnable = true;
|
||||
|
||||
@@ -89,6 +94,12 @@ public abstract class LogFilter extends FilterEventAdapter implements LogFilterM
|
||||
resultSetLogEnabled = false;
|
||||
}
|
||||
}
|
||||
{
|
||||
String prop = System.getProperty("druid.log.stmt.executableSql");
|
||||
if (prop == "true") {
|
||||
statementExecutableSqlLogEnable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -224,6 +235,14 @@ public abstract class LogFilter extends FilterEventAdapter implements LogFilterM
|
||||
this.statementExecuteUpdateAfterLogEnable = afterStatementExecuteUpdateLogEnable;
|
||||
}
|
||||
|
||||
public boolean isStatementExecutableSqlLogEnable() {
|
||||
return statementExecutableSqlLogEnable;
|
||||
}
|
||||
|
||||
public void setStatementExecutableSqlLogEnable(boolean statementExecutableSqlLogEnable) {
|
||||
this.statementExecutableSqlLogEnable = statementExecutableSqlLogEnable;
|
||||
}
|
||||
|
||||
public boolean isStatementPrepareCallAfterLogEnabled() {
|
||||
return isStatementLogEnabled() && statementPrepareCallAfterLogEnable;
|
||||
}
|
||||
@@ -392,6 +411,8 @@ public abstract class LogFilter extends FilterEventAdapter implements LogFilterM
|
||||
|
||||
@Override
|
||||
protected void statementExecuteAfter(StatementProxy statement, String sql, boolean firstResult) {
|
||||
logExecutableSql(statement, sql);
|
||||
|
||||
if (statementExecuteAfterLogEnable && isStatementLogEnabled()) {
|
||||
statement.setLastExecuteTimeNano();
|
||||
double nanos = statement.getLastExecuteTimeNano();
|
||||
@@ -409,18 +430,20 @@ public abstract class LogFilter extends FilterEventAdapter implements LogFilterM
|
||||
|
||||
@Override
|
||||
protected void statementExecuteBatchAfter(StatementProxy statement, int[] result) {
|
||||
String sql;
|
||||
if (statement instanceof PreparedStatementProxy) {
|
||||
sql = ((PreparedStatementProxy) statement).getSql();
|
||||
} else {
|
||||
sql = statement.getBatchSql();
|
||||
}
|
||||
|
||||
logExecutableSql(statement, sql);
|
||||
|
||||
if (statementExecuteBatchAfterLogEnable && isStatementLogEnabled()) {
|
||||
statement.setLastExecuteTimeNano();
|
||||
double nanos = statement.getLastExecuteTimeNano();
|
||||
double millis = nanos / (1000 * 1000);
|
||||
|
||||
String sql;
|
||||
if (statement instanceof PreparedStatementProxy) {
|
||||
sql = ((PreparedStatementProxy) statement).getSql();
|
||||
} else {
|
||||
sql = statement.getBatchSql();
|
||||
}
|
||||
|
||||
statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement)
|
||||
+ "} batch executed. " + millis + " millis. " + sql);
|
||||
}
|
||||
@@ -436,6 +459,8 @@ public abstract class LogFilter extends FilterEventAdapter implements LogFilterM
|
||||
|
||||
@Override
|
||||
protected void statementExecuteQueryAfter(StatementProxy statement, String sql, ResultSetProxy resultSet) {
|
||||
logExecutableSql(statement, sql);
|
||||
|
||||
if (statementExecuteQueryAfterLogEnable && isStatementLogEnabled()) {
|
||||
statement.setLastExecuteTimeNano();
|
||||
double nanos = statement.getLastExecuteTimeNano();
|
||||
@@ -456,6 +481,8 @@ public abstract class LogFilter extends FilterEventAdapter implements LogFilterM
|
||||
|
||||
@Override
|
||||
protected void statementExecuteUpdateAfter(StatementProxy statement, String sql, int updateCount) {
|
||||
logExecutableSql(statement, sql);
|
||||
|
||||
if (statementExecuteUpdateAfterLogEnable && isStatementLogEnabled()) {
|
||||
statement.setLastExecuteTimeNano();
|
||||
double nanos = statement.getLastExecuteTimeNano();
|
||||
@@ -466,6 +493,29 @@ public abstract class LogFilter extends FilterEventAdapter implements LogFilterM
|
||||
}
|
||||
}
|
||||
|
||||
private void logExecutableSql(StatementProxy statement, String sql) {
|
||||
if (!isStatementExecutableSqlLogEnable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<Integer, JdbcParameter> parameterMap = statement.getParameters();
|
||||
if (parameterMap == null || parameterMap.size() == 0) {
|
||||
statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + "} executed. "
|
||||
+ sql);
|
||||
return;
|
||||
}
|
||||
|
||||
List<Object> parameters = new ArrayList<Object>(parameterMap.size());
|
||||
for (JdbcParameter jdbcParam : parameterMap.values()) {
|
||||
parameters.add(jdbcParam.getValue());
|
||||
}
|
||||
|
||||
String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType();
|
||||
String formattedSql = SQLUtils.format(sql, dbType, parameters);
|
||||
statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + "} executed. "
|
||||
+ formattedSql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resultSet_close(FilterChain chain, ResultSetProxy resultSet) throws SQLException {
|
||||
chain.resultSet_close(resultSet);
|
||||
|
||||
@@ -137,6 +137,10 @@ public class DruidPooledConnection extends PoolableWrapper implements javax.sql.
|
||||
public void closePoolableStatement(DruidPooledPreparedStatement stmt) throws SQLException {
|
||||
PreparedStatement rawStatement = stmt.getRawPreparedStatement();
|
||||
|
||||
if (holder == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
try {
|
||||
rawStatement.clearParameters();
|
||||
@@ -145,10 +149,6 @@ public class DruidPooledConnection extends PoolableWrapper implements javax.sql.
|
||||
}
|
||||
}
|
||||
|
||||
if (holder == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
stmt.getPreparedStatementHolder().decrementInUseCount();
|
||||
if (holder.isPoolPreparedStatements()) {
|
||||
holder.getStatementPool().put(stmt.getPreparedStatementHolder());
|
||||
|
||||
@@ -140,12 +140,16 @@ public class SQLUtils {
|
||||
public static SQLExpr toSQLExpr(String sql) {
|
||||
return toSQLExpr(sql, null);
|
||||
}
|
||||
|
||||
|
||||
public static String format(String sql, String dbType) {
|
||||
return format(sql, dbType, null);
|
||||
}
|
||||
|
||||
public static String format(String sql, String dbType, List<Object> parameters) {
|
||||
try {
|
||||
List<SQLStatement> statementList = toStatementList(sql, dbType);
|
||||
|
||||
return toSQLString(statementList, dbType);
|
||||
return toSQLString(statementList, dbType, parameters);
|
||||
} catch (SQLParseException ex) {
|
||||
LOG.warn("format error", ex);
|
||||
return sql;
|
||||
@@ -156,8 +160,15 @@ public class SQLUtils {
|
||||
}
|
||||
|
||||
public static String toSQLString(List<SQLStatement> statementList, String dbType) {
|
||||
return toSQLString(statementList, dbType, null);
|
||||
}
|
||||
|
||||
public static String toSQLString(List<SQLStatement> statementList, String dbType, List<Object> parameters) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
SQLASTOutputVisitor visitor = createFormatOutputVisitor(out, statementList, dbType);
|
||||
if (parameters != null) {
|
||||
visitor.setParameters(parameters);
|
||||
}
|
||||
|
||||
for (SQLStatement stmt : statementList) {
|
||||
stmt.accept(visitor);
|
||||
|
||||
@@ -16,7 +16,14 @@
|
||||
package com.alibaba.druid.sql.visitor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.NClob;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.druid.sql.ast.SQLCommentHint;
|
||||
@@ -107,10 +114,24 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter {
|
||||
private int indentCount = 0;
|
||||
private boolean prettyFormat = true;
|
||||
|
||||
private List<Object> parameters;
|
||||
|
||||
public SQLASTOutputVisitor(Appendable appender){
|
||||
this.appender = appender;
|
||||
}
|
||||
|
||||
public List<Object> getParameters() {
|
||||
if (parameters == null) {
|
||||
parameters = new ArrayList<Object>();
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public void setParameters(List<Object> parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
public int getIndentCount() {
|
||||
return indentCount;
|
||||
}
|
||||
@@ -147,6 +168,16 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter {
|
||||
print(Integer.toString(value));
|
||||
}
|
||||
|
||||
public void print(Date date) {
|
||||
SimpleDateFormat dateFormat;
|
||||
if (date instanceof java.sql.Timestamp) {
|
||||
dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
|
||||
} else {
|
||||
dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
}
|
||||
print("'" + dateFormat.format(date) + "'");
|
||||
}
|
||||
|
||||
public void print(long value) {
|
||||
print(Long.toString(value));
|
||||
}
|
||||
@@ -655,7 +686,63 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter {
|
||||
}
|
||||
|
||||
public boolean visit(SQLVariantRefExpr x) {
|
||||
print(x.getName());
|
||||
int index = x.getIndex();
|
||||
|
||||
if (parameters == null || index >= parameters.size()) {
|
||||
print(x.getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
Object param = parameters.get(index);
|
||||
|
||||
if (param == null) {
|
||||
print("NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (param instanceof Number //
|
||||
|| param instanceof Boolean) {
|
||||
print(param.toString());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (param instanceof String) {
|
||||
SQLCharExpr charExpr = new SQLCharExpr((String) param);
|
||||
visit(charExpr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (param instanceof Date) {
|
||||
print((Date) param);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (param instanceof InputStream) {
|
||||
print("'<InputStream>");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (param instanceof Reader) {
|
||||
print("'<Reader>");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (param instanceof Blob) {
|
||||
print("'<Blob>");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (param instanceof NClob) {
|
||||
print("'<NClob>");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (param instanceof Clob) {
|
||||
print("'<Clob>");
|
||||
return false;
|
||||
}
|
||||
|
||||
print("'" + param.getClass().getName() + "'");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -887,7 +974,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter {
|
||||
print(x.getOperator().name);
|
||||
|
||||
SQLExpr expr = x.getExpr();
|
||||
|
||||
|
||||
switch (x.getOperator()) {
|
||||
case BINARY:
|
||||
case Prior:
|
||||
|
||||
@@ -59,7 +59,7 @@ public class Case1 extends TestCase {
|
||||
private String validationQuery = "SELECT 1";
|
||||
private int threadCount = 5;
|
||||
private int loopCount = 10;
|
||||
final int LOOP_COUNT = 1000 * 1000 * 1 / threadCount;
|
||||
final int LOOP_COUNT = 1000 * 1 * 1 / threadCount;
|
||||
|
||||
private static AtomicLong physicalConnStat = new AtomicLong();
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.alibaba.druid.bvt.filter.log;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.druid.util.JdbcUtils;
|
||||
|
||||
public class LogFilterTest3 extends TestCase {
|
||||
|
||||
private DruidDataSource dataSource;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
System.setProperty("druid.log.stmt.executableSql", "true");
|
||||
dataSource = new DruidDataSource();
|
||||
dataSource.setUrl("jdbc:derby:classpath:petstore-db");
|
||||
dataSource.setFilters("log4j");
|
||||
}
|
||||
|
||||
public void test_select() throws Exception {
|
||||
Connection conn = dataSource.getConnection();
|
||||
|
||||
PreparedStatement stmt = conn.prepareStatement("SELECT * FROM ITEM WHERE LISTPRICE > ?");
|
||||
stmt.setInt(1, 10);
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
rs.close();
|
||||
}
|
||||
|
||||
stmt.close();
|
||||
|
||||
conn.close();
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
JdbcUtils.close(dataSource);
|
||||
|
||||
System.clearProperty("druid.log.stmt.executableSql");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user