/* * 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.logging.Log; import com.alibaba.druid.support.logging.LogFactory; 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 WebSessionStat { private final static Log LOG = LogFactory.getLog(WebSessionStat.class); private final String sessionId; private volatile int runningCount; private volatile int concurrentMax; final static AtomicIntegerFieldUpdater<WebSessionStat> runningCountUpdater = AtomicIntegerFieldUpdater.newUpdater(WebSessionStat.class, "runningCount"); final static AtomicIntegerFieldUpdater<WebSessionStat> concurrentMaxUpdater = AtomicIntegerFieldUpdater.newUpdater(WebSessionStat.class, "concurrentMax"); private volatile long requestCount; private volatile long requestErrorCount; private volatile long requestTimeNano; final static AtomicLongFieldUpdater<WebSessionStat> requestCountUpdater = AtomicLongFieldUpdater.newUpdater(WebSessionStat.class, "requestCount"); final static AtomicLongFieldUpdater<WebSessionStat> requestErrorCountUpdater = AtomicLongFieldUpdater.newUpdater(WebSessionStat.class, "requestErrorCount"); final static AtomicLongFieldUpdater<WebSessionStat> requestTimeNanoUpdater = AtomicLongFieldUpdater.newUpdater(WebSessionStat.class, "requestTimeNano"); private volatile long jdbcFetchRowCount; private volatile long jdbcUpdateCount; private volatile long jdbcExecuteCount; private volatile long jdbcExecuteTimeNano; final static AtomicLongFieldUpdater<WebSessionStat> jdbcFetchRowCountUpdater = AtomicLongFieldUpdater.newUpdater(WebSessionStat.class, "jdbcFetchRowCount"); final static AtomicLongFieldUpdater<WebSessionStat> jdbcUpdateCountUpdater = AtomicLongFieldUpdater.newUpdater(WebSessionStat.class, "jdbcUpdateCount"); final static AtomicLongFieldUpdater<WebSessionStat> jdbcExecuteCountUpdater = AtomicLongFieldUpdater.newUpdater(WebSessionStat.class, "jdbcExecuteCount"); final static AtomicLongFieldUpdater<WebSessionStat> jdbcExecuteTimeNanoUpdater = AtomicLongFieldUpdater.newUpdater(WebSessionStat.class, "jdbcExecuteTimeNano"); private volatile long jdbcCommitCount; private volatile long jdbcRollbackCount; final static AtomicLongFieldUpdater<WebSessionStat> jdbcCommitCountUpdater = AtomicLongFieldUpdater.newUpdater(WebSessionStat.class, "jdbcCommitCount"); final static AtomicLongFieldUpdater<WebSessionStat> jdbcRollbackCountUpdater = AtomicLongFieldUpdater.newUpdater(WebSessionStat.class, "jdbcRollbackCount"); private long createTimeMillis = -1L; private volatile long lastAccessTimeMillis = -1L; private String remoteAddresses; private String principal = null; private String userAgent; private volatile int requestIntervalHistogram_0_1; private volatile int requestIntervalHistogram_1_10; private volatile int requestIntervalHistogram_10_100; private volatile int requestIntervalHistogram_100_1000; private volatile int requestIntervalHistogram_1000_10000; private volatile int requestIntervalHistogram_10000_100000; private volatile int requestIntervalHistogram_100000_1000000; private volatile int requestIntervalHistogram_1000000_10000000; private volatile int requestIntervalHistogram_10000000_more; final static AtomicIntegerFieldUpdater<WebSessionStat> requestIntervalHistogram_0_1_Updater = AtomicIntegerFieldUpdater.newUpdater(WebSessionStat.class, "requestIntervalHistogram_0_1"); final static AtomicIntegerFieldUpdater<WebSessionStat> requestIntervalHistogram_1_10_Updater = AtomicIntegerFieldUpdater.newUpdater(WebSessionStat.class, "requestIntervalHistogram_1_10"); final static AtomicIntegerFieldUpdater<WebSessionStat> requestIntervalHistogram_10_100_Updater = AtomicIntegerFieldUpdater.newUpdater(WebSessionStat.class, "requestIntervalHistogram_10_100"); final static AtomicIntegerFieldUpdater<WebSessionStat> requestIntervalHistogram_100_1000_Updater = AtomicIntegerFieldUpdater.newUpdater(WebSessionStat.class, "requestIntervalHistogram_100_1000"); final static AtomicIntegerFieldUpdater<WebSessionStat> requestIntervalHistogram_1000_10000_Updater = AtomicIntegerFieldUpdater.newUpdater(WebSessionStat.class, "requestIntervalHistogram_1000_10000"); final static AtomicIntegerFieldUpdater<WebSessionStat> requestIntervalHistogram_10000_100000_Updater = AtomicIntegerFieldUpdater.newUpdater(WebSessionStat.class, "requestIntervalHistogram_10000_100000"); final static AtomicIntegerFieldUpdater<WebSessionStat> requestIntervalHistogram_100000_1000000_Updater = AtomicIntegerFieldUpdater.newUpdater(WebSessionStat.class, "requestIntervalHistogram_100000_1000000"); final static AtomicIntegerFieldUpdater<WebSessionStat> requestIntervalHistogram_1000000_10000000_Updater = AtomicIntegerFieldUpdater.newUpdater(WebSessionStat.class, "requestIntervalHistogram_1000000_10000000"); final static AtomicIntegerFieldUpdater<WebSessionStat> requestIntervalHistogram_10000000_more_Updater = AtomicIntegerFieldUpdater.newUpdater(WebSessionStat.class, "requestIntervalHistogram_10000000_more"); public WebSessionStat(String sessionId){ super(); this.sessionId = sessionId; } public void reset() { concurrentMaxUpdater.set(this, 0); requestCountUpdater.set(this, 0); requestErrorCountUpdater.set(this, 0); requestTimeNanoUpdater.set(this, 0); jdbcFetchRowCountUpdater.set(this, 0); jdbcUpdateCountUpdater.set(this, 0); jdbcExecuteCountUpdater.set(this, 0); jdbcExecuteTimeNanoUpdater.set(this, 0); jdbcCommitCountUpdater.set(this, 0); jdbcRollbackCountUpdater.set(this, 0); remoteAddresses = null; principal = null; requestIntervalHistogram_0_1_Updater.set(this, 0); requestIntervalHistogram_1_10_Updater.set(this, 0); requestIntervalHistogram_10_100_Updater.set(this, 0); requestIntervalHistogram_100_1000_Updater.set(this, 0); requestIntervalHistogram_1000_10000_Updater.set(this, 0); requestIntervalHistogram_10000_100000_Updater.set(this, 0); requestIntervalHistogram_100000_1000000_Updater.set(this, 0); requestIntervalHistogram_1000000_10000000_Updater.set(this, 0); requestIntervalHistogram_10000000_more_Updater.set(this, 0); } public String getUserAgent() { return userAgent; } public void setUserAgent(String userAgent) { this.userAgent = userAgent; } public String getSessionId() { return sessionId; } public long getCreateTimeMillis() { return createTimeMillis; } public String getPrincipal() { return principal; } public void setPrincipal(String principal) { this.principal = principal; } public void setCreateTimeMillis(long createTimeMillis) { this.createTimeMillis = createTimeMillis; } public long getLastAccessTimeMillis() { return lastAccessTimeMillis; } public String getRemoteAddress() { return remoteAddresses; } public void setLastAccessTimeMillis(long lastAccessTimeMillis) { if (this.lastAccessTimeMillis > 0) { long interval = lastAccessTimeMillis - this.lastAccessTimeMillis; requestIntervalHistogramRecord(interval); } this.lastAccessTimeMillis = lastAccessTimeMillis; } private void requestIntervalHistogramRecord(long nanoSpan) { long millis = nanoSpan / 1000 / 1000; if (millis < 1) { requestIntervalHistogram_0_1_Updater.incrementAndGet(this); } else if (millis < 10) { requestIntervalHistogram_1_10_Updater.incrementAndGet(this); } else if (millis < 100) { requestIntervalHistogram_10_100_Updater.incrementAndGet(this); } else if (millis < 1000) { requestIntervalHistogram_100_1000_Updater.incrementAndGet(this); } else if (millis < 10000) { requestIntervalHistogram_1000_10000_Updater.incrementAndGet(this); } else if (millis < 100000) { requestIntervalHistogram_10000_100000_Updater.incrementAndGet(this); } else if (millis < 1000000) { requestIntervalHistogram_100000_1000000_Updater.incrementAndGet(this); } else if (millis < 10000000) { requestIntervalHistogram_1000000_10000000_Updater.incrementAndGet(this); } else { requestIntervalHistogram_10000000_more_Updater.incrementAndGet(this); } } public void beforeInvoke() { int running = runningCountUpdater.incrementAndGet(this); for (;;) { int max = concurrentMaxUpdater.get(this); if (running > max) { if (concurrentMaxUpdater.compareAndSet(this, max, running)) { break; } } else { break; } } incrementRequestCount(); WebRequestStat requestStat = WebRequestStat.current(); if (requestStat != null) { this.setLastAccessTimeMillis(requestStat.getStartMillis()); } } public void incrementRequestCount() { requestCountUpdater.incrementAndGet(this); } public void afterInvoke(Throwable error, long nanos) { runningCountUpdater.decrementAndGet(this); reacord(nanos); } public void reacord(long nanos) { requestTimeNanoUpdater.addAndGet(this, nanos); WebRequestStat requestStat = WebRequestStat.current(); if (requestStat != null) { this.addJdbcExecuteCount(requestStat.getJdbcExecuteCount()); this.addJdbcFetchRowCount(requestStat.getJdbcFetchRowCount()); this.addJdbcUpdateCount(requestStat.getJdbcUpdateCount()); this.addJdbcCommitCount(requestStat.getJdbcCommitCount()); this.addJdbcRollbackCount(requestStat.getJdbcRollbackCount()); this.addJdbcExecuteTimeNano(requestStat.getJdbcExecuteTimeNano()); } } public void addRemoteAddress(String ip) { if (remoteAddresses == null) { this.remoteAddresses = ip; return; } if (remoteAddresses.contains(ip)) { return; } if (remoteAddresses.length() > 256) { LOG.error("session ip change too many"); return; } remoteAddresses += ';' + ip; } public int getRunningCount() { return this.runningCount; } public long getConcurrentMax() { return concurrentMax; } public long getRequestCount() { return requestCount; } public long getRequestErrorCount() { return requestErrorCount; } public long getRequestTimeNano() { return requestTimeNano; } public void addJdbcFetchRowCount(long delta) { jdbcFetchRowCountUpdater.addAndGet(this, delta); } public long getJdbcFetchRowCount() { return jdbcFetchRowCount; } public void addJdbcUpdateCount(long updateCount) { jdbcUpdateCountUpdater.addAndGet(this, updateCount); } public long getJdbcUpdateCount() { return jdbcUpdateCount; } public void incrementJdbcExecuteCount() { jdbcExecuteCountUpdater.incrementAndGet(this); } public void addJdbcExecuteCount(long executeCount) { jdbcExecuteCountUpdater.addAndGet(this, executeCount); } public long getJdbcExecuteCount() { return jdbcExecuteCount; } public long getJdbcExecuteTimeNano() { return jdbcExecuteTimeNano; } public void addJdbcExecuteTimeNano(long nano) { jdbcExecuteTimeNanoUpdater.addAndGet(this, nano); } public void incrementJdbcCommitCount() { jdbcCommitCountUpdater.incrementAndGet(this); } public long getJdbcCommitCount() { return jdbcCommitCount; } public void addJdbcCommitCount(long commitCount) { jdbcCommitCountUpdater.addAndGet(this, commitCount); } public void incrementJdbcRollbackCount() { jdbcRollbackCountUpdater.incrementAndGet(this); } public long getJdbcRollbackCount() { return jdbcRollbackCount; } public void addJdbcRollbackCount(long rollbackCount) { jdbcRollbackCountUpdater.addAndGet(this, rollbackCount); } public long[] getRequestInterval() { return new long[] { // requestIntervalHistogram_0_1, // requestIntervalHistogram_1_10, // requestIntervalHistogram_10_100, // requestIntervalHistogram_100_1000, // requestIntervalHistogram_1000_10000, // requestIntervalHistogram_10000_100000, // requestIntervalHistogram_100000_1000000, // requestIntervalHistogram_1000000_10000000, // requestIntervalHistogram_10000000_more // }; } public Map<String, Object> getStatData() { return getValue(false).getStatData(); } public WebSessionStatValue getValue(boolean reset) { WebSessionStatValue val = new WebSessionStatValue(); val.sessionId = sessionId; val.runningCount = this.getRunningCount(); val.concurrentMax = get(this, concurrentMaxUpdater, reset); val.requestCount = get(this, requestCountUpdater, reset); val.requestErrorCount = get(this, requestErrorCountUpdater, reset); val.requestTimeNano = get(this, requestTimeNanoUpdater, reset); val.jdbcFetchRowCount = get(this, jdbcFetchRowCountUpdater, reset); val.jdbcUpdateCount = get(this, jdbcUpdateCountUpdater, reset); val.jdbcExecuteCount = get(this, jdbcExecuteCountUpdater, reset); val.jdbcExecuteTimeNano = get(this, jdbcExecuteTimeNanoUpdater, reset); val.jdbcCommitCount = get(this, jdbcCommitCountUpdater, reset); val.jdbcRollbackCount = get(this, jdbcRollbackCountUpdater, reset); val.createTimeMillis = createTimeMillis; val.lastAccessTimeMillis = lastAccessTimeMillis; val.remoteAddress = remoteAddresses; val.principal = principal; val.userAgent = userAgent; val.requestIntervalHistogram_0_1 = get(this, requestIntervalHistogram_0_1_Updater, reset); val.requestIntervalHistogram_1_10 = get(this, requestIntervalHistogram_1_10_Updater, reset); val.requestIntervalHistogram_10_100 = get(this, requestIntervalHistogram_10_100_Updater, reset); val.requestIntervalHistogram_100_1000 = get(this, requestIntervalHistogram_100_1000_Updater, reset); val.requestIntervalHistogram_1000_10000 = get(this, requestIntervalHistogram_1000_10000_Updater, reset); val.requestIntervalHistogram_10000_100000 = get(this, requestIntervalHistogram_10000_100000_Updater, reset); val.requestIntervalHistogram_100000_1000000 = get(this, requestIntervalHistogram_100000_1000000_Updater, reset); val.requestIntervalHistogram_1000000_10000000 = get(this, requestIntervalHistogram_1000000_10000000_Updater, reset); val.requestIntervalHistogram_10000000_more = get(this, requestIntervalHistogram_10000000_more_Updater, reset); return val; } }