package com.taobao.tddl.monitor; import java.util.Arrays; import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import com.taobao.tddl.common.utils.TStringUtil; import com.taobao.tddl.monitor.logger.LoggerInit; import com.taobao.tddl.monitor.stat.BufferedLogWriter; import com.taobao.tddl.monitor.stat.LoggerLogWriter; import com.taobao.tddl.monitor.stat.NagiosLogWriter; import com.taobao.tddl.monitor.stat.StatLogWriter; import com.taobao.tddl.monitor.utils.NagiosUtils; import com.taobao.tddl.common.utils.logger.Logger; import com.taobao.tddl.common.utils.logger.LoggerFactory; /** * StatMonitor 改为在公共的 BufferedLogWriter 基础上实现。 <br/> * * @author changyuan.lh * @author guangxia * @since 1.0, 2010-2-8 下午04:18:39 */ public class StatMonitor extends BufferedLogWriter implements StatMonitorMBean { private static final Logger logger = LoggerFactory.getLogger(StatMonitor.class); private static final StatMonitor instance = new StatMonitor(); private StatMonitor(){ // XXX: 日志内容是行复制和 SQL 解析, Key 量与 SQL 相同数量级 super(5 * 60, 1000, 4000, new NagiosLogWriter()); lastStatMap = map; } public static StatMonitor getInstance() { return instance; } private volatile ConcurrentHashMap<LogKey, LogCounter> lastStatMap; private volatile long lastResetTime = System.currentTimeMillis(); private volatile long duration = 0; public void resetStat() { // XXX: 如果正在刷出, 则不重置 if (!flushing && flushLock.tryLock()) { try { lastStatMap = map; map = new ConcurrentHashMap<LogKey, LogCounter>( // NL maxKeySize, 0.75f, 32); duration = System.currentTimeMillis() - lastResetTime; lastResetTime = System.currentTimeMillis(); } finally { flushLock.unlock(); } } } protected void insureMaxSize() { // XXX: StatMonitor 不会刷出 LRU 日志 // super.insureMaxSize(); } protected void flushAll() { try { lastStatMap = map; duration = System.currentTimeMillis() - lastResetTime; lastResetTime = System.currentTimeMillis(); // 刷出所有统计日志 super.flushAll(); // 拉取自定义日志内容并打印 writeCallBackLog(); } catch (Throwable e) { logger.warn("flushAll", e); } } protected void flushLRU() { // XXX: StatMonitor 不会刷出 LRU 日志 // super.flushLRU(); } public String getStatResult(String key1, String key2, String key3) { LogKey logKey = new LogKey(new Object[] { key1, key2, key3 }); LogCounter counter = lastStatMap.get(logKey); if (counter == null) { logger.warn("getLastStatResult(" + key1 + ", " + key2 + ", " + key3 + ") Invalid"); return null; } long count = counter.getCount(); long values = counter.getValue(); String averageValueStr = "invalid"; String averageCountStr = "invalid"; if (count != 0) { double averageValue = (double) values / count; averageValueStr = String.valueOf(averageValue); } long duration = this.duration; if (duration == 0) { duration = System.currentTimeMillis() - lastResetTime; } if (duration != 0) { double averageCount = (double) (count * 1000) / duration; averageCountStr = String.valueOf(averageCount); } return "count: " + count + ", value: " + values + ", average: " + averageValueStr + ", Count/Duration: " + averageCountStr; } public long getDuration() { return (duration != 0) ? duration : (System.currentTimeMillis() - lastResetTime); } public long getStatDuration() { return lastResetTime; } public final boolean addStat(String keyOne, String keyTwo, String keyThree) { return realTimeStat(keyOne, keyTwo, keyThree, 0); } public final boolean addStat(String keyOne, String keyTwo, String keyThree, long value) { return realTimeStat(keyOne, keyTwo, keyThree, value); } private final boolean realTimeStat(String key1, String key2, String key3, long value) { LogKey logKey = new LogKey(new Object[] { key1, key2, key3 }); if (!map.containsKey(logKey)) { if (map.size() >= maxKeySize) { return false; // XXX: 到容量上限后放弃 } } long[] values = new long[] { 1L, value }; // XXX: 目前不进行 key1/key2 的合并统计, 没有这个需求 // write(new Object[] { key1 }, values); // write(new Object[] { key1, key2 }, values); write(logKey.getKeys(), values); return true; } private List<SnapshotValuesOutputCallBack> snapshotValueCallBack = new LinkedList<SnapshotValuesOutputCallBack>(); public synchronized void addSnapshotValuesCallbask(SnapshotValuesOutputCallBack callbackList) { if (snapshotValueCallBack.contains(callbackList)) { // only one instance is allowed return; } snapshotValueCallBack.add(callbackList); } public synchronized void removeSnapshotValuesCallback(SnapshotValuesOutputCallBack callbackList) { snapshotValueCallBack.remove(callbackList); } /** * 拉取自定义日志内容并打印(单线程,无需锁) */ private final void writeCallBackLog() { for (SnapshotValuesOutputCallBack callBack : snapshotValueCallBack) { try { // XXX: 原来这里会合并同类项, 目前看来无必要 callBack.snapshotValues(TDDL_Log_Writer); } catch (Throwable e) { logger.warn("callBack", e); } } } /** * 将内存数据输出到日志中 */ @SuppressWarnings("unused") private final StatLogWriter Nagios_Log_Writer = new StatLogWriter() { public void write(Object[] keys, Object[] fields, long... values) { if (values.length < 2) { throw new IllegalArgumentException("At least given 2 values"); } fields = Arrays.copyOf((fields == null) ? keys : fields, 3); long count = values[0]; long value = values[1]; String averageValueStr = "invalid"; if (count != 0) { double averageValue = (double) value / count; averageValueStr = String.valueOf(averageValue); } // String key = new // StringBuilder(entry.getKey()).append("||").toString(); // String value = new // StringBuilder().append(values.value1).append("|").append(values.value2).append("|") // .append(values.value2).append((double) // values.value1.get() // / // values.value2.get()).toString(); // NagiosUtils.addNagiosLog(key, // value); NagiosUtils.addNagiosLog(TStringUtil.join(fields, "|"), // NL count + "|" + value + "|" + averageValueStr); } }; /** * 将内存数据输出到日志中 SELECT xxx * #@#my065037_cm4_feel_25#@#EXECUTE_A_SQL_SUCCESS#@#1 * #@#1#@#1#@#1#@#10-12-27 13:58:35:224 SELECT sss * #@#my065026_cm4_feel_03#@#EXECUTE_A_SQL_SUCCESS * #@#1#@#1#@#1#@#1#@#10-12-27 13:58:35:224 */ private final StatLogWriter TDDL_Log_Writer = new LoggerLogWriter(LoggerInit.TDDL_Snapshot_LOG) { // XXX: 输出中首先写数据, 然后写信息, // 最后写时间 protected StringBuffer format(StringBuffer buf, Object[] fields, Date time, long... values) { // LoggerInit.TDDL_Snapshot_LOG.warn(new // StringBuilder().append(values.value1).append( // BufferedStatLogWriter.logFieldSep).append(values.value2).append( // BufferedStatLogWriter.logFieldSep).append(key).append(BufferedStatLogWriter.logFieldSep) // .append(time).append(BufferedStatLogWriter.linesep)); for (long value : values) { buf.append(value).append(fieldSeperator); } for (Object field : fields) { buf.append(field).append(fieldSeperator); } return buf.append(df.format(time)).append(lineSeperator); } }; }