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
031        implements PerformanceCounter, ManagedPerformanceCounterMBean {
032
033    public static final String TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
034
035    private Statistic exchangesCompleted;
036    private Statistic exchangesFailed;
037    private Statistic exchangesInflight;
038    private Statistic failuresHandled;
039    private Statistic redeliveries;
040    private Statistic externalRedeliveries;
041    private Statistic minProcessingTime;
042    private Statistic maxProcessingTime;
043    private Statistic totalProcessingTime;
044    private Statistic lastProcessingTime;
045    private Statistic deltaProcessingTime;
046    private Statistic meanProcessingTime;
047    private Statistic firstExchangeCompletedTimestamp;
048    private String firstExchangeCompletedExchangeId;
049    private Statistic firstExchangeFailureTimestamp;
050    private String firstExchangeFailureExchangeId;
051    private Statistic lastExchangeCreatedTimestamp;
052    private Statistic lastExchangeCompletedTimestamp;
053    private String lastExchangeCompletedExchangeId;
054    private Statistic lastExchangeFailureTimestamp;
055    private String lastExchangeFailureExchangeId;
056    private boolean statisticsEnabled = true;
057
058    @Override
059    public void init(ManagementStrategy strategy) {
060        super.init(strategy);
061        this.exchangesCompleted = new StatisticCounter();
062        this.exchangesFailed = new StatisticCounter();
063        this.exchangesInflight = new StatisticCounter();
064
065        this.failuresHandled = new StatisticCounter();
066        this.redeliveries = new StatisticCounter();
067        this.externalRedeliveries = new StatisticCounter();
068
069        this.minProcessingTime = new StatisticMinimum();
070        this.maxProcessingTime = new StatisticMaximum();
071        this.totalProcessingTime = new StatisticCounter();
072        this.lastProcessingTime = new StatisticValue();
073        this.deltaProcessingTime = new StatisticDelta();
074        this.meanProcessingTime = new StatisticValue();
075
076        this.firstExchangeCompletedTimestamp = new StatisticValue();
077        this.firstExchangeFailureTimestamp = new StatisticValue();
078        this.lastExchangeCreatedTimestamp = new StatisticValue();
079        this.lastExchangeCompletedTimestamp = new StatisticValue();
080        this.lastExchangeFailureTimestamp = new StatisticValue();
081    }
082
083    @Override
084    public void reset() {
085        super.reset();
086        exchangesCompleted.reset();
087        exchangesFailed.reset();
088        // do not reset exchangesInflight
089        failuresHandled.reset();
090        redeliveries.reset();
091        externalRedeliveries.reset();
092        minProcessingTime.reset();
093        maxProcessingTime.reset();
094        totalProcessingTime.reset();
095        lastProcessingTime.reset();
096        deltaProcessingTime.reset();
097        meanProcessingTime.reset();
098        firstExchangeCompletedTimestamp.reset();
099        firstExchangeCompletedExchangeId = null;
100        firstExchangeFailureTimestamp.reset();
101        firstExchangeFailureExchangeId = null;
102        lastExchangeCreatedTimestamp.reset();
103        lastExchangeCompletedTimestamp.reset();
104        lastExchangeCompletedExchangeId = null;
105        lastExchangeFailureTimestamp.reset();
106        lastExchangeFailureExchangeId = null;
107    }
108
109    @Override
110    public long getExchangesCompleted() {
111        return exchangesCompleted.getValue();
112    }
113
114    @Override
115    public long getExchangesFailed() {
116        return exchangesFailed.getValue();
117    }
118
119    @Override
120    public long getExchangesInflight() {
121        return exchangesInflight.getValue();
122    }
123
124    @Override
125    public long getFailuresHandled() {
126        return failuresHandled.getValue();
127    }
128
129    @Override
130    public long getRedeliveries() {
131        return redeliveries.getValue();
132    }
133
134    @Override
135    public long getExternalRedeliveries() {
136        return externalRedeliveries.getValue();
137    }
138
139    @Override
140    public long getMinProcessingTime() {
141        return minProcessingTime.getValue();
142    }
143
144    @Override
145    public long getMeanProcessingTime() {
146        return meanProcessingTime.getValue();
147    }
148
149    @Override
150    public long getMaxProcessingTime() {
151        return maxProcessingTime.getValue();
152    }
153
154    @Override
155    public long getTotalProcessingTime() {
156        return totalProcessingTime.getValue();
157    }
158
159    @Override
160    public long getLastProcessingTime() {
161        return lastProcessingTime.getValue();
162    }
163
164    @Override
165    public long getDeltaProcessingTime() {
166        return deltaProcessingTime.getValue();
167    }
168
169    @Override
170    public long getIdleSince() {
171        // must not have any inflight
172        if (getExchangesInflight() <= 0) {
173            // what is the last time since completed/failed
174            long max = Math.max(lastExchangeCompletedTimestamp.getValue(), lastExchangeFailureTimestamp.getValue());
175            if (max > 0) {
176                long delta = System.currentTimeMillis() - max;
177                if (delta > 0) {
178                    return delta;
179                }
180            }
181        }
182        return -1;
183    }
184
185    @Override
186    public Date getLastExchangeCreatedTimestamp() {
187        long value = lastExchangeCreatedTimestamp.getValue();
188        return value > 0 ? new Date(value) : null;
189    }
190
191    @Override
192    public Date getLastExchangeCompletedTimestamp() {
193        long value = lastExchangeCompletedTimestamp.getValue();
194        return value > 0 ? new Date(value) : null;
195    }
196
197    @Override
198    public String getLastExchangeCompletedExchangeId() {
199        return lastExchangeCompletedExchangeId;
200    }
201
202    @Override
203    public Date getFirstExchangeCompletedTimestamp() {
204        long value = firstExchangeCompletedTimestamp.getValue();
205        return value > 0 ? new Date(value) : null;
206    }
207
208    @Override
209    public String getFirstExchangeCompletedExchangeId() {
210        return firstExchangeCompletedExchangeId;
211    }
212
213    @Override
214    public Date getLastExchangeFailureTimestamp() {
215        long value = lastExchangeFailureTimestamp.getValue();
216        return value > 0 ? new Date(value) : null;
217    }
218
219    @Override
220    public String getLastExchangeFailureExchangeId() {
221        return lastExchangeFailureExchangeId;
222    }
223
224    @Override
225    public Date getFirstExchangeFailureTimestamp() {
226        long value = firstExchangeFailureTimestamp.getValue();
227        return value > 0 ? new Date(value) : null;
228    }
229
230    @Override
231    public String getFirstExchangeFailureExchangeId() {
232        return firstExchangeFailureExchangeId;
233    }
234
235    @Override
236    public boolean isStatisticsEnabled() {
237        return statisticsEnabled;
238    }
239
240    @Override
241    public void setStatisticsEnabled(boolean statisticsEnabled) {
242        this.statisticsEnabled = statisticsEnabled;
243    }
244
245    @Override
246    public void processExchange(Exchange exchange, String type) {
247        exchangesInflight.increment();
248        if ("route".equals(type)) {
249            long now = System.currentTimeMillis();
250            lastExchangeCreatedTimestamp.updateValue(now);
251        }
252    }
253
254    @Override
255    public void completedExchange(Exchange exchange, long time) {
256        increment();
257        exchangesCompleted.increment();
258        exchangesInflight.decrement();
259
260        if (ExchangeHelper.isFailureHandled(exchange)) {
261            failuresHandled.increment();
262        }
263        if (exchange.isExternalRedelivered()) {
264            externalRedeliveries.increment();
265        }
266
267        minProcessingTime.updateValue(time);
268        maxProcessingTime.updateValue(time);
269        totalProcessingTime.updateValue(time);
270        lastProcessingTime.updateValue(time);
271        deltaProcessingTime.updateValue(time);
272
273        long now = System.currentTimeMillis();
274        if (!firstExchangeCompletedTimestamp.isUpdated()) {
275            firstExchangeCompletedTimestamp.updateValue(now);
276        }
277
278        lastExchangeCompletedTimestamp.updateValue(now);
279        if (firstExchangeCompletedExchangeId == null) {
280            firstExchangeCompletedExchangeId = exchange.getExchangeId();
281        }
282        lastExchangeCompletedExchangeId = exchange.getExchangeId();
283
284        // update mean
285        long mean = 0;
286        long completed = exchangesCompleted.getValue();
287        if (completed > 0) {
288            mean = totalProcessingTime.getValue() / completed;
289        }
290        meanProcessingTime.updateValue(mean);
291    }
292
293    @Override
294    public void failedExchange(Exchange exchange) {
295        increment();
296        exchangesFailed.increment();
297        exchangesInflight.decrement();
298
299        if (ExchangeHelper.isRedelivered(exchange)) {
300            redeliveries.increment();
301        }
302        if (exchange.isExternalRedelivered()) {
303            externalRedeliveries.increment();
304        }
305
306        long now = System.currentTimeMillis();
307        if (!firstExchangeFailureTimestamp.isUpdated()) {
308            firstExchangeFailureTimestamp.updateValue(now);
309        }
310
311        lastExchangeFailureTimestamp.updateValue(now);
312        if (firstExchangeFailureExchangeId == null) {
313            firstExchangeFailureExchangeId = exchange.getExchangeId();
314        }
315        lastExchangeFailureExchangeId = exchange.getExchangeId();
316    }
317
318    @Override
319    public String dumpStatsAsXml(boolean fullStats) {
320        StringBuilder sb = new StringBuilder();
321        sb.append("<stats ");
322        sb.append(String.format("exchangesCompleted=\"%s\"", exchangesCompleted.getValue()));
323        sb.append(String.format(" exchangesFailed=\"%s\"", exchangesFailed.getValue()));
324        sb.append(String.format(" failuresHandled=\"%s\"", failuresHandled.getValue()));
325        sb.append(String.format(" redeliveries=\"%s\"", redeliveries.getValue()));
326        sb.append(String.format(" externalRedeliveries=\"%s\"", externalRedeliveries.getValue()));
327        sb.append(String.format(" minProcessingTime=\"%s\"", minProcessingTime.getValue()));
328        sb.append(String.format(" maxProcessingTime=\"%s\"", maxProcessingTime.getValue()));
329        sb.append(String.format(" totalProcessingTime=\"%s\"", totalProcessingTime.getValue()));
330        sb.append(String.format(" lastProcessingTime=\"%s\"", lastProcessingTime.getValue()));
331        sb.append(String.format(" deltaProcessingTime=\"%s\"", deltaProcessingTime.getValue()));
332        sb.append(String.format(" meanProcessingTime=\"%s\"", meanProcessingTime.getValue()));
333        sb.append(String.format(" idleSince=\"%s\"", getIdleSince()));
334
335        if (fullStats) {
336            sb.append(String.format(" startTimestamp=\"%s\"", dateAsString(startTimestamp.getTime())));
337            sb.append(String.format(" resetTimestamp=\"%s\"", dateAsString(resetTimestamp.getTime())));
338            sb.append(String.format(" firstExchangeCompletedTimestamp=\"%s\"",
339                    dateAsString(firstExchangeCompletedTimestamp.getValue())));
340            sb.append(String.format(" firstExchangeCompletedExchangeId=\"%s\"", nullSafe(firstExchangeCompletedExchangeId)));
341            sb.append(String.format(" firstExchangeFailureTimestamp=\"%s\"",
342                    dateAsString(firstExchangeFailureTimestamp.getValue())));
343            sb.append(String.format(" firstExchangeFailureExchangeId=\"%s\"", nullSafe(firstExchangeFailureExchangeId)));
344            sb.append(String.format(" lastExchangeCreatedTimestamp=\"%s\"",
345                    dateAsString(lastExchangeCreatedTimestamp.getValue())));
346            sb.append(String.format(" lastExchangeCompletedTimestamp=\"%s\"",
347                    dateAsString(lastExchangeCompletedTimestamp.getValue())));
348            sb.append(String.format(" lastExchangeCompletedExchangeId=\"%s\"", nullSafe(lastExchangeCompletedExchangeId)));
349            sb.append(String.format(" lastExchangeFailureTimestamp=\"%s\"",
350                    dateAsString(lastExchangeFailureTimestamp.getValue())));
351            sb.append(String.format(" lastExchangeFailureExchangeId=\"%s\"", nullSafe(lastExchangeFailureExchangeId)));
352        }
353        sb.append("/>");
354        return sb.toString();
355    }
356
357    private static String dateAsString(long value) {
358        if (value <= 0) {
359            return "";
360        }
361        return new SimpleDateFormat(TIMESTAMP_FORMAT).format(value);
362    }
363
364    private static String nullSafe(String s) {
365        return s != null ? s : "";
366    }
367
368}