import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
/**
* SimpleMonitor 简单监控器
*/
public class SimpleMonitor {
private static Map<String, SimpleMonitor> smMap = new ConcurrentHashMap<String, SimpleMonitor>();
/**
*
* Aggregation description: 聚合操作标识
*
*/
public enum Aggregation {
Avg("avg"), Sum("sum"), Diff("diff");
private String value;
private Aggregation(String v) {
value = v;
}
@Override
public String toString() {
return value;
}
}
/**
*
* SumBySeconds description:
*
*/
private static class SumBySeconds {
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
private long timespan;
private long timestamp;
private int lastRecordNumber = 1;
private Map<String, Long> records = new LinkedHashMap<String, Long>();
public void setLastRecordNumber(int lastRecordNumber) {
this.lastRecordNumber = lastRecordNumber;
}
public long getTimespan() {
return timespan;
}
public void setTimespan(long timespan) {
this.timespan = timespan;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public void putHistoryRecord(long timestamp, long value) {
if (records.size() >= lastRecordNumber) {
String key = records.keySet().iterator().next();
records.remove(key);
}
records.put(sdf.format(new Date(timestamp)), value);
}
public Map<String, Long> getHistoryRecords() {
return this.records;
}
}
/**
* get simple monitor
*
* @param name
* @return
*/
public static SimpleMonitor getMonitor(String name) {
if (null == name || "".equals(name)) {
return null;
}
if (smMap.containsKey(name)) {
return smMap.get(name);
}
SimpleMonitor sm = new SimpleMonitor();
smMap.put(name, sm);
return sm;
}
private Map<String, Object> elems = new ConcurrentHashMap<String, Object>();
private Map<String, SumBySeconds> elemSumBySeconds = new ConcurrentHashMap<String, SumBySeconds>();
private Map<String, Map<String, String>> elemsAttrs = new ConcurrentHashMap<String, Map<String, String>>();
/**
*
* @param mode
* 0 默认JSON格式,1 文本模式换行
* @return
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public String toJSONString(int mode) {
String lineChar = (mode == 0) ? "" : "\n";
int delChatLen = (mode == 0) ? 1 : 2;
StringBuilder sb = new StringBuilder("{");
Iterator<Entry<String, Object>> entry = elems.entrySet().iterator();
int count = 0;
while (entry.hasNext()) {
Entry<String, Object> e = entry.next();
sb.append("\"" + e.getKey() + "\":");
Object val = e.getValue();
Class<?> valClass = val.getClass();
if (AtomicLong.class.isAssignableFrom(valClass) || Long.class.isAssignableFrom(valClass)
|| Integer.class.isAssignableFrom(valClass) || Double.class.isAssignableFrom(valClass)) {
sb.append(val);
}
else if (Map.class.isAssignableFrom(valClass)) {
Map map = (Map) val;
Iterator<Entry> newentry = map.entrySet().iterator();
StringBuilder msb = new StringBuilder("{");
int countMSB = 0;
while (newentry.hasNext()) {
Entry entryElem = newentry.next();
msb.append("\"" + entryElem.getKey() + "\":" + entryElem.getValue() + ",");
countMSB++;
}
if (countMSB > 0) {
msb = msb.deleteCharAt(msb.length() - 1);
}
msb.append("}");
sb.append(msb.toString());
}
else {
sb.append("\"" + val + "\"");
}
sb.append("," + lineChar);
count++;
}
if (count > 0) {
sb = sb.deleteCharAt(sb.length() - delChatLen);
}
return sb.append("}").toString();
}
/**
* 设置值
*
* @param key
* @param value
*/
public void setValue(String key, Object value) {
if (key == null || value == null)
return;
elems.put(key, value);
}
/**
* 计数器
*
* @param key
* @return
*/
public long increValue(String key) {
return sumValue(key, 1);
}
/**
* 计数器 by value
*
* @param key
* @param addValue
* @return
*/
public long sumValue(String key, long addValue) {
Object obj = elems.get(key);
// new init
if (obj == null) {
synchronized (elems) {
obj = elems.get(key);
if (obj == null) {
AtomicLong incre = new AtomicLong(addValue);
elems.put(key, incre);
return addValue;
}
}
}
AtomicLong incre = AtomicLong.class.cast(obj);
long tmp = 0;
SumBySeconds sbs = this.elemSumBySeconds.get(key);
// sum by period
if (sbs != null) {
if (System.currentTimeMillis() - sbs.getTimestamp() >= sbs.getTimespan()) {
synchronized (incre) {
if (System.currentTimeMillis() - sbs.getTimestamp() >= sbs.getTimespan()) {
// update timestamp
sbs.setTimestamp(System.currentTimeMillis());
// recore last value
sbs.putHistoryRecord(sbs.getTimestamp(), incre.get());
// set records value
setValue(key + ".rc", sbs.getHistoryRecords());
// return current value to 0
incre.set(addValue);
tmp = addValue;
}
else {
tmp = incre.addAndGet(addValue);
}
}
}
else {
tmp = incre.addAndGet(addValue);
}
}
// normal incre
else {
tmp = incre.addAndGet(addValue);
}
// when exceed MAXVALUE
if (tmp < 0) {
elems.remove(key);
synchronized (elems) {
obj = elems.get(key);
if (obj == null) {
AtomicLong newincre = new AtomicLong(addValue);
elems.put(key, newincre);
tmp = addValue;
}
else {
AtomicLong newincre = AtomicLong.class.cast(obj);
tmp = newincre.addAndGet(addValue);
}
}
}
return tmp;
}
/**
* 设置某个计数器的统计周期
*
* @param key
* @param tu
* 统计多少秒内的值,过后回0
*/
public void setValueSumBySeconds(String key, Long tu) {
setValueSumBySeconds(key, tu, 1);
}
/**
* 设置某个计数器的统计周期
*
* @param key
* @param tu
* 统计多少秒内的值,过后回0
* @param lastRecordNumber
* 保存过去记录的个数
*
*/
public void setValueSumBySeconds(String key, Long tu, int lastRecordNumber) {
if (null == key || tu <= 0 || lastRecordNumber <= 0) {
return;
}
SumBySeconds sbs = new SumBySeconds();
sbs.setTimespan(tu * 1000);
sbs.setTimestamp(System.currentTimeMillis());
sbs.setLastRecordNumber(lastRecordNumber);
elemSumBySeconds.put(key, sbs);
}
/**
* 清除某个计数器的统计周期
*
* @param key
*/
public void unsetValueSumBySeconds(String key) {
if (null == key) {
return;
}
elemSumBySeconds.remove(key);
}
/**
* remove metric
*
* @param key
*/
public void removeMetric(String key) {
if (elems.containsKey(key)) {
String skey = getSKey(key);
System.getProperties().remove(skey);
elems.remove(key);
elemSumBySeconds.remove(key);
elemsAttrs.remove(key);
}
}
/**
* 将某个指标设定到一个指标group里面,可以实现合并显示
*
* @param metricKey
* @param groupName
*/
public void setMetricGroup(String metricKey, String groupName) {
if (!this.elemsAttrs.containsKey(metricKey)) {
Map<String, String> m = new HashMap<String, String>();
this.elemsAttrs.put(metricKey, m);
}
Map<String, String> m = this.elemsAttrs.get(metricKey);
m.put("gp", groupName);
}
/**
*
* 设置某个指标的聚合方式,在显示上体系
*
* @param metricKey
* @param agg
*/
public void setMetricAggregation(String metricKey, Aggregation agg) {
if (!this.elemsAttrs.containsKey(metricKey)) {
Map<String, String> m = new HashMap<String, String>();
this.elemsAttrs.put(metricKey, m);
}
Map<String, String> m = this.elemsAttrs.get(metricKey);
m.put("agg", agg.toString());
}
/**
* 将metric值flush到SystemProperties
*
* @param includeMetrics
* 为null则表示flush 所有metrics;如果给出metrics名字,则只flush这些metrics 注意:该方法只将最近的metric值flush到,而历史值是默认忽略的
*/
public void flushToSystemProperties(String... includeMetrics) {
Map<String, String> pro = new HashMap<String, String>();
if (includeMetrics == null || includeMetrics.length == 0) {
for (String key : this.elems.keySet()) {
// ignore those history data
if (key.endsWith(".rc") == true) {
continue;
}
String skey = getSKey(key);
pro.put(skey, String.valueOf(elems.get(key)));
}
}
else {
for (String key : includeMetrics) {
if (elems.containsKey(key)) {
String skey = getSKey(key);
pro.put(skey, String.valueOf(elems.get(key)));
}
}
}
System.getProperties().putAll(pro);
}
/**
* get skey
*
* @param key
* @return
*/
private String getSKey(String key) {
String skey = "mo@" + key;
if (this.elemsAttrs.containsKey(key)) {
Map<String, String> attrs = this.elemsAttrs.get(key);
if (attrs.size() > 0) {
skey += "@" + convertMapToString(attrs);
}
}
return skey;
}
private String convertMapToString(Map<String, String> attrs) {
StringBuilder sb = new StringBuilder();
sb.append("{");
for (String key : attrs.keySet()) {
sb.append("\"" + key + "\":\"" + attrs.get(key) + "\",");
}
if (attrs.size() > 0) {
sb = sb.deleteCharAt(sb.length() - 1);
}
sb.append("}");
return sb.toString();
}
}