/*
* (C) 2007-2012 Alibaba Group Holding Limited.
*
* 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.
* Authors:
* wuhua <wq163@163.com> , boyan <killme2008@gmail.com>
*/
package com.taobao.metamorphosis.utils;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
/**
*
*
* StatLog�İ�װ��
*
* @author boyan
*
* @since 1.0, 2009-6-2 ����03:15:37
*/
public final class MetaStatLog {
public static boolean startRealTimeStat = false;
private MetaStatLog() {
}
// û���κ����ã�����Ϊ��ע�������
static MetaStatLog ME = new MetaStatLog();
static ConcurrentHashMap<String/* key1 */, ConcurrentHashMap<String, ConcurrentHashMap<String, StatCounter>>> realTimeStatMap =
new ConcurrentHashMap<String, ConcurrentHashMap<String, ConcurrentHashMap<String, StatCounter>>>();
public static volatile long lastResetTime = System.currentTimeMillis();
static class StatCounter {
private final AtomicLong count = new AtomicLong(0L);
private final AtomicLong value = new AtomicLong(0L);
public void incrementCount() {
this.count.incrementAndGet();
}
public void addValue(final long value) {
this.value.addAndGet(value);
}
public synchronized void reset() {
this.count.set(0L);
this.value.set(0L);
}
}
public static void clearRealTimeStat() {
realTimeStatMap =
new ConcurrentHashMap<String, ConcurrentHashMap<String, ConcurrentHashMap<String, StatCounter>>>();
}
public static class RealTimeStatRestTask implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(30 * 60 * 1000);
}
catch (final InterruptedException e) {
Thread.currentThread().interrupt();
}
resetRealTimeStat();
}
}
}
public synchronized static final void resetRealTimeStat() {
for (final Map.Entry<String, ConcurrentHashMap<String, ConcurrentHashMap<String, StatCounter>>> entry1 : realTimeStatMap
.entrySet()) {
for (final Map.Entry<String, ConcurrentHashMap<String, StatCounter>> entry2 : entry1.getValue().entrySet()) {
for (final Map.Entry<String, StatCounter> entry3 : entry2.getValue().entrySet()) {
entry3.getValue().reset();
}
}
}
lastResetTime = System.currentTimeMillis();
}
public static List<String> getRealTimeStatItemNames() {
final List<String> result = new ArrayList<String>();
for (final Map.Entry<String, ConcurrentHashMap<String, ConcurrentHashMap<String, StatCounter>>> entry1 : realTimeStatMap
.entrySet()) {
for (final Map.Entry<String, ConcurrentHashMap<String, StatCounter>> entry2 : entry1.getValue().entrySet()) {
for (final Map.Entry<String, StatCounter> entry3 : entry2.getValue().entrySet()) {
final StringBuilder sb = new StringBuilder("[");
sb.append(entry1.getKey()).append(",");
sb.append(entry2.getKey()).append(",");
sb.append(entry3.getKey()).append("]");
result.add(sb.toString());
}
}
}
return result;
}
public static final String getRealTimeStatResult(final String key1, final String key2, final String key3) {
final ConcurrentHashMap<String, ConcurrentHashMap<String, StatCounter>> map1 = realTimeStatMap.get(key1);
if (map1 == null) {
return "Invalid keyOne:" + key1;
}
final ConcurrentHashMap<String, StatCounter> map2 = map1.get(key2);
if (map2 == null) {
return "Invalid keyTwo:" + key2;
}
final StatCounter counter = map2.get(key3);
if (counter == null) {
return "Invalid keyThree:" + key3;
}
return formatOutput(counter);
}
private static String formatOutput(final StatCounter counter) {
final double count = counter.count.get();
final double values = counter.value.get();
final long duration = (System.currentTimeMillis() - lastResetTime) / 1000;
String averageValueStr = "invalid";
String averageCountStr = "invalid";
final DecimalFormat numberFormat = new DecimalFormat("#.##");
if (count != 0) {
final double averageValue = values / count;
averageValueStr = numberFormat.format(averageValue);
}
if (duration != 0) {
final double averageCount = count / duration;
averageCountStr = numberFormat.format(averageCount);
}
return String.format(OUTPUT_FORMAT, numberFormat.format(count), numberFormat.format(values), averageValueStr,
averageCountStr, duration);
}
public static final String getGroupedRealTimeStatResult(final String key1) {
final ConcurrentHashMap<String, ConcurrentHashMap<String, StatCounter>> map1 = realTimeStatMap.get(key1);
if (null == map1) {
return null;
}
final StatCounter statCounter = new StatCounter();
for (final Map.Entry<String/* key2 */, ConcurrentHashMap<String/* key3 */, StatCounter>> entry1 : map1
.entrySet()) {
final ConcurrentHashMap<String/* key3 */, StatCounter> map2 = entry1.getValue();
if (null == map2) {
continue;
}
for (final Map.Entry<String, StatCounter> entry2 : map2.entrySet()) {
statCounter.count.addAndGet(entry2.getValue().count.longValue());
statCounter.value.addAndGet(entry2.getValue().value.longValue());
}
}
return formatOutput(statCounter);
}
public static final String getGroupedRealTimeStatResult(final String key1, final String key2) {
final ConcurrentHashMap<String, ConcurrentHashMap<String, StatCounter>> map1 = realTimeStatMap.get(key1);
if (null == map1) {
return null;
}
final ConcurrentHashMap<String, StatCounter> map2 = map1.get(key2);
if (map2 == null) {
return "Invalid keyTwo:" + key2;
}
final StatCounter statCounter = new StatCounter();
for (final Map.Entry<String, StatCounter> entry2 : map2.entrySet()) {
statCounter.count.addAndGet(entry2.getValue().count.longValue());
statCounter.value.addAndGet(entry2.getValue().value.longValue());
}
return formatOutput(statCounter);
}
public static long getDuration() {
return (System.currentTimeMillis() - lastResetTime) / 1000;
}
public static String OUTPUT_FORMAT = "Count=%s,Value=%s,Value/Count=%s,Count/Duration=%s,Duration=%d";
public static final void addStat(final String appName, final String keyOne, final String keyTwo,
final String keyThree) {
realTimeStat(keyOne, keyTwo, keyThree, 0);
}
@SuppressWarnings("unused")
private static class RealTimeStaticKey {
private String key1;
private String key2;
private String key3;
public RealTimeStaticKey(final String key1, final String key2, final String key3) {
this.key1 = key1;
this.key2 = key2;
this.key3 = key3;
}
public String getKey1() {
return this.key1;
}
public void setKey1(final String key1) {
this.key1 = key1;
}
public String getKey2() {
return this.key2;
}
public void setKey2(final String key2) {
this.key2 = key2;
}
public String getKey3() {
return this.key3;
}
public void setKey3(final String key3) {
this.key3 = key3;
}
}
public static final void realTimeStat(final String key1, final String key2, final String key3, final long value) {
if (startRealTimeStat) {
processMap2(key1, key2, key3, value);
}
}
private static void processMap2(final String key1, final String key2, final String key3, final long value) {
ConcurrentHashMap<String, ConcurrentHashMap<String, StatCounter>> statMap1 = realTimeStatMap.get(key1);
if (statMap1 == null) {
statMap1 = new ConcurrentHashMap<String, ConcurrentHashMap<String, StatCounter>>();
final ConcurrentHashMap<String, ConcurrentHashMap<String, StatCounter>> oldStatMap1 =
realTimeStatMap.putIfAbsent(key1, statMap1);
if (oldStatMap1 != null) {
statMap1 = oldStatMap1;
}
}
ConcurrentHashMap<String, StatCounter> statMap2 = statMap1.get(key2);
if (statMap2 == null) {
statMap2 = new ConcurrentHashMap<String, StatCounter>();
final ConcurrentHashMap<String, StatCounter> oldStatMap2 = statMap1.putIfAbsent(key2, statMap2);
if (oldStatMap2 != null) {
statMap2 = oldStatMap2;
}
}
StatCounter statCounter = statMap2.get(key3);
if (statCounter == null) {
statCounter = new StatCounter();
final StatCounter oldCounter = statMap2.putIfAbsent(key3, statCounter);
if (oldCounter != null) {
statCounter = oldCounter;
}
}
statCounter.incrementCount();
statCounter.addValue(value);
}
public static final void addStat(final String appName, final String keyOne, final String keyTwo) {
realTimeStat(keyOne, keyTwo, "*", 0);
}
public static final void addStat(final String appName, final String keyOne) {
realTimeStat(keyOne, "*", "*", 0);
}
public static final void addStatValue2(final String appName, final String keyOne, final long value) {
realTimeStat(keyOne, "*", "*", value);
}
public static final void addStatValue2(final String appName, final String keyOne, final String keyTwo,
final long value) {
realTimeStat(keyOne, keyTwo, "*", value);
}
public static final void addStatValue2(final String appName, final String keyOne, final String keyTwo,
final String keyThree, final long value) {
realTimeStat(keyOne, keyTwo, keyThree, value);
}
}