5-DruidDataSource监控信息定期打印日志线程LogStatsThread
5.1 简介
前面我们说了初始化《3-Connection连接数据库之前的初始化操作》
初始化线程池时候初始化了一个打印线程信息的线程 LogStatsThread对象logStatsThread创建,调用代码如下所示:
DruidDataSource类型的init方法中调用创建和打印监控信息到日志的线程
createAndLogThread();
具体逻辑如下:
DruidDataSource类型的createAndLogThread方法
private void createAndLogThread() {
if (this.timeBetweenLogStatsMillis <= 0) {
return;
}
String threadName = "Druid-ConnectionPool-Log-" + System.identityHashCode(this);
logStatsThread = new LogStatsThread(threadName);
logStatsThread.start();
this.resetStatEnable = false;
}
5.2 线程类
5.2.1 线程类LogStatsThread
监控打印到日志的类型LogStatsThread
public class LogStatsThread extends Thread {
public LogStatsThread(String name){
super(name);
this.setDaemon(true);
}
public void run() {
try {
for (;;) {
try {
logStats();
} catch (Exception e) {
LOG.error("logStats error", e);
}
Thread.sleep(timeBetweenLogStatsMillis);
}
} catch (InterruptedException e) {
// skip
}
}
}
可以看到上面代码使用了循环,然后使用Thread.sleep来进行休眠timeBetweenLogStatsMillis时间,这个代码性能并不好,休眠还占用着线程应该使用wait优化下,调试时候可以指定参数如下参数开启:
下面我配置了10毫秒可以根据实际情况修改
-Ddruid.timeBetweenLogStatsMillis=10
5.2.2 取值然后打印
public void logStats() {
final DruidDataSourceStatLogger statLogger = this.statLogger;
if (statLogger == null) {
return;
}
DruidDataSourceStatValue statValue = getStatValueAndReset();
statLogger.log(statValue);
}
5.2.3 取值
public DruidDataSourceStatValue getStatValueAndReset() {
DruidDataSourceStatValue value = new DruidDataSourceStatValue();
lock.lock();
try {
value.setPoolingCount(this.poolingCount);
value.setPoolingPeak(this.poolingPeak);
value.setPoolingPeakTime(this.poolingPeakTime);
value.setActiveCount(this.activeCount);
value.setActivePeak(this.activePeak);
value.setActivePeakTime(this.activePeakTime);
value.setConnectCount(this.connectCount);
value.setCloseCount(this.closeCount);
value.setWaitThreadCount(lock.getWaitQueueLength(notEmpty));
value.setNotEmptyWaitCount(this.notEmptyWaitCount);
value.setNotEmptyWaitNanos(this.notEmptyWaitNanos);
value.setKeepAliveCheckCount(this.keepAliveCheckCount);
// reset
this.poolingPeak = 0;
this.poolingPeakTime = 0;
this.activePeak = 0;
this.activePeakTime = 0;
this.connectCount = 0;
this.closeCount = 0;
this.keepAliveCheckCount = 0;
this.notEmptyWaitCount = 0;
this.notEmptyWaitNanos = 0;
} finally {
lock.unlock();
}
value.setName(this.getName());
value.setDbType(this.dbTypeName);
value.setDriverClassName(this.getDriverClassName());
value.setUrl(this.getUrl());
value.setUserName(this.getUsername());
value.setFilterClassNames(this.getFilterClassNames());
value.setInitialSize(this.getInitialSize());
value.setMinIdle(this.getMinIdle());
value.setMaxActive(this.getMaxActive());
value.setQueryTimeout(this.getQueryTimeout());
value.setTransactionQueryTimeout(this.getTransactionQueryTimeout());
value.setLoginTimeout(this.getLoginTimeout());
value.setValidConnectionCheckerClassName(this.getValidConnectionCheckerClassName());
value.setExceptionSorterClassName(this.getExceptionSorterClassName());
value.setTestOnBorrow(this.testOnBorrow);
value.setTestOnReturn(this.testOnReturn);
value.setTestWhileIdle(this.testWhileIdle);
value.setDefaultAutoCommit(this.isDefaultAutoCommit());
if (defaultReadOnly != null) {
value.setDefaultReadOnly(defaultReadOnly);
}
value.setDefaultTransactionIsolation(this.getDefaultTransactionIsolation());
value.setLogicConnectErrorCount(connectErrorCountUpdater.getAndSet(this, 0));
value.setPhysicalConnectCount(createCountUpdater.getAndSet(this, 0));
value.setPhysicalCloseCount(destroyCountUpdater.getAndSet(this, 0));
value.setPhysicalConnectErrorCount(createErrorCountUpdater.getAndSet(this, 0));
value.setExecuteCount(this.getAndResetExecuteCount());
value.setErrorCount(errorCountUpdater.getAndSet(this, 0));
value.setCommitCount(commitCountUpdater.getAndSet(this, 0));
value.setRollbackCount(rollbackCountUpdater.getAndSet(this, 0));
value.setPstmtCacheHitCount(cachedPreparedStatementHitCountUpdater.getAndSet(this,0));
value.setPstmtCacheMissCount(cachedPreparedStatementMissCountUpdater.getAndSet(this, 0));
value.setStartTransactionCount(startTransactionCountUpdater.getAndSet(this, 0));
value.setTransactionHistogram(this.getTransactionHistogram().toArrayAndReset());
value.setConnectionHoldTimeHistogram(this.getDataSourceStat().getConnectionHoldHistogram().toArrayAndReset());
value.setRemoveAbandoned(this.isRemoveAbandoned());
value.setClobOpenCount(this.getDataSourceStat().getClobOpenCountAndReset());
value.setBlobOpenCount(this.getDataSourceStat().getBlobOpenCountAndReset());
value.setSqlSkipCount(this.getDataSourceStat().getSkipSqlCountAndReset());
value.setSqlList(this.getDataSourceStat().getSqlStatMapAndReset());
return value;
}
5.2.4 打印
DruidDataSourceStatLoggerImpl类型的log方法
public void log(DruidDataSourceStatValue statValue) {
if (!isLogEnable()) {
return;
}
Map<String, Object> map = new LinkedHashMap<String, Object>();
map.put("url", statValue.url);
map.put("dbType", statValue.getDbType());
map.put("name", statValue.getName());
map.put("activeCount", statValue.getActiveCount());
if (statValue.getActivePeak() > 0) {
map.put("activePeak", statValue.getActivePeak());
map.put("activePeakTime", statValue.getActivePeakTime());
}
map.put("poolingCount", statValue.getPoolingCount());
if (statValue.getPoolingPeak() > 0) {
map.put("poolingPeak", statValue.getPoolingPeak());
map.put("poolingPeakTime", statValue.getPoolingPeakTime());
}
map.put("connectCount", statValue.getConnectCount());
map.put("closeCount", statValue.getCloseCount());
if (statValue.getWaitThreadCount() > 0) {
map.put("waitThreadCount", statValue.getWaitThreadCount());
}
if (statValue.getNotEmptyWaitCount() > 0) {
map.put("notEmptyWaitCount", statValue.getNotEmptyWaitCount());
}
if (statValue.getNotEmptyWaitMillis() > 0) {
map.put("notEmptyWaitMillis", statValue.getNotEmptyWaitMillis());
}
if (statValue.getLogicConnectErrorCount() > 0) {
map.put("logicConnectErrorCount", statValue.getLogicConnectErrorCount());
}
if (statValue.getPhysicalConnectCount() > 0) {
map.put("physicalConnectCount", statValue.getPhysicalConnectCount());
}
if (statValue.getPhysicalCloseCount() > 0) {
map.put("physicalCloseCount", statValue.getPhysicalCloseCount());
}
if (statValue.getPhysicalConnectErrorCount() > 0) {
map.put("physicalConnectErrorCount", statValue.getPhysicalConnectErrorCount());
}
if (statValue.getExecuteCount() > 0) {
map.put("executeCount", statValue.getExecuteCount());
}
if (statValue.getErrorCount() > 0) {
map.put("errorCount", statValue.getErrorCount());
}
if (statValue.getCommitCount() > 0) {
map.put("commitCount", statValue.getCommitCount());
}
if (statValue.getRollbackCount() > 0) {
map.put("rollbackCount", statValue.getRollbackCount());
}
if (statValue.getPstmtCacheHitCount() > 0) {
map.put("pstmtCacheHitCount", statValue.getPstmtCacheHitCount());
}
if (statValue.getPstmtCacheMissCount() > 0) {
map.put("pstmtCacheMissCount", statValue.getPstmtCacheMissCount());
}
if (statValue.getStartTransactionCount() > 0) {
map.put("startTransactionCount", statValue.getStartTransactionCount());
map.put("transactionHistogram", rtrim(statValue.getTransactionHistogram()));
}
if (statValue.getConnectCount() > 0) {
map.put("connectionHoldTimeHistogram", rtrim(statValue.getConnectionHoldTimeHistogram()));
}
if (statValue.getClobOpenCount() > 0) {
map.put("clobOpenCount", statValue.getClobOpenCount());
}
if (statValue.getBlobOpenCount() > 0) {
map.put("blobOpenCount", statValue.getBlobOpenCount());
}
if (statValue.getSqlSkipCount() > 0) {
map.put("sqlSkipCount", statValue.getSqlSkipCount());
}
ArrayList<Map<String, Object>> sqlList = new ArrayList<Map<String, Object>>();
if (statValue.sqlList.size() > 0) {
for (JdbcSqlStatValue sqlStat : statValue.getSqlList()) {
Map<String, Object> sqlStatMap = new LinkedHashMap<String, Object>();
sqlStatMap.put("sql", sqlStat.getSql());
if (sqlStat.getExecuteCount() > 0) {
sqlStatMap.put("executeCount", sqlStat.getExecuteCount());
sqlStatMap.put("executeMillisMax", sqlStat.getExecuteMillisMax());
sqlStatMap.put("executeMillisTotal", sqlStat.getExecuteMillisTotal());
sqlStatMap.put("executeHistogram", rtrim(sqlStat.getExecuteHistogram()));
sqlStatMap.put("executeAndResultHoldHistogram", rtrim(sqlStat.getExecuteAndResultHoldHistogram()));
}
long executeErrorCount = sqlStat.getExecuteErrorCount();
if (executeErrorCount > 0) {
sqlStatMap.put("executeErrorCount", executeErrorCount);
}
int runningCount = sqlStat.getRunningCount();
if (runningCount > 0) {
sqlStatMap.put("runningCount", runningCount);
}
int concurrentMax = sqlStat.getConcurrentMax();
if (concurrentMax > 0) {
sqlStatMap.put("concurrentMax", concurrentMax);
}
if (sqlStat.getFetchRowCount() > 0) {
sqlStatMap.put("fetchRowCount", sqlStat.getFetchRowCount());
sqlStatMap.put("fetchRowCountMax", sqlStat.getFetchRowCountMax());
sqlStatMap.put("fetchRowHistogram", rtrim(sqlStat.getFetchRowHistogram()));
}
if (sqlStat.getUpdateCount() > 0) {
sqlStatMap.put("updateCount", sqlStat.getUpdateCount());
sqlStatMap.put("updateCountMax", sqlStat.getUpdateCountMax());
sqlStatMap.put("updateHistogram", rtrim(sqlStat.getUpdateHistogram()));
}
if (sqlStat.getInTransactionCount() > 0) {
sqlStatMap.put("inTransactionCount", sqlStat.getInTransactionCount());
}
if (sqlStat.getClobOpenCount() > 0) {
sqlStatMap.put("clobOpenCount", sqlStat.getClobOpenCount());
}
if (sqlStat.getBlobOpenCount() > 0) {
sqlStatMap.put("blobOpenCount", sqlStat.getBlobOpenCount());
}
sqlList.add(sqlStatMap);
}
map.put("sqlList", sqlList);
}
if (statValue.getKeepAliveCheckCount() > 0) {
map.put("keepAliveCheckCount", statValue.getKeepAliveCheckCount());
}
String text = JSONUtils.toJSONString(map);
log(text);
}
5.2.5 打印的样例数据如下
[16/06/22 22:29:08:033 CST] Druid-ConnectionPool-Log-1636506029 INFO pool.DruidDataSourceStatLoggerImpl: {"url":"jdbc:mysql://localhost:3306/druid?allowMultiQueries=true","dbType":"mysql","name":"DataSource-1636506029","activeCount":1,"poolingCount":0,"connectCount":0,"closeCount":0,"executeCount":1}