package com.linkedin.camus.sweeper; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.log4j.Logger; public class CamusSweeperMetrics { private static final Logger LOG = Logger.getLogger(CamusSweeperMetrics.class); private final Map<String, Long> dataSizeByTopic; private final Map<String, Long> runnerStartTimeByTopic; private final Map<String, Long> mrSubmitTimeByTopic; private final Map<String, Long> mrStartRunningTimeByTopic; private final Map<String, Long> mrFinishTimeByTopic; private long totalDataSize; private long timeStart; CamusSweeperMetrics() { this.dataSizeByTopic = new ConcurrentHashMap<String, Long>(); this.mrSubmitTimeByTopic = new ConcurrentHashMap<String, Long>(); this.mrFinishTimeByTopic = new ConcurrentHashMap<String, Long>(); this.runnerStartTimeByTopic = new ConcurrentHashMap<String, Long>(); this.mrStartRunningTimeByTopic = new ConcurrentHashMap<String, Long>(); timeStart = 0; totalDataSize = 0; } public long getTotalDataSize() { return totalDataSize; } public void addToTotalDataSize(long size) { this.totalDataSize += size; } public long getTimeStart() { return timeStart; } public void setTimeStart(long timeStart) { this.timeStart = timeStart; } public void recordDataSizeByTopic(String topic, long dataSize) { this.dataSizeByTopic.put(topic, dataSize); } public void recordRunnerStartTimeByTopic(String topic, long time) { this.runnerStartTimeByTopic.put(topic, time); } public void recordMrSubmitTimeByTopic(String topic, long time) { this.mrSubmitTimeByTopic.put(topic, time); } public void recordMrStartRunningTimeByTopic(String topic, long time) { this.mrStartRunningTimeByTopic.put(topic, time); } public void recordMrFinishTimeByTopic(String topic, long time) { this.mrFinishTimeByTopic.put(topic, time); } public void reportTotalRunningTime() { LOG.info("total running time: " + (System.currentTimeMillis() - this.timeStart) / 1000L + " sec"); } public void reportTotalDataSize() { double totalDataSizeGB = (double) this.totalDataSize / 1024.0 / 1024.0 / 1024.0; LOG.info("total data size: " + String.format("%.2f", totalDataSizeGB) + "GB"); } public void reportDataSizeByTopic() { this.reportDataSizeByTopic(Integer.MAX_VALUE); } public void reportDataSizeByTopic(int maxToReport) { LOG.info("Data Size By Topic:"); List<Map.Entry<String, Long>> dataSizeByTopicSorted = sortByValueDesc(this.dataSizeByTopic); for (int i = 0; i < dataSizeByTopicSorted.size() && i < maxToReport; i++) { Map.Entry<String, Long> entry = dataSizeByTopicSorted.get(i); double dataSizeMB = (double) entry.getValue() / 1024.0 / 1024.0; LOG.info(" " + entry.getKey() + ": " + String.format("%.2f", dataSizeMB) + "MB"); } } public void reportDurationFromStartToRunnerStart() { this.reportDurationFromStartToRunnerStart(Integer.MAX_VALUE); } public void reportDurationFromStartToRunnerStart(int maxToReport) { LOG.info("Time from start processing to runner starts By Topic:"); Map<String, Long> durations = getDurations(this.timeStart, this.runnerStartTimeByTopic); reportDurations(durations, maxToReport); } public void reportDurationFromRunnerStartToMRSubmitted() { this.reportDurationFromRunnerStartToMRSubmitted(Integer.MAX_VALUE); } public void reportDurationFromRunnerStartToMRSubmitted(int maxToReport) { LOG.info("Time from runner start to MR submitted By Topic:"); Map<String, Long> durations = getDurations(this.runnerStartTimeByTopic, this.mrSubmitTimeByTopic); reportDurations(durations, maxToReport); } public void reportDurationFromMRSubmittedToMRStarted() { this.reportDurationFromMRSubmittedToMRStarted(Integer.MAX_VALUE); } public void reportDurationFromMRSubmittedToMRStarted(int maxToReport) { LOG.info("Time from MR submitted to MR started running By Topic:"); Map<String, Long> durations = getDurations(this.mrSubmitTimeByTopic, this.mrStartRunningTimeByTopic); reportDurations(durations, maxToReport); } public void reportDurationFromMRStartedToMRFinished() { this.reportDurationFromMRStartedToMRFinished(Integer.MAX_VALUE); } public void reportDurationFromMRStartedToMRFinished(int maxToReport) { LOG.info("Time from MR started running to MR finished By Topic:"); Map<String, Long> durations = getDurations(this.mrStartRunningTimeByTopic, this.mrFinishTimeByTopic); reportDurations(durations, maxToReport); } private void reportDurations(Map<String, Long> durations, int maxToReport) { List<Map.Entry<String, Long>> durationsSorted = sortByValueDesc(durations); for (int i = 0; i < durations.size() && i < maxToReport; i++) { Map.Entry<String, Long> entry = durationsSorted.get(i); LOG.info(" " + entry.getKey() + ": " + entry.getValue() / 1000L + " sec"); } } private Map<String, Long> getDurations(Map<String, Long> startTimes, Map<String, Long> endTimes) { Map<String, Long> durations = new HashMap<String, Long>(); for (String topic : startTimes.keySet()) { if (endTimes.containsKey(topic)) { durations.put(topic, endTimes.get(topic) - startTimes.get(topic)); } } return durations; } private Map<String, Long> getDurations(long startTime, Map<String, Long> endTimes) { Map<String, Long> durations = new HashMap<String, Long>(); for (String topic : endTimes.keySet()) { durations.put(topic, endTimes.get(topic) - startTime); } return durations; } private static <K, V extends Comparable<? super V>> List<Map.Entry<K, V>> sortByValueDesc(Map<K, V> map) { List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>(map.entrySet()); Collections.sort(list, new Comparator<Map.Entry<K, V>>() { public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) { return (o2.getValue()).compareTo(o1.getValue()); } }); return list; } }