/* * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.openflowjava.statistics; import java.util.Map; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import org.opendaylight.openflowjava.protocol.spi.statistics.StatisticsHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Singleton class to hold and process counters. * * @author madamjak */ public final class StatisticsCounters implements StatisticsHandler { /** * Default delay between two writings into log (milliseconds). */ public static final int DEFAULT_LOG_REPORT_PERIOD = 10000; /** * Minimal delay between two writings into log (milliseconds). */ public static final int MINIMAL_LOG_REPORT_PERIOD = 500; private static StatisticsCounters instanceHolder; private static final Logger LOG = LoggerFactory.getLogger(StatisticsCounters.class); private Timer logReporter; private int logReportPeriod; private boolean runLogReport; private final Map countersMap; private boolean runCounting; // array to hold enabled counter types private final CounterEventTypes[] enabledCounters = { CounterEventTypes.DS_ENCODE_FAIL, CounterEventTypes.DS_ENCODE_SUCCESS, CounterEventTypes.DS_ENTERED_OFJAVA, CounterEventTypes.DS_FLOW_MODS_ENTERED, CounterEventTypes.DS_FLOW_MODS_SENT, CounterEventTypes.US_DROPPED_PACKET_IN, CounterEventTypes.US_DECODE_FAIL, CounterEventTypes.US_DECODE_SUCCESS, CounterEventTypes.US_MESSAGE_PASS, CounterEventTypes.US_RECEIVED_IN_OFJAVA }; /** * Get instance of statistics counters, first created object does not start counting and log reporting. * * @return an instance */ public static synchronized StatisticsCounters getInstance() { if (instanceHolder == null) { instanceHolder = new StatisticsCounters(); } return instanceHolder; } private StatisticsCounters() { countersMap = new ConcurrentHashMap<>(); for (CounterEventTypes cet : enabledCounters) { countersMap.put(cet, new Counter()); } runCounting = false; this.logReportPeriod = 0; this.runLogReport = false; LOG.debug("StaticsCounters has been created"); } /** * Start counting (counters are set to 0 before counting starts). * * @param reportToLogs - true = statistic counters will periodically log * @param logReportDelay - delay between two logs (in milliseconds) */ public void startCounting(boolean reportToLogs, int logReportDelay) { if (runCounting) { return; } resetCounters(); LOG.debug("Counting started..."); if (reportToLogs) { startLogReport(logReportDelay); } runCounting = true; } /** * Stop counting, values in counters are untouched, log reporter is stopped. */ public void stopCounting() { runCounting = false; LOG.debug("Stop counting..."); stopLogReport(); } /** * Give an information if counting is running. * * @return true, if counting is running, otherwise false */ public boolean isRunCounting() { return runCounting; } /** * Prints statistics with given delay between logs. * * @param logReportDelay - delay between two logs (in milliseconds) * @exception IllegalArgumentException if logReportDelay is less than 0 */ public void startLogReport(int logReportDelay) { if (runLogReport) { return; } if (logReportDelay <= 0) { throw new IllegalArgumentException("logReportDelay has to be greater than 0"); } if (logReportDelay < MINIMAL_LOG_REPORT_PERIOD) { this.logReportPeriod = MINIMAL_LOG_REPORT_PERIOD; } else { this.logReportPeriod = logReportDelay; } logReporter = new Timer("SC_Timer"); logReporter.schedule(new LogReporterTask(this), this.logReportPeriod, this.logReportPeriod); runLogReport = true; LOG.debug("Statistics log reporter has been scheduled with period {} ms", this.logReportPeriod); } /** * Stops logging, counting continues. */ public void stopLogReport() { if (runLogReport) { if (logReporter != null) { logReporter.cancel(); LOG.debug("Statistics log reporter has been canceled"); } runLogReport = false; } } /** * Give an information if log reporter is running (statistics are write into logs). * @return true if log reporter writes statistics into log, otherwise false */ public boolean isRunLogReport() { return runLogReport; } /** * Returns the current delay between two writings into logs. */ public int getLogReportPeriod() { return logReportPeriod; } /** * Returns the enabled counters. */ protected CounterEventTypes[] getEnabledCounters() { return enabledCounters; } /** * Returns the countersMap. */ protected Map getCountersMap() { return countersMap; } /** * Determines if the given counter is enabled. * * @param counterEventKey the counter key * @return true if counter has been Enabled, otherwise false */ public boolean isCounterEnabled(CounterEventTypes counterEventKey) { if (counterEventKey == null) { return false; } return countersMap.containsKey(counterEventKey); } /** * Get counter by CounterEventType. * * @param counterEventKey key to identify counter (can not be null) * @return Counter object or null if counter has not been enabled * @throws IllegalArgumentException if counterEventKey is null */ public Counter getCounter(CounterEventTypes counterEventKey) { if (counterEventKey == null) { throw new IllegalArgumentException("counterEventKey can not be null"); } return countersMap.get(counterEventKey); } /** * Increment value of given counter. * * @param counterEventKey key to identify counter */ public void incrementCounter(CounterEventTypes counterEventKey) { if (runCounting) { if (isCounterEnabled(counterEventKey)) { countersMap.get(counterEventKey).incrementCounter(); } } } @Override public void resetCounters() { for (CounterEventTypes cet : enabledCounters) { countersMap.get(cet).reset(); } LOG.debug("StaticsCounters has been reset"); } @Override public String printStatistics() { StringBuilder strBuilder = new StringBuilder(); for (CounterEventTypes cet : getEnabledCounters()) { strBuilder.append(cet.name() + ": " + getCountersMap().get(cet).getStat() + "\n"); } return strBuilder.toString(); } /** * internal class to process logReporter. * * @author madamjak */ private static class LogReporterTask extends TimerTask { private final StatisticsCounters sc; LogReporterTask(StatisticsCounters sc) { this.sc = sc; } @Override public void run() { for (CounterEventTypes cet : sc.getEnabledCounters()) { LOG.debug("Event {}: {}", cet.name(), sc.getCountersMap().get(cet).getStat()); } } } }