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 {
+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 LOGGER = LoggerFactory.getLogger(StatisticsCounters.class);
- private final Counter cntDSEncodeFail;
- private final Counter cntDSEncodeSuccess;
- private final Counter cntDSEnteredOFJava;
- private final Counter cntUSDecodeFail;
- private final Counter cntUSDecodeSuccess;
- private final Counter cntUSMessagePass;
- private final Counter cntUSReceivedOFJava;
- //private Map<CounterEventTypes,Counter> countersMap;
-
- public static StatisticsCounters getInstance(){
- if (instanceHolder == null){
+ private Timer logReporter;
+ private int logReportPeriod;
+ private boolean runLogReport;
+ private Map<CounterEventTypes, Counter> countersMap;
+ private boolean runCounting;
+ // array to hold enabled counter types
+ private 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_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 synchronized static StatisticsCounters getInstance() {
+ if (instanceHolder == null) {
instanceHolder = new StatisticsCounters();
}
return instanceHolder;
}
private StatisticsCounters() {
- cntDSEncodeFail = new Counter();
- cntDSEncodeSuccess = new Counter();
- cntDSEnteredOFJava = new Counter();
- cntUSDecodeFail = new Counter();
- cntUSDecodeSuccess = new Counter();
- cntUSMessagePass = new Counter();
- cntUSReceivedOFJava = new Counter();
- LOGGER.debug("StaticsCounters (without Map) has been created");
-// countersMap = new ConcurrentHashMap<>();
-// countersMap.put(CounterEventTypes.DS_ENCODE_FAIL, new Counter());
-// countersMap.put(CounterEventTypes.DS_ENCODE_SUCCESS, new Counter());
-// countersMap.put(CounterEventTypes.DS_ENTERED_OFJAVA, new Counter());
-// countersMap.put(CounterEventTypes.US_DECODE_FAIL, new Counter());
-// countersMap.put(CounterEventTypes.US_DECODE_SUCCESS, new Counter());
-// countersMap.put(CounterEventTypes.US_MESSAGE_PASS, new Counter());
-// countersMap.put(CounterEventTypes.US_RECEIVED_IN_OFJAVA, new Counter());
-// LOGGER.debug("StaticsCounters (with Map) has been created");
- }
-
- /**
- * Get given counter
- * @param counterEventKey - key to identify counter
- * @return
- */
- public Counter getCounter(CounterEventTypes counterEventKey){
- if(counterEventKey == null){
- throw new IllegalArgumentException("counterEventKey can not be null");
+ countersMap = new ConcurrentHashMap<>();
+ for(CounterEventTypes cet : enabledCounters){
+ countersMap.put(cet, new Counter());
+ }
+ runCounting = false;
+ this.logReportPeriod = 0;
+ this.runLogReport = false;
+ LOGGER.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();
+ LOGGER.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;
+ LOGGER.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;
}
- switch (counterEventKey){
- case DS_ENCODE_FAIL:
- return cntDSEncodeFail;
- case DS_ENCODE_SUCCESS:
- return cntDSEncodeSuccess;
- case DS_ENTERED_OFJAVA:
- return cntDSEnteredOFJava;
- case US_DECODE_FAIL:
- return cntUSDecodeFail;
- case US_DECODE_SUCCESS:
- return cntUSDecodeSuccess;
- case US_MESSAGE_PASS:
- return cntUSMessagePass;
- case US_RECEIVED_IN_OFJAVA:
- return cntUSReceivedOFJava;
- default:
- throw new IllegalArgumentException("unknown counterEventKey");
+ if(logReportDelay <= 0){
+ throw new IllegalArgumentException("logReportDelay has to be greater than 0");
}
-// return countersMap.get(counterEventKey);
+ 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;
+ LOGGER.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();
+ LOGGER.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;
+ }
+
+ /**
+ * @return the current delay between two writings into logs
+ */
+ public int getLogReportPeriod() {
+ return logReportPeriod;
+ }
+
+ /**
+ * @return the enabled counters
+ */
+ protected CounterEventTypes[] getEnabledCounters() {
+ return enabledCounters;
+ }
+ /**
+ * @return the countersMap
+ */
+ protected Map<CounterEventTypes, Counter> getCountersMap() {
+ return countersMap;
+ }
+
+ /**
+ * Give an information if is given counter is enabled
+ * @param counterEventKey
+ * @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
+ * @exception - 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
- * @return
- */
- public void incrementCounter(CounterEventTypes counterEventKey){
- getCounter(counterEventKey).incrementCounter();
- }
-
- /**
- * Set values of all counter to 0 (zero)
- */
- public void resetCounters(){
- cntDSEncodeFail.reset(); ;
- cntDSEncodeSuccess.reset();
- cntDSEnteredOFJava.reset();
- cntUSDecodeFail.reset();
- cntUSDecodeSuccess.reset();
- cntUSMessagePass.reset();
- cntUSReceivedOFJava.reset();
-// countersMap.get(CounterEventTypes.DS_ENCODE_FAIL).reset();
-// countersMap.get(CounterEventTypes.DS_ENCODE_SUCCESS).reset();
-// countersMap.get(CounterEventTypes.DS_ENTERED_OFJAVA).reset();
-// countersMap.get(CounterEventTypes.US_DECODE_FAIL).reset();
-// countersMap.get(CounterEventTypes.US_DECODE_SUCCESS).reset();
-// countersMap.get(CounterEventTypes.US_MESSAGE_PASS).reset();
-// countersMap.get(CounterEventTypes.US_RECEIVED_IN_OFJAVA).reset();
+ * @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();
+ }
LOGGER.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 static final Logger LOG = LoggerFactory.getLogger(LogReporterTask.class);
+
+ private StatisticsCounters sc;
+ public LogReporterTask(StatisticsCounters sc) {
+ this.sc = sc;
+ }
+
+ @Override
+ public void run() {
+ for(CounterEventTypes cet : sc.getEnabledCounters()){
+ LOG.debug(cet.name() + ": " + sc.getCountersMap().get(cet).getStat());
+ }
+ }
+ }
+}
\ No newline at end of file