Statistics collection added
[openflowjava.git] / openflow-protocol-impl / src / main / java / org / opendaylight / openflowjava / statistics / StatisticsCounters.java
1 /*
2  * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.openflowjava.statistics;
9
10 import java.util.Map;
11 import java.util.Timer;
12 import java.util.TimerTask;
13 import java.util.concurrent.ConcurrentHashMap;
14
15 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory;
17
18 /**
19  * Singleton class to hold and process counters
20  * @author madamjak
21  *
22  */
23 public final class StatisticsCounters {
24
25     /**
26      * Default delay between two writings into log (milliseconds)
27      */
28     public static final int DEFAULT_LOG_REPORT_PERIOD = 10000;
29     /**
30      * Minimal delay between two writings into log (milliseconds)
31      */
32     public static final int MINIMAL_LOG_REPORT_PERIOD = 500;
33     private static StatisticsCounters instanceHolder;
34     private static final Logger LOGGER = LoggerFactory.getLogger(StatisticsCounters.class);
35
36     private Timer logReporter;
37     private int logReportPeriod;
38     private boolean runLogReport;
39     private Map<CounterEventTypes, Counter> countersMap;
40     private boolean runCounting;
41     // array to hold enabled counter types
42     private CounterEventTypes[] enabledCounters = {
43                     CounterEventTypes.DS_ENCODE_FAIL, 
44                     CounterEventTypes.DS_ENCODE_SUCCESS,
45                     CounterEventTypes.DS_ENTERED_OFJAVA,
46                     CounterEventTypes.DS_FLOW_MODS_ENTERED,
47                     CounterEventTypes.DS_FLOW_MODS_SENT,
48                     CounterEventTypes.US_DECODE_FAIL, 
49                     CounterEventTypes.US_DECODE_SUCCESS, 
50                     CounterEventTypes.US_MESSAGE_PASS, 
51                     CounterEventTypes.US_RECEIVED_IN_OFJAVA};
52
53     /**
54      * Get instance of statistics counters, first created object does not start counting and log reporting
55      * @return an instance
56      */
57     public synchronized static StatisticsCounters getInstance() {
58         if (instanceHolder == null) {
59             instanceHolder = new StatisticsCounters();
60         }
61         return instanceHolder;
62     }
63
64     private StatisticsCounters() {
65         countersMap = new ConcurrentHashMap<>();
66         for(CounterEventTypes cet : enabledCounters){
67             countersMap.put(cet, new Counter());
68         }
69         runCounting = false;
70         this.logReportPeriod = -1;
71         this.runLogReport = false;
72         LOGGER.debug("StaticsCounters has been created");
73     }
74
75     /**
76      * Start counting
77      * @param resetCounters - true = statistics counters will be reset before start counting
78      * @param reportToLogs - true = statistics counters will periodically write to log
79      * @param logReportDelay - delay between two writings into logs in milliseconds (for details see startLogReport(int logReportDelay))
80      */
81     public void startCounting(boolean resetCounters, boolean reportToLogs, int logReportDelay){
82         if (runCounting) {
83             return;
84         }
85         LOGGER.debug("Start counting...");
86         if(reportToLogs){
87             startLogReport(logReportDelay);
88         }
89         if(resetCounters){
90             resetCounters();
91         }
92         runCounting = true;
93     }
94
95     /**
96      * Start counting (counters are set to 0 before start counting)
97      * @param reportToLogs - true = statistics counters will periodically write to log
98      * @param logReportDelay - delay between two writings into logs in milliseconds (for details see startLogReport(int logReportDelay))
99      */
100     public void startCounting(boolean reportToLogs, int logReportDelay){
101         if (runCounting) {
102             return;
103         }
104         startCounting(true,reportToLogs,logReportDelay);
105     }
106
107     /**
108      * Stop counting, values in counters are untouched, log reporter is stopped
109      */
110     public void stopCounting(){
111         runCounting = false;
112         LOGGER.debug("Stop counting...");
113         stopLogReport();
114     }
115
116     /**
117      * Give an information if counting is running
118      * @return true, if counting is running, otherwise false
119      */
120     public boolean isRunCounting(){
121         return runCounting;
122     }
123
124     /**
125      * Start write statistics into logs, if writing is run calling has no effect. 
126      * If method is called without previous setting of report delay than DEFAULT_LOG_REPORT_PERIOD will be used.
127      */
128     public void startLogReport(){
129         if(runLogReport){
130             return;
131         }
132         if(this.logReportPeriod <= 0){
133             this.logReportPeriod = DEFAULT_LOG_REPORT_PERIOD;
134         }
135         if(this.logReportPeriod <= MINIMAL_LOG_REPORT_PERIOD){
136             this.logReportPeriod = MINIMAL_LOG_REPORT_PERIOD;
137         }
138         logReporter = new Timer("SC_Timer");
139         logReporter.schedule(new LogReporterTask(this), this.logReportPeriod,this.logReportPeriod);
140         runLogReport = true;
141         LOGGER.debug("Statistics log reporter has been scheduled with period {} ms", this.logReportPeriod);
142     }
143
144     /**
145      * Start write statistics into logs with given delay between writings, if writing is run calling has no effect.
146      * @param logReportDelay - delay between two writings into logs (milliseconds). 
147      *            It is mandatory if reportToLogs is true, value have to be greater than 0 (zero)
148      *            If value is smaller than MINIMAL_LOG_REPORT_PERIOD, the value MINIMAL_LOG_REPORT_PERIOD will be used.
149      * @exception IllegalArgumentException if logReportDelay is not greater than 0 (zero)
150      */
151     public void startLogReport(int logReportDelay){
152         if(runLogReport){
153             return;
154         }
155         if(logReportDelay <= 0){
156             throw new IllegalArgumentException("logReportPeriod have to bee greater than 0 zero");
157         }
158         if(logReportDelay < MINIMAL_LOG_REPORT_PERIOD){
159             this.logReportPeriod = MINIMAL_LOG_REPORT_PERIOD;
160         } else {
161             this.logReportPeriod = logReportDelay;
162         }
163         startLogReport();
164     }
165
166     /**
167      * Stop  write statistics into logs, counting does not stop
168      */
169     public void stopLogReport(){
170         if(runLogReport){
171             if(logReporter != null){
172                 logReporter.cancel();
173                 LOGGER.debug("Statistics log reporter has been canceled");
174             }
175             runLogReport = false;
176         }
177     }
178
179     /**
180      * Give an information if log reporter is running (statistics are write into logs).
181      * @return true if log reporter writes statistics into log, otherwise false
182      */
183     public boolean isRunLogReport(){
184         return runLogReport;
185     }
186
187     /**
188      * @return the current delay between two writings into logs
189      */
190     public int getLogReportPeriod() {
191         return logReportPeriod;
192     }
193
194     /**
195      * @return the enabled counters
196      */
197     protected CounterEventTypes[] getEnabledCounters() {
198         return enabledCounters;
199     }
200     /**
201      * @return the countersMap
202      */
203     protected Map<CounterEventTypes, Counter> getCountersMap() {
204         return countersMap;
205     }
206
207     /**
208      * Give an information if is given counter is enabled
209      * @param counterEventKey
210      * @return true if counter has been Enabled, otherwise false
211      */
212     public boolean isCounterEnabled(CounterEventTypes counterEventKey){
213         if (counterEventKey == null) {
214             return false;
215         }
216         return countersMap.containsKey(counterEventKey);
217     }
218
219     /**
220      * Get counter by counter event type
221      * @param counterEventKey key to identify counter (can not be null)
222      * @return - Counter object or null if counter has not been enabled
223      * @exception - IllegalArgumentException if counterEventKey is null
224      */
225     public Counter getCounter(CounterEventTypes counterEventKey) {
226         if (counterEventKey == null) {
227             throw new IllegalArgumentException("counterEventKey can not be null");
228         }
229         return countersMap.get(counterEventKey);
230     }
231
232     /**
233      * Increment value of given counter
234      * @param counterEventKey key to identify counter
235      */
236     public void incrementCounter(CounterEventTypes counterEventKey) {
237         if(runCounting){
238             if (isCounterEnabled(counterEventKey)){
239                 countersMap.get(counterEventKey).incrementCounter();
240             }
241         }
242     }
243
244     /**
245      * Set values of all counter to 0 (zero)
246      */
247     public void resetCounters() {
248         for(CounterEventTypes cet : enabledCounters){
249             countersMap.get(cet).reset();
250         }
251         LOGGER.debug("StaticsCounters has been reset");
252     }
253
254     /**
255      * internal class to process logReporter
256      * @author madamjak
257      *
258      */
259     private static class LogReporterTask extends TimerTask {
260         private static final Logger LOG = LoggerFactory.getLogger(LogReporterTask.class);
261
262         private StatisticsCounters sc;
263         public LogReporterTask(StatisticsCounters sc) {
264             this.sc = sc;
265         }
266
267         @Override
268         public void run() {
269                 for(CounterEventTypes cet : sc.getEnabledCounters()){
270                     LOG.debug(cet.toString() + ": " + sc.getCountersMap().get(cet).toString());
271                 }
272         }
273     }
274 }