/* * Copyright 1999-2017 Alibaba Group Holding Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.druid.support.http.stat; import com.alibaba.druid.support.profile.ProfileStat; import java.util.Date; import java.util.Map; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicLongFieldUpdater; import static com.alibaba.druid.util.JdbcSqlStatUtils.get; public class WebURIStat { private final String uri; private volatile int runningCount; private volatile int concurrentMax; private volatile long requestCount; private volatile long requestTimeNano; final static AtomicIntegerFieldUpdater<WebURIStat> runningCountUpdater = AtomicIntegerFieldUpdater.newUpdater(WebURIStat.class, "runningCount"); final static AtomicIntegerFieldUpdater<WebURIStat> concurrentMaxUpdater = AtomicIntegerFieldUpdater.newUpdater(WebURIStat.class, "concurrentMax"); final static AtomicLongFieldUpdater<WebURIStat> requestCountUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "requestCount"); final static AtomicLongFieldUpdater<WebURIStat> requestTimeNanoUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "requestTimeNano"); private volatile long jdbcFetchRowCount; private volatile long jdbcFetchRowPeak; // 单次请求读取行数的峰值 final static AtomicLongFieldUpdater<WebURIStat> jdbcFetchRowCountUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "jdbcFetchRowCount"); final static AtomicLongFieldUpdater<WebURIStat> jdbcFetchRowPeakUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "jdbcFetchRowPeak"); private volatile long jdbcUpdateCount; private volatile long jdbcUpdatePeak; // 单次请求更新行数的峰值 final static AtomicLongFieldUpdater<WebURIStat> jdbcUpdateCountUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "jdbcUpdateCount"); final static AtomicLongFieldUpdater<WebURIStat> jdbcUpdatePeakUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "jdbcUpdatePeak"); private volatile long jdbcExecuteCount; private volatile long jdbcExecuteErrorCount; private volatile long jdbcExecutePeak; // 单次请求执行SQL次数的峰值 private volatile long jdbcExecuteTimeNano; final static AtomicLongFieldUpdater<WebURIStat> jdbcExecuteCountUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "jdbcExecuteCount"); final static AtomicLongFieldUpdater<WebURIStat> jdbcExecuteErrorCountUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "jdbcExecuteErrorCount"); final static AtomicLongFieldUpdater<WebURIStat> jdbcExecutePeakUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "jdbcExecutePeak"); final static AtomicLongFieldUpdater<WebURIStat> jdbcExecuteTimeNanoUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "jdbcExecuteTimeNano"); private volatile long jdbcCommitCount; private volatile long jdbcRollbackCount; final static AtomicLongFieldUpdater<WebURIStat> jdbcCommitCountUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "jdbcCommitCount"); final static AtomicLongFieldUpdater<WebURIStat> jdbcRollbackCountUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "jdbcRollbackCount"); private volatile long jdbcPoolConnectionOpenCount; private volatile long jdbcPoolConnectionCloseCount; final static AtomicLongFieldUpdater<WebURIStat> jdbcPoolConnectionOpenCountUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "jdbcPoolConnectionOpenCount"); final static AtomicLongFieldUpdater<WebURIStat> jdbcPoolConnectionCloseCountUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "jdbcPoolConnectionCloseCount"); private volatile long jdbcResultSetOpenCount; private volatile long jdbcResultSetCloseCount; private volatile long errorCount; private volatile long lastAccessTimeMillis = -1L; private volatile ProfileStat profiletat = new ProfileStat(); final static AtomicLongFieldUpdater<WebURIStat> jdbcResultSetOpenCountUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "jdbcResultSetOpenCount"); final static AtomicLongFieldUpdater<WebURIStat> jdbcResultSetCloseCountUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "jdbcResultSetCloseCount"); final static AtomicLongFieldUpdater<WebURIStat> errorCountUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "errorCount"); final static AtomicLongFieldUpdater<WebURIStat> lastAccessTimeMillisUpdater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "lastAccessTimeMillis"); private final static ThreadLocal<WebURIStat> currentLocal = new ThreadLocal<WebURIStat>(); private volatile long histogram_0_1; private volatile long histogram_1_10; private volatile long histogram_10_100; private volatile long histogram_100_1000; private volatile int histogram_1000_10000; private volatile int histogram_10000_100000; private volatile int histogram_100000_1000000; private volatile int histogram_1000000_more; final static AtomicLongFieldUpdater<WebURIStat> histogram_0_1_Updater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "histogram_0_1"); final static AtomicLongFieldUpdater<WebURIStat> histogram_1_10_Updater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "histogram_1_10"); final static AtomicLongFieldUpdater<WebURIStat> histogram_10_100_Updater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "histogram_10_100"); final static AtomicLongFieldUpdater<WebURIStat> histogram_100_1000_Updater = AtomicLongFieldUpdater.newUpdater(WebURIStat.class, "histogram_100_1000"); final static AtomicIntegerFieldUpdater<WebURIStat> histogram_1000_10000_Updater = AtomicIntegerFieldUpdater.newUpdater(WebURIStat.class, "histogram_1000_10000"); final static AtomicIntegerFieldUpdater<WebURIStat> histogram_10000_100000_Updater = AtomicIntegerFieldUpdater.newUpdater(WebURIStat.class, "histogram_10000_100000"); final static AtomicIntegerFieldUpdater<WebURIStat> histogram_100000_1000000_Updater = AtomicIntegerFieldUpdater.newUpdater(WebURIStat.class, "histogram_100000_1000000"); final static AtomicIntegerFieldUpdater<WebURIStat> histogram_1000000_more_Updater = AtomicIntegerFieldUpdater.newUpdater(WebURIStat.class, "histogram_1000000_more"); public WebURIStat(String uri){ super(); this.uri = uri; } public static WebURIStat current() { return currentLocal.get(); } public String getUri() { return uri; } public void beforeInvoke() { currentLocal.set(this); int running = runningCountUpdater.incrementAndGet(this); for (;;) { int max = concurrentMaxUpdater.get(this); if (running > max) { if (concurrentMaxUpdater.compareAndSet(this, max, running)) { break; } } else { break; } } requestCountUpdater.incrementAndGet(this); WebRequestStat requestStat = WebRequestStat.current(); if (requestStat != null) { this.setLastAccessTimeMillis(requestStat.getStartMillis()); } } public void afterInvoke(Throwable error, long nanos) { runningCountUpdater.decrementAndGet(this); requestTimeNanoUpdater.addAndGet(this, nanos); histogramRecord(nanos); if (error != null) { errorCountUpdater.incrementAndGet(this); } { WebRequestStat localStat = WebRequestStat.current(); if (localStat != null) { { long fetchRowCount = localStat.getJdbcFetchRowCount(); this.addJdbcFetchRowCount(fetchRowCount); for (;;) { long peak = jdbcFetchRowPeakUpdater.get(this); if (fetchRowCount <= peak) { break; } if (jdbcFetchRowPeakUpdater.compareAndSet(this, peak, fetchRowCount)) { break; } } } { long executeCount = localStat.getJdbcExecuteCount(); this.addJdbcExecuteCount(executeCount); for (;;) { long peak = jdbcExecutePeakUpdater.get(this); if (executeCount <= peak) { break; } if (jdbcExecutePeakUpdater.compareAndSet(this, peak, executeCount)) { break; } } } { long updateCount = localStat.getJdbcUpdateCount(); this.addJdbcUpdateCount(updateCount); for (;;) { long peak = jdbcUpdatePeakUpdater.get(this); if (updateCount <= peak) { break; } if (jdbcUpdatePeakUpdater.compareAndSet(this, peak, updateCount)) { break; } } } jdbcExecuteErrorCountUpdater.addAndGet(this, localStat.getJdbcExecuteErrorCount()); jdbcExecuteTimeNanoUpdater.addAndGet(this, localStat.getJdbcExecuteTimeNano()); this.addJdbcPoolConnectionOpenCount(localStat.getJdbcPoolConnectionOpenCount()); this.addJdbcPoolConnectionCloseCount(localStat.getJdbcPoolConnectionCloseCount()); this.addJdbcResultSetOpenCount(localStat.getJdbcResultSetOpenCount()); this.addJdbcResultSetCloseCount(localStat.getJdbcResultSetCloseCount()); } } currentLocal.set(null); } private void histogramRecord(long nanos) { final long millis = nanos / 1000 / 1000; if (millis < 1) { histogram_0_1_Updater.incrementAndGet(this); } else if (millis < 10) { histogram_1_10_Updater.incrementAndGet(this); } else if (millis < 100) { histogram_10_100_Updater.incrementAndGet(this); } else if (millis < 1000) { histogram_100_1000_Updater.incrementAndGet(this); } else if (millis < 10000) { histogram_1000_10000_Updater.incrementAndGet(this); } else if (millis < 100000) { histogram_10000_100000_Updater.incrementAndGet(this); } else if (millis < 1000000) { histogram_100000_1000000_Updater.incrementAndGet(this); } else { histogram_1000000_more_Updater.incrementAndGet(this); } } public int getRunningCount() { return this.runningCount; } public long getConcurrentMax() { return concurrentMax; } public long getRequestCount() { return requestCount; } public long getRequestTimeNano() { return requestTimeNano; } public long getRequestTimeMillis() { return getRequestTimeNano() / (1000 * 1000); } public void addJdbcFetchRowCount(long delta) { jdbcFetchRowCountUpdater.addAndGet(this, delta); } public long getJdbcFetchRowCount() { return jdbcFetchRowCount; } public long getJdbcFetchRowPeak() { return jdbcFetchRowPeak; } public void addJdbcUpdateCount(long updateCount) { jdbcUpdateCountUpdater.addAndGet(this, updateCount); } public long getJdbcUpdateCount() { return jdbcUpdateCount; } public long getJdbcUpdatePeak() { return jdbcUpdatePeak; } public void incrementJdbcExecuteCount() { jdbcExecuteCountUpdater.incrementAndGet(this); } public void addJdbcExecuteCount(long executeCount) { jdbcExecuteCountUpdater.addAndGet(this, executeCount); } public long getJdbcExecuteCount() { return jdbcExecuteCount; } public long getJdbcExecuteErrorCount() { return jdbcExecuteErrorCount; } public long getJdbcExecutePeak() { return jdbcExecutePeak; } public long getJdbcExecuteTimeMillis() { return getJdbcExecuteTimeNano() / (1000 * 1000); } public long getJdbcExecuteTimeNano() { return jdbcExecuteTimeNano; } public void incrementJdbcCommitCount() { jdbcCommitCountUpdater.incrementAndGet(this); } public long getJdbcCommitCount() { return jdbcCommitCount; } public void incrementJdbcRollbackCount() { jdbcRollbackCountUpdater.incrementAndGet(this); } public long getJdbcRollbackCount() { return jdbcRollbackCount; } public void setLastAccessTimeMillis(long lastAccessTimeMillis) { this.lastAccessTimeMillis = lastAccessTimeMillis; } public Date getLastAccessTime() { if (lastAccessTimeMillis < 0L) { return null; } return new Date(lastAccessTimeMillis); } public long getLastAccessTimeMillis() { return lastAccessTimeMillis; } public long getErrorCount() { return errorCount; } public long getJdbcPoolConnectionOpenCount() { return jdbcPoolConnectionOpenCount; } public void addJdbcPoolConnectionOpenCount(long delta) { jdbcPoolConnectionOpenCountUpdater.addAndGet(this, delta); } public void incrementJdbcPoolConnectionOpenCount() { jdbcPoolConnectionOpenCountUpdater.incrementAndGet(this); } public long getJdbcPoolConnectionCloseCount() { return jdbcPoolConnectionCloseCount; } public void addJdbcPoolConnectionCloseCount(long delta) { jdbcPoolConnectionCloseCountUpdater.addAndGet(this, delta); } public void incrementJdbcPoolConnectionCloseCount() { jdbcPoolConnectionCloseCountUpdater.incrementAndGet(this); } public long getJdbcResultSetOpenCount() { return jdbcResultSetOpenCount; } public void addJdbcResultSetOpenCount(long delta) { jdbcResultSetOpenCountUpdater.addAndGet(this, delta); } public long getJdbcResultSetCloseCount() { return jdbcResultSetCloseCount; } public void addJdbcResultSetCloseCount(long delta) { jdbcResultSetCloseCountUpdater.addAndGet(this, delta); } public ProfileStat getProfiletat() { return profiletat; } public long[] getHistogramValues() { return new long[] { // histogram_0_1, // histogram_1_10, // histogram_10_100, // histogram_100_1000, // histogram_1000_10000, // histogram_10000_100000, // histogram_100000_1000000, // histogram_1000000_more // }; } public WebURIStatValue getValue(boolean reset) { WebURIStatValue val = new WebURIStatValue(); val.setUri(uri); val.setRunningCount(runningCount); val.setConcurrentMax(get(this, concurrentMaxUpdater, reset)); val.setRequestCount(get(this, requestCountUpdater, reset)); val.setRequestTimeNano(get(this, requestTimeNanoUpdater, reset)); val.setJdbcFetchRowCount(get(this, jdbcFetchRowCountUpdater, reset)); val.setJdbcFetchRowPeak(get(this, jdbcFetchRowPeakUpdater, reset)); val.setJdbcUpdateCount(get(this, jdbcUpdateCountUpdater, reset)); val.setJdbcUpdatePeak(get(this, jdbcUpdatePeakUpdater, reset)); val.setJdbcExecuteCount(get(this, jdbcExecuteCountUpdater, reset)); val.setJdbcExecuteErrorCount(get(this, jdbcExecuteErrorCountUpdater, reset)); val.setJdbcExecutePeak(get(this, jdbcExecutePeakUpdater, reset)); val.setJdbcExecuteTimeNano(get(this, jdbcExecuteTimeNanoUpdater, reset)); val.setJdbcCommitCount(get(this, jdbcCommitCountUpdater, reset)); val.setJdbcRollbackCount(get(this, jdbcRollbackCountUpdater, reset)); val.setJdbcPoolConnectionOpenCount(get(this, jdbcPoolConnectionOpenCountUpdater, reset)); val.setJdbcPoolConnectionCloseCount(get(this, jdbcPoolConnectionCloseCountUpdater, reset)); val.setJdbcResultSetOpenCount(get(this, jdbcResultSetOpenCountUpdater, reset)); val.setJdbcResultSetCloseCount(get(this, jdbcResultSetCloseCountUpdater, reset)); val.setErrorCount(get(this, errorCountUpdater, reset)); val.setLastAccessTimeMillis(get(this, lastAccessTimeMillisUpdater, reset)); val.setProfileEntryStatValueList(this.getProfiletat().getStatValue(reset)); val.histogram_0_1 = get(this, histogram_0_1_Updater, reset); val.histogram_1_10 = get(this, histogram_1_10_Updater, reset); val.histogram_10_100 = get(this, histogram_10_100_Updater, reset); val.histogram_100_1000 = get(this, histogram_100_1000_Updater, reset); val.histogram_1000_10000 = get(this, histogram_1000_10000_Updater, reset); val.histogram_10000_100000 = get(this, histogram_10000_100000_Updater, reset); val.histogram_100000_1000000 = get(this, histogram_100000_1000000_Updater, reset); val.histogram_1000000_more = get(this, histogram_1000000_more_Updater, reset); return val; } public Map<String, Object> getStatData() { return getValue(false).getStatData(); } }