package org.googlecode.perftrace; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.googlecode.perftrace.perf4j.LoggingStopWatch; import org.googlecode.perftrace.schema.BootstrapPerftrace; import org.googlecode.perftrace.util.StringUtils; /** * @author zhongfeng * */ public abstract class PerfTrace { private final static Logger logger = Logger.getLogger(PerfTrace.class .getName()); public final static String PERF_TRACE_LOG = "org.googlecode.perftrace"; private final static String PERF_LOG_SEG = "*"; private final static String OUTPUT_LOG_SEG = "|"; private static final ThreadLocal<ArrayList<LoggingStopWatch>> WATCH_CHAIN = new ThreadLocal<ArrayList<LoggingStopWatch>>() { public ArrayList<LoggingStopWatch> initialValue() { return new ArrayList<LoggingStopWatch>(); } }; // private static final private static final ThreadLocal<ArrayList<String>> ADDITION_MSG = new ThreadLocal<ArrayList<String>>() { public ArrayList<String> initialValue() { return new ArrayList<String>(); } }; public void addPerfWatch(LoggingStopWatch watch) { logger.log(Level.FINE, "Enter Add:{},watch :{}", new Object[] { watch.toString(), watch.isRootMethod() }); if (isInsertPerfQueue(watch)) { getOtaPerfWatchList().add(watch); } } /** * @param watch * @return * */ private static boolean isInsertPerfQueue(LoggingStopWatch watch) { return (!getOtaPerfWatchList().isEmpty()) || watch.isRootMethod(); } public void addAdditionMsg(String msg) { getAdditionMsg().add(msg); } public void watchStop(LoggingStopWatch watch) { logger.log(Level.FINE, "Enter Stop:{}", watch.toString()); if (isStop(watch)) { doPerfLog(); WATCH_CHAIN.remove(); ADDITION_MSG.remove(); return; } // 注意,这里需要有防止内存暴涨的保护措施,比如WATCH_CHAIN > 2000时,需要强制刷掉 if (WATCH_CHAIN.get().size() > BootstrapPerftrace.getGlobal() .getMaxWatchChainDepth()) { logger.log(Level.WARNING, "WatchChain size is:{0},gt MaxWatchChainDepth:{1}", new Object[] { WATCH_CHAIN.get().size(), BootstrapPerftrace.getGlobal() .getMaxWatchChainDepth() }); doPerfLog(); WATCH_CHAIN.remove(); } if (ADDITION_MSG.get().size() > BootstrapPerftrace.getGlobal() .getMaxAdditionMsgCount()) { logger.log(Level.WARNING, "ADDITION_MSG size is:{0},gt MaxAdditionMsgCount:{1}", new Object[] { ADDITION_MSG.get().size(), BootstrapPerftrace.getGlobal() .getMaxAdditionMsgCount() }); doPerfLog(); ADDITION_MSG.remove(); } } /** * @param watch * @return */ private static boolean isStop(LoggingStopWatch watch) { return (!getOtaPerfWatchList().isEmpty()) && watch.equals(getOtaPerfWatchList().get(0)); } private void doPerfLog() { String logString = buildOutputLogString(); log(logString); // LogWatchComposite lwc = LogWatchParser.analysis(logString); // LOG.info(lwc.toXMLLogString()); } /** * abstract log method * * @param logSring */ public abstract void log(String logSring); /** * */ private static String buildOutputLogString() { List<String> outputLogSegs = new ArrayList<String>(); outputLogSegs.addAll(getAdditionMsg()); outputLogSegs.add(buildPerfLogSeg()); return StringUtils.join(outputLogSegs, OUTPUT_LOG_SEG); } /** * @return */ private static String buildPerfLogSeg() { List<String> perfLogs = new ArrayList<String>(); for (LoggingStopWatch watch : getOtaPerfWatchList()) { if (watch.isOverTimeThreshold()) perfLogs.add(watch.getLogRetString()); } String perfLogSeg = StringUtils.join(perfLogs, PERF_LOG_SEG); return perfLogSeg; } private static ArrayList<LoggingStopWatch> getOtaPerfWatchList() { return WATCH_CHAIN.get(); } /** * @return */ private static ArrayList<String> getAdditionMsg() { return ADDITION_MSG.get(); } }