001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.camel.management.mbean;
018
019import java.text.SimpleDateFormat;
020import java.util.Date;
021
022import org.apache.camel.Exchange;
023import org.apache.camel.api.management.ManagedResource;
024import org.apache.camel.api.management.mbean.ManagedPerformanceCounterMBean;
025import org.apache.camel.management.PerformanceCounter;
026import org.apache.camel.spi.ManagementStrategy;
027import org.apache.camel.support.ExchangeHelper;
028
029@ManagedResource(description = "Managed PerformanceCounter")
030public abstract class ManagedPerformanceCounter extends ManagedCounter implements PerformanceCounter, ManagedPerformanceCounterMBean {
031
032    public static final String TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
033
034    private Statistic exchangesCompleted;
035    private Statistic exchangesFailed;
036    private Statistic exchangesInflight;
037    private Statistic failuresHandled;
038    private Statistic redeliveries;
039    private Statistic externalRedeliveries;
040    private Statistic minProcessingTime;
041    private Statistic maxProcessingTime;
042    private Statistic totalProcessingTime;
043    private Statistic lastProcessingTime;
044    private Statistic deltaProcessingTime;
045    private Statistic meanProcessingTime;
046    private Statistic firstExchangeCompletedTimestamp;
047    private String firstExchangeCompletedExchangeId;
048    private Statistic firstExchangeFailureTimestamp;
049    private String firstExchangeFailureExchangeId;
050    private Statistic lastExchangeCompletedTimestamp;
051    private String lastExchangeCompletedExchangeId;
052    private Statistic lastExchangeFailureTimestamp;
053    private String lastExchangeFailureExchangeId;
054    private boolean statisticsEnabled = true;
055
056    @Override
057    public void init(ManagementStrategy strategy) {
058        super.init(strategy);
059        this.exchangesCompleted = new StatisticCounter();
060        this.exchangesFailed = new StatisticCounter();
061        this.exchangesInflight = new StatisticCounter();
062
063        this.failuresHandled = new StatisticCounter();
064        this.redeliveries = new StatisticCounter();
065        this.externalRedeliveries = new StatisticCounter();
066
067        this.minProcessingTime = new StatisticMinimum();
068        this.maxProcessingTime = new StatisticMaximum();
069        this.totalProcessingTime = new StatisticCounter();
070        this.lastProcessingTime = new StatisticValue();
071        this.deltaProcessingTime = new StatisticDelta();
072        this.meanProcessingTime = new StatisticValue();
073
074        this.firstExchangeCompletedTimestamp = new StatisticValue();
075        this.firstExchangeFailureTimestamp = new StatisticValue();
076        this.lastExchangeCompletedTimestamp = new StatisticValue();
077        this.lastExchangeFailureTimestamp = new StatisticValue();
078    }
079
080    @Override
081    public void reset() {
082        super.reset();
083        exchangesCompleted.reset();
084        exchangesFailed.reset();
085        exchangesInflight.reset();
086        failuresHandled.reset();
087        redeliveries.reset();
088        externalRedeliveries.reset();
089        minProcessingTime.reset();
090        maxProcessingTime.reset();
091        totalProcessingTime.reset();
092        lastProcessingTime.reset();
093        deltaProcessingTime.reset();
094        meanProcessingTime.reset();
095        firstExchangeCompletedTimestamp.reset();
096        firstExchangeCompletedExchangeId = null;
097        firstExchangeFailureTimestamp.reset();
098        firstExchangeFailureExchangeId = null;
099        lastExchangeCompletedTimestamp.reset();
100        lastExchangeCompletedExchangeId = null;
101        lastExchangeFailureTimestamp.reset();
102        lastExchangeFailureExchangeId = null;
103    }
104
105    @Override
106    public long getExchangesCompleted() throws Exception {
107        return exchangesCompleted.getValue();
108    }
109
110    @Override
111    public long getExchangesFailed() throws Exception {
112        return exchangesFailed.getValue();
113    }
114
115    @Override
116    public long getExchangesInflight() {
117        return exchangesInflight.getValue();
118    }
119
120    @Override
121    public long getFailuresHandled() throws Exception {
122        return failuresHandled.getValue();
123    }
124
125    @Override
126    public long getRedeliveries() throws Exception {
127        return redeliveries.getValue();
128    }
129
130    @Override
131    public long getExternalRedeliveries() throws Exception {
132        return externalRedeliveries.getValue();
133    }
134
135    @Override
136    public long getMinProcessingTime() throws Exception {
137        return minProcessingTime.getValue();
138    }
139
140    @Override
141    public long getMeanProcessingTime() throws Exception {
142        return meanProcessingTime.getValue();
143    }
144
145    @Override
146    public long getMaxProcessingTime() throws Exception {
147        return maxProcessingTime.getValue();
148    }
149
150    @Override
151    public long getTotalProcessingTime() throws Exception {
152        return totalProcessingTime.getValue();
153    }
154
155    @Override
156    public long getLastProcessingTime() throws Exception {
157        return lastProcessingTime.getValue();
158    }
159
160    @Override
161    public long getDeltaProcessingTime() throws Exception {
162        return deltaProcessingTime.getValue();
163    }
164
165    @Override
166    public Date getLastExchangeCompletedTimestamp() {
167        long value = lastExchangeCompletedTimestamp.getValue();
168        return value > 0 ? new Date(value) : null;
169    }
170
171    @Override
172    public String getLastExchangeCompletedExchangeId() {
173        return lastExchangeCompletedExchangeId;
174    }
175
176    @Override
177    public Date getFirstExchangeCompletedTimestamp() {
178        long value = firstExchangeCompletedTimestamp.getValue();
179        return value > 0 ? new Date(value) : null;
180    }
181
182    @Override
183    public String getFirstExchangeCompletedExchangeId() {
184        return firstExchangeCompletedExchangeId;
185    }
186
187    @Override
188    public Date getLastExchangeFailureTimestamp() {
189        long value = lastExchangeFailureTimestamp.getValue();
190        return value > 0 ? new Date(value) : null;
191    }
192
193    @Override
194    public String getLastExchangeFailureExchangeId() {
195        return lastExchangeFailureExchangeId;
196    }
197
198    @Override
199    public Date getFirstExchangeFailureTimestamp() {
200        long value = firstExchangeFailureTimestamp.getValue();
201        return value > 0 ? new Date(value) : null;
202    }
203
204    @Override
205    public String getFirstExchangeFailureExchangeId() {
206        return firstExchangeFailureExchangeId;
207    }
208
209    @Override
210    public boolean isStatisticsEnabled() {
211        return statisticsEnabled;
212    }
213
214    @Override
215    public void setStatisticsEnabled(boolean statisticsEnabled) {
216        this.statisticsEnabled = statisticsEnabled;
217    }
218
219    @Override
220    public void processExchange(Exchange exchange) {
221        exchangesInflight.increment();
222    }
223
224    @Override
225    public void completedExchange(Exchange exchange, long time) {
226        increment();
227        exchangesCompleted.increment();
228        exchangesInflight.decrement();
229
230        if (ExchangeHelper.isFailureHandled(exchange)) {
231            failuresHandled.increment();
232        }
233        if (exchange.isExternalRedelivered()) {
234            externalRedeliveries.increment();
235        }
236
237        minProcessingTime.updateValue(time);
238        maxProcessingTime.updateValue(time);
239        totalProcessingTime.updateValue(time);
240        lastProcessingTime.updateValue(time);
241        deltaProcessingTime.updateValue(time);
242
243        long now = System.currentTimeMillis();
244        if (!firstExchangeCompletedTimestamp.isUpdated()) {
245            firstExchangeCompletedTimestamp.updateValue(now);
246        }
247
248        lastExchangeCompletedTimestamp.updateValue(now);
249        if (firstExchangeCompletedExchangeId == null) {
250            firstExchangeCompletedExchangeId = exchange.getExchangeId();
251        }
252        lastExchangeCompletedExchangeId = exchange.getExchangeId();
253
254        // update mean
255        long mean = 0;
256        long completed = exchangesCompleted.getValue();
257        if (completed > 0) {
258            mean = totalProcessingTime.getValue() / completed;
259        }
260        meanProcessingTime.updateValue(mean);
261    }
262
263    @Override
264    public void failedExchange(Exchange exchange) {
265        increment();
266        exchangesFailed.increment();
267        exchangesInflight.decrement();
268
269        if (ExchangeHelper.isRedelivered(exchange)) {
270            redeliveries.increment();
271        }
272        if (exchange.isExternalRedelivered()) {
273            externalRedeliveries.increment();
274        }
275
276        long now = System.currentTimeMillis();
277        if (!firstExchangeFailureTimestamp.isUpdated()) {
278            firstExchangeFailureTimestamp.updateValue(now);
279        }
280
281        lastExchangeFailureTimestamp.updateValue(now);
282        if (firstExchangeFailureExchangeId == null) {
283            firstExchangeFailureExchangeId = exchange.getExchangeId();
284        }
285        lastExchangeFailureExchangeId = exchange.getExchangeId();
286    }
287
288    @Override
289    public String dumpStatsAsXml(boolean fullStats) {
290        StringBuilder sb = new StringBuilder();
291        sb.append("<stats ");
292        sb.append(String.format("exchangesCompleted=\"%s\"", exchangesCompleted.getValue()));
293        sb.append(String.format(" exchangesFailed=\"%s\"", exchangesFailed.getValue()));
294        sb.append(String.format(" failuresHandled=\"%s\"", failuresHandled.getValue()));
295        sb.append(String.format(" redeliveries=\"%s\"", redeliveries.getValue()));
296        sb.append(String.format(" externalRedeliveries=\"%s\"", externalRedeliveries.getValue()));
297        sb.append(String.format(" minProcessingTime=\"%s\"", minProcessingTime.getValue()));
298        sb.append(String.format(" maxProcessingTime=\"%s\"", maxProcessingTime.getValue()));
299        sb.append(String.format(" totalProcessingTime=\"%s\"", totalProcessingTime.getValue()));
300        sb.append(String.format(" lastProcessingTime=\"%s\"", lastProcessingTime.getValue()));
301        sb.append(String.format(" deltaProcessingTime=\"%s\"", deltaProcessingTime.getValue()));
302        sb.append(String.format(" meanProcessingTime=\"%s\"", meanProcessingTime.getValue()));
303
304        if (fullStats) {
305            sb.append(String.format(" startTimestamp=\"%s\"", dateAsString(startTimestamp.getTime())));
306            sb.append(String.format(" resetTimestamp=\"%s\"", dateAsString(resetTimestamp.getTime())));
307            sb.append(String.format(" firstExchangeCompletedTimestamp=\"%s\"", dateAsString(firstExchangeCompletedTimestamp.getValue())));
308            sb.append(String.format(" firstExchangeCompletedExchangeId=\"%s\"", nullSafe(firstExchangeCompletedExchangeId)));
309            sb.append(String.format(" firstExchangeFailureTimestamp=\"%s\"", dateAsString(firstExchangeFailureTimestamp.getValue())));
310            sb.append(String.format(" firstExchangeFailureExchangeId=\"%s\"", nullSafe(firstExchangeFailureExchangeId)));
311            sb.append(String.format(" lastExchangeCompletedTimestamp=\"%s\"", dateAsString(lastExchangeCompletedTimestamp.getValue())));
312            sb.append(String.format(" lastExchangeCompletedExchangeId=\"%s\"", nullSafe(lastExchangeCompletedExchangeId)));
313            sb.append(String.format(" lastExchangeFailureTimestamp=\"%s\"", dateAsString(lastExchangeFailureTimestamp.getValue())));
314            sb.append(String.format(" lastExchangeFailureExchangeId=\"%s\"", nullSafe(lastExchangeFailureExchangeId)));
315        }
316        sb.append("/>");
317        return sb.toString();
318    }
319
320    private static String dateAsString(long value) {
321        if (value <= 0) {
322            return "";
323        }
324        return new SimpleDateFormat(TIMESTAMP_FORMAT).format(value);
325    }
326    
327    private static String nullSafe(String s) {
328        return s != null ? s : "";
329    }
330
331}