Merge pull request #163 from wenshao/master

profile support
This commit is contained in:
温高铁
2012-10-07 02:54:47 -07:00
14 changed files with 465 additions and 105 deletions
@@ -50,6 +50,7 @@ import com.alibaba.druid.stat.JdbcStatementStat;
import com.alibaba.druid.support.json.JSONWriter;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.druid.support.profile.Profiler;
/**
* @author wenshao<szujobs@hotmail.com>
@@ -425,6 +426,8 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean {
}
StatFilterContext.getInstance().executeBefore(sql, inTransaction);
Profiler.enter(sql, Profiler.PROFILE_TYPE_SQL);
}
private final void internalAfterStatementExecute(StatementProxy statement, boolean firstResult,
@@ -433,10 +436,10 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean {
final JdbcStatementStat.Entry entry = getStatementInfo(statement);
final long nowNano = System.nanoTime();
final long nanoSpan = nowNano - entry.getLastExecuteStartNano();
final long nanos = nowNano - entry.getLastExecuteStartNano();
JdbcDataSourceStat dataSourceStat = statement.getConnectionProxy().getDirectDataSource().getDataSourceStat();
dataSourceStat.getStatementStat().afterExecute(nanoSpan);
dataSourceStat.getStatementStat().afterExecute(nanos);
final JdbcSqlStat sqlStat = statement.getSqlStat();
@@ -444,8 +447,8 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean {
sqlStat.incrementExecuteSuccessCount();
sqlStat.decrementRunningCount();
sqlStat.addExecuteTime(statement.getLastExecuteType(), firstResult, nanoSpan);
statement.setLastExecuteTimeNano(nanoSpan);
sqlStat.addExecuteTime(statement.getLastExecuteType(), firstResult, nanos);
statement.setLastExecuteTimeNano(nanos);
if ((!statement.isFirstResultSet()) && statement.getLastExecuteType() == StatementExecuteType.Execute) {
try {
int updateCount = statement.getUpdateCount();
@@ -461,7 +464,7 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean {
}
}
long millis = nanoSpan / (1000 * 1000);
long millis = nanos / (1000 * 1000);
if (millis >= slowSqlMillis) {
String slowParameters = buildSlowParameters(statement);
sqlStat.setLastSlowParameters(slowParameters);
@@ -474,7 +477,9 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean {
}
String sql = statement.getLastExecuteSql();
StatFilterContext.getInstance().executeAfter(sql, nanoSpan, null);
StatFilterContext.getInstance().executeAfter(sql, nanos, null);
Profiler.release(nanos);
}
@Override
@@ -484,11 +489,11 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean {
ConnectionProxy connection = statement.getConnectionProxy();
JdbcConnectionStat.Entry connectionCounter = getConnectionInfo(connection);
long nanoSpan = System.nanoTime() - counter.getLastExecuteStartNano();
long nanos = System.nanoTime() - counter.getLastExecuteStartNano();
JdbcDataSourceStat dataSourceStat = statement.getConnectionProxy().getDirectDataSource().getDataSourceStat();
dataSourceStat.getStatementStat().error(error);
dataSourceStat.getStatementStat().afterExecute(nanoSpan);
dataSourceStat.getStatementStat().afterExecute(nanos);
connectionCounter.error(error);
@@ -497,11 +502,12 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean {
if (sqlStat != null) {
sqlStat.error(error);
sqlStat.addExecuteTime(statement.getLastExecuteType(), statement.isFirstResultSet(), nanoSpan);
statement.setLastExecuteTimeNano(nanoSpan);
sqlStat.addExecuteTime(statement.getLastExecuteType(), statement.isFirstResultSet(), nanos);
statement.setLastExecuteTimeNano(nanos);
}
StatFilterContext.getInstance().executeAfter(sql, nanoSpan, error);
StatFilterContext.getInstance().executeAfter(sql, nanos, error);
Profiler.release(nanos);
}
private String buildSlowParameters(StatementProxy statement) {
@@ -138,7 +138,7 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
protected volatile int queryTimeout;
protected volatile int transactionQueryTimeout;
protected long createErrorCount;
protected AtomicLong createErrorCount = new AtomicLong();
protected long createTimespan;
@@ -205,11 +205,11 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
private final AtomicLong executeCount = new AtomicLong();
protected Throwable createError;
protected Throwable lastError;
protected long lastErrorTimeMillis;
protected Throwable lastCreateError;
protected long lastCreateErrorTimeMillis;
protected volatile Throwable createError;
protected volatile Throwable lastError;
protected volatile long lastErrorTimeMillis;
protected volatile Throwable lastCreateError;
protected volatile long lastCreateErrorTimeMillis;
protected boolean isOracle = false;
@@ -839,7 +839,7 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
}
public long getCreateErrorCount() {
return createErrorCount;
return createErrorCount.get();
}
public int getMaxActive() {
@@ -1269,19 +1269,19 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
validateConnection(conn);
createError = null;
} catch (SQLException ex) {
createErrorCount++;
createErrorCount.incrementAndGet();
createError = ex;
lastCreateError = ex;
lastCreateErrorTimeMillis = System.currentTimeMillis();
throw ex;
} catch (RuntimeException ex) {
createErrorCount++;
createErrorCount.incrementAndGet();
createError = ex;
lastCreateError = ex;
lastCreateErrorTimeMillis = System.currentTimeMillis();
throw ex;
} catch (Error ex) {
createErrorCount++;
createErrorCount.incrementAndGet();
throw ex;
} finally {
long nano = System.nanoTime() - startNano;
@@ -699,7 +699,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
* @param realConnection
* @throws SQLException
*/
private void discardConnection(Connection realConnection) throws SQLException {
private void discardConnection(Connection realConnection) {
JdbcUtils.close(realConnection);
lock.lock();
@@ -825,10 +825,11 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
}
}
try {
final boolean isAutoCommit = holder.isUnderlyingAutoCommit();
final boolean isReadOnly = holder.isUnderlyingReadOnly();
final boolean isAutoCommit = holder.isUnderlyingAutoCommit();
final boolean isReadOnly = holder.isUnderlyingReadOnly();
final boolean testOnReturn = this.isTestOnReturn();
try {
// check need to rollback?
if ((!isAutoCommit) && (!isReadOnly)) {
pooledConnection.rollback();
@@ -837,7 +838,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
// reset holder, restore default settings, clear warnings
holder.reset();
if (isTestOnReturn()) {
if (testOnReturn) {
boolean validate = testConnectionInternal(physicalConnection);
if (!validate) {
JdbcUtils.close(physicalConnection);
@@ -1761,6 +1762,32 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
}
public Map<String, Object> getStatData() {
final int activeCount;
final int activePeak;
final Date activePeakTime;
final int poolingCount;
final int poolingPeak;
final Date poolingPeakTime;
final long connectCount;
final long closeCount;
lock.lock();
try {
poolingCount = this.poolingCount;
poolingPeak = this.poolingPeak;
poolingPeakTime = this.getPoolingPeakTime();
activeCount = this.activeCount;
activePeak = this.activePeak;
activePeakTime = this.getActivePeakTime();
connectCount = this.connectCount;
closeCount = this.closeCount;
} finally {
lock.unlock();
}
Map<String, Object> dataMap = new LinkedHashMap<String, Object>();
dataMap.put("Identity", System.identityHashCode(this));
@@ -1776,13 +1803,13 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
dataMap.put("NotEmptyWaitCount", this.getNotEmptyWaitCount());
dataMap.put("NotEmptyWaitMillis", this.getNotEmptyWaitMillis());
dataMap.put("PoolingCount", this.getPoolingCount());
dataMap.put("PoolingPeak", this.getPoolingPeak());
dataMap.put("PoolingPeakTime", this.getPoolingPeakTime() == null ? null : this.getPoolingPeakTime().toString());
dataMap.put("PoolingCount", poolingCount);
dataMap.put("PoolingPeak", poolingPeak);
dataMap.put("PoolingPeakTime", poolingPeakTime);
dataMap.put("ActiveCount", this.getActiveCount());
dataMap.put("ActivePeak", this.getActivePeak());
dataMap.put("ActivePeakTime", this.getActivePeakTime() == null ? null : this.getActivePeakTime().toString());
dataMap.put("ActiveCount", activeCount);
dataMap.put("ActivePeak", activePeak);
dataMap.put("ActivePeakTime", activePeakTime);
dataMap.put("InitialSize", this.getInitialSize());
dataMap.put("MinIdle", this.getMinIdle());
@@ -1802,8 +1829,8 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
dataMap.put("DefaultReadOnly", this.isDefaultAutoCommit());
dataMap.put("DefaultTransactionIsolation", this.getDefaultTransactionIsolation());
dataMap.put("LogicConnectCount", this.getConnectCount());
dataMap.put("LogicCloseCount", this.getCloseCount());
dataMap.put("LogicConnectCount", connectCount);
dataMap.put("LogicCloseCount", closeCount);
dataMap.put("LogicConnectErrorCount", this.getConnectErrorCount());
dataMap.put("PhysicalConnectCount", this.getCreateCount());
@@ -18,6 +18,7 @@ package com.alibaba.druid.support.http;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.servlet.Filter;
@@ -41,6 +42,9 @@ import com.alibaba.druid.support.http.stat.WebSessionStat;
import com.alibaba.druid.support.http.stat.WebURIStat;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.druid.support.profile.ProfileEntryKey;
import com.alibaba.druid.support.profile.ProfileEntryReqStat;
import com.alibaba.druid.support.profile.Profiler;
import com.alibaba.druid.util.DruidWebUtils;
import com.alibaba.druid.util.PatternMatcher;
import com.alibaba.druid.util.ServletPathMatcher;
@@ -55,6 +59,7 @@ public class WebStatFilter implements Filter {
private final static Log LOG = LogFactory.getLog(WebStatFilter.class);
public final static String PARAM_NAME_PORFILE_ENABLE = "profileEnable";
public final static String PARAM_NAME_SESSION_STAT_ENABLE = "sessionStatEnable";
public final static String PARAM_NAME_SESSION_STAT_MAX_COUNT = "sessionStatMaxCount";
public static final String PARAM_NAME_EXCLUSIONS = "exclusions";
@@ -75,6 +80,7 @@ public class WebStatFilter implements Filter {
private boolean sessionStatEnable = true;
private int sessionStatMaxCount = DEFAULT_MAX_STAT_SESSION_COUNT;
private boolean createSession = false;
private boolean profileEnable = false;
private String contextPath;
@@ -114,6 +120,10 @@ public class WebStatFilter implements Filter {
}
}
if (isProfileEnable()) {
Profiler.initLocal();
}
// 第一次访问时,uriStat这里为null,是为了防止404攻击。
if (uriStat != null) {
uriStat.beforeInvoke();
@@ -177,6 +187,12 @@ public class WebStatFilter implements Filter {
}
WebRequestStat.set(null);
if (isProfileEnable()) {
Map<ProfileEntryKey, ProfileEntryReqStat> requestStatsMap = Profiler.getStatsMap();
uriStat.getProfiletat().record(requestStatsMap);
Profiler.removeLocal();
}
}
}
@@ -339,6 +355,20 @@ public class WebStatFilter implements Filter {
}
}
}
{
String param = config.getInitParameter(PARAM_NAME_PORFILE_ENABLE);
if (param != null && param.trim().length() != 0) {
param = param.trim();
if ("true".equals(param)) {
this.profileEnable = true;
} else if ("false".equals(param)) {
this.profileEnable = false;
} else {
LOG.error("WebStatFilter Parameter '" + PARAM_NAME_PORFILE_ENABLE + "' config error");
}
}
}
{
String param = config.getInitParameter(PARAM_NAME_SESSION_STAT_MAX_COUNT);
if (param != null && param.trim().length() != 0) {
@@ -376,6 +406,14 @@ public class WebStatFilter implements Filter {
this.sessionStatEnable = sessionStatEnable;
}
public boolean isProfileEnable() {
return profileEnable;
}
public void setProfileEnable(boolean profileEnable) {
this.profileEnable = profileEnable;
}
public WebAppStat getWebAppStat() {
return webAppStat;
}
@@ -21,6 +21,9 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import com.alibaba.druid.support.profile.ProfileStat;
import com.alibaba.druid.support.profile.Profiler;
public class WebURIStat {
private final String uri;
@@ -54,6 +57,8 @@ public class WebURIStat {
private volatile long lastAccessTimeMillis = -1L;
private ProfileStat profiletat = new ProfileStat();
private final static ThreadLocal<WebURIStat> currentLocal = new ThreadLocal<WebURIStat>();
public WebURIStat(String uri){
@@ -93,6 +98,8 @@ public class WebURIStat {
if (requestStat != null) {
this.setLastAccessTimeMillis(requestStat.getStartMillis());
}
Profiler.enter(uri, Profiler.PROFILE_TYPE_WEB);
}
public void afterInvoke(Throwable error, long nanos) {
@@ -154,16 +161,18 @@ public class WebURIStat {
this.jdbcExecuteErrorCount.addAndGet(localStat.getJdbcExecuteErrorCount());
this.jdbcExecuteTimeNano.addAndGet(localStat.getJdbcExecuteTimeNano());
this.addJdbcPoolConnectionOpenCount(localStat.getJdbcPoolConnectionOpenCount());
this.addJdbcPoolConnectionCloseCount(localStat.getJdbcPoolConnectionCloseCount());
this.addJdbcResultSetOpenCount(localStat.getJdbcResultSetOpenCount());
this.addJdbcResultSetCloseCount(localStat.getJdbcResultSetCloseCount());
}
}
currentLocal.set(null);
Profiler.release(nanos);
}
public int getRunningCount() {
@@ -301,7 +310,7 @@ public class WebURIStat {
public long getJdbcResultSetOpenCount() {
return jdbcResultSetOpenCount.get();
}
public void addJdbcResultSetOpenCount(long delta) {
jdbcResultSetOpenCount.addAndGet(delta);
}
@@ -309,11 +318,15 @@ public class WebURIStat {
public long getJdbcResultSetCloseCount() {
return jdbcResultSetCloseCount.get();
}
public void addJdbcResultSetCloseCount(long delta) {
jdbcResultSetCloseCount.addAndGet(delta);
}
public ProfileStat getProfiletat() {
return profiletat;
}
public Map<String, Object> getStatData() {
Map<String, Object> data = new LinkedHashMap<String, Object>();
@@ -341,10 +354,12 @@ public class WebURIStat {
data.put("JdbcPoolConnectionOpenCount", this.getJdbcPoolConnectionOpenCount());
data.put("JdbcPoolConnectionCloseCount", this.getJdbcPoolConnectionCloseCount());
data.put("JdbcResultSetOpenCount", this.getJdbcResultSetOpenCount());
data.put("JdbcResultSetCloseCount", this.getJdbcResultSetCloseCount());
data.put("Profiles", this.getProfiletat().getStatData());
return data;
}
}
@@ -2,41 +2,51 @@ package com.alibaba.druid.support.profile;
public class ProfileEntry {
private final Key key;
private final String type;
private final ProfileEntry parent;
private final ProfileEntryKey key;
public ProfileEntry(Key key, String type){
super();
private int executeCount = 0;
private long executeTimeNanos = 0;
public ProfileEntry(ProfileEntry parent, ProfileEntryKey key){
this.parent = parent;
this.key = key;
this.type = type;
}
public Key getKey() {
public ProfileEntry getParent() {
return parent;
}
public ProfileEntryKey getKey() {
return key;
}
public String getParentName() {
return key.getParentName();
}
public String getName() {
return key.getName();
}
public String getType() {
return type;
return key.getType();
}
public static class Key {
private String parent;
private String name;
public Key(String parentName, String name){
super();
this.parent = parentName;
this.name = name;
}
public String getParent() {
return parent;
}
public String getName() {
return name;
}
public int getExecuteCount() {
return executeCount;
}
public void incrementExecuteCount() {
this.executeCount++;
}
public long getExecuteTimeNanos() {
return executeTimeNanos;
}
public void addExecuteTimeNanos(long nanos) {
this.executeTimeNanos += nanos;
}
}
@@ -0,0 +1,65 @@
package com.alibaba.druid.support.profile;
public class ProfileEntryKey {
private final String parentName;
private final String name;
private final String type;
public ProfileEntryKey(String parentName, String name, String type){
this.parentName = parentName;
this.name = name;
this.type = type;
}
public String getParentName() {
return parentName;
}
public String getName() {
return name;
}
public String getType() {
return type;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((parentName == null) ? 0 : parentName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ProfileEntryKey other = (ProfileEntryKey) obj;
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
if (parentName == null) {
if (other.parentName != null) {
return false;
}
} else if (!parentName.equals(other.parentName)) {
return false;
}
return true;
}
}
@@ -0,0 +1,24 @@
package com.alibaba.druid.support.profile;
public class ProfileEntryReqStat {
private long executeCount;
private long executeTimeNanos;
public long getExecuteCount() {
return executeCount;
}
public void incrementExecuteCount() {
this.executeCount++;
}
public long getExecuteTimeNanos() {
return executeTimeNanos;
}
public void addExecuteTimeNanos(long nanos) {
this.executeTimeNanos += nanos;
}
}
@@ -0,0 +1,33 @@
package com.alibaba.druid.support.profile;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
public class ProfileEntryStat {
private volatile long executeCount = 0;
private volatile long executeTimeNanos = 0;
private static final AtomicLongFieldUpdater<ProfileEntryStat> executeCountUpdater;
private static final AtomicLongFieldUpdater<ProfileEntryStat> executeTimeNanosUpdater;
static {
executeCountUpdater = AtomicLongFieldUpdater.newUpdater(ProfileEntryStat.class, "executeCount");
executeTimeNanosUpdater = AtomicLongFieldUpdater.newUpdater(ProfileEntryStat.class, "executeTimeNanos");
}
public long getExecuteCount() {
return executeCount;
}
public void addExecuteCount(long delta) {
executeCountUpdater.addAndGet(this, delta);
}
public long getExecuteTimeNanos() {
return executeTimeNanos;
}
public void addExecuteTimeNanos(long delta) {
executeTimeNanosUpdater.addAndGet(this, delta);
}
}
@@ -0,0 +1,55 @@
package com.alibaba.druid.support.profile;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ProfileStat {
private ConcurrentHashMap<ProfileEntryKey, ProfileEntryStat> entries = new ConcurrentHashMap<ProfileEntryKey, ProfileEntryStat>();
public ConcurrentHashMap<ProfileEntryKey, ProfileEntryStat> getEntries() {
return entries;
}
public void record(Map<ProfileEntryKey, ProfileEntryReqStat> requestStatsMap) {
if (requestStatsMap == null) {
return;
}
for (Map.Entry<ProfileEntryKey, ProfileEntryReqStat> entry : requestStatsMap.entrySet()) {
ProfileEntryKey entryKey = entry.getKey();
ProfileEntryReqStat reqEntryStat = entry.getValue();
ProfileEntryStat entryStat = entries.get(entryKey);
if (entryStat == null) {
entries.putIfAbsent(entryKey, new ProfileEntryStat());
entryStat = entries.get(entryKey);
}
entryStat.addExecuteCount(reqEntryStat.getExecuteCount());
entryStat.addExecuteTimeNanos(reqEntryStat.getExecuteTimeNanos());
}
}
public Map<Map<String, Object>, Map<String, Object>> getStatData() {
Map<Map<String, Object>, Map<String, Object>> data = new LinkedHashMap<Map<String, Object>, Map<String, Object>>();
for (Map.Entry<ProfileEntryKey, ProfileEntryStat> entry : entries.entrySet()) {
Map<String, Object> key = new LinkedHashMap<String, Object>();
Map<String, Object> value = new LinkedHashMap<String, Object>();
key.put("Parent", entry.getKey().getParentName());
key.put("Name", entry.getKey().getName());
key.put("Type", entry.getKey().getType());
value.put("ExecuteCount", entry.getValue().getExecuteCount());
value.put("ExecuteTimeNanos", entry.getValue().getExecuteTimeNanos());
data.put(key, value);
}
return data;
}
}
@@ -3,49 +3,34 @@ package com.alibaba.druid.support.profile;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.druid.support.profile.ProfileEntry.Key;
public class Profiler {
public static ThreadLocal<Boolean> enableLocal = new ThreadLocal<Boolean>();
public static final String PROFILE_TYPE_WEB = "WEB";
public static final String PROFILE_TYPE_SPRING = "SPRING";
public static final String PROFILE_TYPE_SQL = "SQL";
private static ThreadLocal<Map<ProfileEntry.Key, ProfileEntry>> entriesLocal = new ThreadLocal<Map<Key, ProfileEntry>>();
private static ThreadLocal<Map<ProfileEntryKey, ProfileEntryReqStat>> statsMapLocal = new ThreadLocal<Map<ProfileEntryKey, ProfileEntryReqStat>>();
private final static ThreadLocal<ProfileEntry> currentLocal = new ThreadLocal<ProfileEntry>();
public static void setThreadLocalEnable() {
enableLocal.set(true);
}
public static void setThreadLocalDisable() {
enableLocal.remove();
}
private final static ThreadLocal<ProfileEntry> currentLocal = new ThreadLocal<ProfileEntry>();
public static boolean isEnable() {
return Boolean.TRUE == enableLocal.get();
return statsMapLocal != null;
}
public static void enter(String name, String type, long startNano) {
public static void enter(String name, String type) {
if (!isEnable()) {
return;
}
ProfileEntry parent = currentLocal.get();
String parentName = null;
if (parent != null) {
parentName = parent.getKey().getName();
parentName = parent.getName();
}
ProfileEntry.Key key = new ProfileEntry.Key(parentName, name);
Map<ProfileEntry.Key, ProfileEntry> entries = entriesLocal.get();
if (entries == null) {
entries = new HashMap<ProfileEntry.Key, ProfileEntry>();
entriesLocal.set(entries);
}
ProfileEntry entry = entries.get(key);
if (entry == null) {
entry = new ProfileEntry(key, type);
entries.put(key, entry);
}
ProfileEntryKey key = new ProfileEntryKey(parentName, name, type);
ProfileEntry entry = new ProfileEntry(parent, key);
currentLocal.set(entry);
}
@@ -53,7 +38,36 @@ public class Profiler {
return currentLocal.get();
}
public static void release(long nanoSpan) {
public static void release(long nanos) {
ProfileEntry current = currentLocal.get();
currentLocal.set(current.getParent());
ProfileEntryReqStat stat = null;
Map<ProfileEntryKey, ProfileEntryReqStat> statsMap = statsMapLocal.get();
if (statsMap == null) {
return;
}
stat = statsMap.get(current.getKey());
if (stat == null) {
stat = new ProfileEntryReqStat();
statsMap.put(current.getKey(), stat);
}
stat.incrementExecuteCount();
stat.addExecuteTimeNanos(nanos);
}
public static Map<ProfileEntryKey, ProfileEntryReqStat> getStatsMap() {
return statsMapLocal.get();
}
public static void initLocal() {
statsMapLocal.set(new HashMap<ProfileEntryKey, ProfileEntryReqStat>());
}
public static void removeLocal() {
statsMapLocal.remove();
}
}
@@ -30,6 +30,8 @@ import com.alibaba.druid.support.logging.LogFactory;
public class DruidStatInterceptor implements MethodInterceptor, InitializingBean, DisposableBean {
public static final String PROP_NAME_PORFILE = "druid.profile";
private final static Log LOG = LogFactory.getLog(DruidStatInterceptor.class);
private static SpringStat springStat = new SpringStat();
@@ -21,6 +21,8 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import com.alibaba.druid.support.profile.Profiler;
public class SpringMethodStat {
private final static ThreadLocal<SpringMethodStat> currentLocal = new ThreadLocal<SpringMethodStat>();
@@ -72,7 +74,7 @@ public class SpringMethodStat {
jdbcPoolConnectionOpenCount.set(0);
jdbcPoolConnectionCloseCount.set(0);
jdbcResultSetOpenCount.set(0);
jdbcResultSetCloseCount.set(0);
@@ -111,6 +113,8 @@ public class SpringMethodStat {
}
executeCount.incrementAndGet();
Profiler.enter(methodInfo.getSignature(), Profiler.PROFILE_TYPE_SPRING);
}
public void afterInvoke(Throwable error, long nanos) {
@@ -122,6 +126,8 @@ public class SpringMethodStat {
lastError = error;
lastErrorTimeMillis = System.currentTimeMillis();
}
Profiler.release(nanos);
}
public Throwable getLastError() {
@@ -263,15 +269,15 @@ public class SpringMethodStat {
public void incrementJdbcPoolConnectionCloseCount() {
jdbcPoolConnectionCloseCount.incrementAndGet();
}
public long getJdbcResultSetOpenCount() {
return jdbcResultSetOpenCount.get();
}
public void addJdbcResultSetOpenCount(long delta) {
jdbcResultSetOpenCount.addAndGet(delta);
}
public void incrementJdbcResultSetOpenCount() {
jdbcResultSetOpenCount.incrementAndGet();
}
@@ -279,11 +285,11 @@ public class SpringMethodStat {
public long getJdbcResultSetCloseCount() {
return jdbcResultSetCloseCount.get();
}
public void addJdbcResultSetCloseCount(long delta) {
jdbcResultSetCloseCount.addAndGet(delta);
}
public void incrementJdbcResultSetCloseCount() {
jdbcResultSetCloseCount.incrementAndGet();
}
@@ -305,10 +311,10 @@ public class SpringMethodStat {
data.put("JdbcPoolConnectionOpenCount", this.getJdbcPoolConnectionOpenCount());
data.put("JdbcPoolConnectionCloseCount", this.getJdbcPoolConnectionCloseCount());
data.put("JdbcResultSetOpenCount", this.getJdbcResultSetOpenCount());
data.put("JdbcResultSetCloseCount", this.getJdbcResultSetCloseCount());
data.put("JdbcExecuteCount", this.getJdbcExecuteCount());
data.put("JdbcExecuteErrorCount", this.getJdbcExecuteErrorCount());
data.put("JdbcExecuteTimeMillis", this.getJdbcExecuteTimeMillis());
@@ -0,0 +1,65 @@
package com.alibaba.druid.bvt.support.profile;
import junit.framework.Assert;
import junit.framework.TestCase;
import com.alibaba.druid.support.profile.ProfileEntryKey;
import com.alibaba.druid.support.profile.ProfileEntryReqStat;
import com.alibaba.druid.support.profile.Profiler;
public class ProfilerTest extends TestCase {
public void test_profile() throws Exception {
for (int i = 0; i < 10; ++i) {
req();
}
}
private void req() {
Profiler.initLocal();
Profiler.enter("/", Profiler.PROFILE_TYPE_WEB);
for (int i = 0; i < 100; ++i) {
execA();
}
Assert.assertEquals(2, Profiler.getStatsMap().size());
{
ProfileEntryReqStat stat = Profiler.getStatsMap().get(new ProfileEntryKey("/", "com.xxx.a(int)",
Profiler.PROFILE_TYPE_SPRING));
Assert.assertEquals(100, stat.getExecuteCount());
Assert.assertEquals(100, stat.getExecuteTimeNanos());
}
{
ProfileEntryReqStat stat = Profiler.getStatsMap().get(new ProfileEntryKey("com.xxx.a(int)",
"com.xxx.b(int)",
Profiler.PROFILE_TYPE_SPRING));
Assert.assertEquals(1000 * 100, stat.getExecuteCount());
Assert.assertEquals(1000 * 100, stat.getExecuteTimeNanos());
}
Profiler.release(1);
Assert.assertEquals(3, Profiler.getStatsMap().size());
Profiler.removeLocal();
}
private void execA() {
Profiler.enter("com.xxx.a(int)", Profiler.PROFILE_TYPE_SPRING);
for (int i = 0; i < 1000; ++i) {
execB();
}
Profiler.release(1);
}
private void execB() {
Profiler.enter("com.xxx.b(int)", Profiler.PROFILE_TYPE_SPRING);
Profiler.release(1);
}
}