ali druid 自定义filter
·
自定义filter的起因是希望在跟踪resultset的获取行数,同时slow sql输出的时候可以输出thread stack,以帮助快速定位问题。
先看关键类:
public abstract class LogFilter
首先定义了4个log 对象
protected String dataSourceLoggerName = "druid.sql.DataSource";
protected String connectionLoggerName = "druid.sql.Connection";
protected String statementLoggerName = "druid.sql.Statement";
protected String resultSetLoggerName = "druid.sql.ResultSet";
这些对应了log配置,以log4j2为例:
<!--记录druid-sql的记录-->
<logger name="druid.sql.Statement" level="info" additivity="false">
<appender-ref ref="druidSqlRollingFile"/>
<appender-ref ref="Console"/>
</logger>
<!--log4j2 自带过滤日志-->
<Logger name="druid.sql.ResultSet" level="debug" additivity="false">
<appender-ref ref="druidSqlRollingFile"/>
<appender-ref ref="Console"/>
</Logger>
及大量开关参数:
private boolean connectionConnectBeforeLogEnable = true;
private boolean connectionConnectAfterLogEnable = true;
private boolean connectionCommitAfterLogEnable = true;
private boolean connectionRollbackAfterLogEnable = true;
private boolean connectionCloseAfterLogEnable = true;
这些在spring boot 模式下,对应的properties 如下:
spring.datasource.druid.filter.slf4j.enabled=true
spring.datasource.druid.filter.slf4j.statement-create-after-log-enabled=false
spring.datasource.druid.filter.slf4j.statement-close-after-log-enabled=false
spring.datasource.druid.filter.slf4j.statement-execute-update-after-log-enabled=false
#spring.datasource.druid.filter.log4j2.statement-execute-after-log-enabled=false
spring.datasource.druid.filter.stat.log-slow-sql=true
spring.datasource.druid.filter.stat.slow-sql-millis=1
但有一些也可以通过environment 来定义,这些定义在如下代码中:
public void configFromProperties(Properties properties) {
{
String prop = properties.getProperty("druid.log.conn");
if ("false".equals(prop)) {
connectionLogEnabled = false;
} else if ("true".equals(prop)) {
connectionLogEnabled = true;
}
}
{
String prop = properties.getProperty("druid.log.stmt");
if ("false".equals(prop)) {
statementLogEnabled = false;
} else if ("true".equals(prop)) {
statementLogEnabled = true;
}
}
{
String prop = properties.getProperty("druid.log.rs");
if ("false".equals(prop)) {
resultSetLogEnabled = false;
} else if ("true".equals(prop)) {
resultSetLogEnabled = true;
}
}
{
String prop = properties.getProperty("druid.log.stmt.executableSql");
if ("true".equals(prop)) {
statementExecutableSqlLogEnable = true;
} else if ("false".equals(prop)) {
statementExecutableSqlLogEnable = false;
}
}
}
同时发现如下,可以发现必须是debug模式才输出rs信息
@Override
public boolean isStatementLogEnabled() {
return statementLogger.isDebugEnabled() && super.isStatementLogEnabled();
}
@Override
public boolean isResultSetLogEnabled() {
return resultSetLogger.isDebugEnabled() && super.isResultSetLogEnabled();
}
通过以上代码,可以输出resultset的结果如下:
[10:52:55.803] DEBUG com.alibaba.druid.filter.logging.Log4j2Filter 142 resultSetLog - {conn-10001, pstmt-20001, rs-50130} open
[10:52:55.803] DEBUG com.alibaba.druid.filter.logging.Log4j2Filter 142 resultSetLog - {conn-10001, pstmt-20001, rs-50130} Header: [NEXTVAL]
[10:52:55.803] DEBUG com.alibaba.druid.filter.logging.Log4j2Filter 142 resultSetLog - {conn-10001, pstmt-20001, rs-50130} Result: [7728]
[10:52:55.803] DEBUG com.alibaba.druid.filter.logging.Slf4jLogFilter 139 resultSetLog - {conn-10001, pstmt-20001, rs-50130} Result: [7728]
[10:52:55.803] DEBUG com.alibaba.druid.filter.logging.Log4j2Filter 142 resultSetLog - {conn-10001, pstmt-20001, rs-50130} closed
[10:52:55.803] DEBUG com.alibaba.druid.filter.logging.Slf4jLogFilter 139 resultSetLog - {conn-10001, pstmt-20001, rs-50130} closed
还是不能满足要求,于是开始看是否可以自定义。阅读代码,发现关键代码如下:
private static void loadFilterConfig(Properties filterProperties, ClassLoader classLoader) throws IOException {
if (classLoader == null) {
return;
}
for (Enumeration<URL> e = classLoader.getResources("META-INF/druid-filter.properties"); e.hasMoreElements();) {
URL url = e.nextElement();
Properties property = new Properties();
InputStream is = null;
try {
is = url.openStream();
property.load(is);
} finally {
JdbcUtils.close(is);
}
filterProperties.putAll(property);
}
}
public static Properties loadFilterConfig() throws IOException {
Properties filterProperties = new Properties();
loadFilterConfig(filterProperties, ClassLoader.getSystemClassLoader());
loadFilterConfig(filterProperties, FilterManager.class.getClassLoader());
loadFilterConfig(filterProperties, Thread.currentThread().getContextClassLoader());
loadFilterConfig(filterProperties, FilterManager.class.getClassLoader());
return filterProperties;
}
最关键代码:
classLoader.getResources(“META-INF/druid-filter.properties”)
即从classpath的多个druid-filter.properties文件读取filter,因此自己在应用中定义个META-INF/druid-filter.properties,内容如下:
druid.filters.log4j24=extend.druid.Log4j2Filter
修改application.properties
spring.datasource.druid.filters= stat,wall,log4j24
使用自定义filter 代替默认的log4j2输出,增加如下代码
private String stmtId(ResultSetProxy resultSet) {
return stmtId(resultSet.getStatementProxy());
}
private String stmtId(StatementProxy statement) {
StringBuffer buf = new StringBuffer();
if (statement instanceof CallableStatementProxy) {
buf.append("cstmt-");
} else if (statement instanceof PreparedStatementProxy) {
buf.append("pstmt-");
} else {
buf.append("stmt-");
}
buf.append(statement.getId());
return buf.toString();
}
@Override
public void resultSet_close(FilterChain chain, ResultSetProxy resultSet) throws SQLException {
chain.resultSet_close(resultSet);
StringBuffer buf = new StringBuffer();
buf.append("{custom-conn-");
buf.append(resultSet.getStatementProxy().getConnectionProxy().getId());
buf.append(", ");
buf.append(stmtId(resultSet));
buf.append(", rs-");
buf.append(resultSet.getId());
buf.append(", FetchSize-");
buf.append(resultSet.getFetchSize());
buf.append(", FetchRowCount-");
buf.append(resultSet.getFetchRowCount());
buf.append("} closed");
if (isResultSetCloseAfterLogEnabled()) {
resultSetLog(buf.toString());
}
}
顺利达到输出fetchsize的目的,同理stat及wall filter也是可以自定义的。
更多推荐

所有评论(0)