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 Date getLastExchangeCreatedTimestamp() {
171        long value = lastExchangeCreatedTimestamp.getValue();
172        return value > 0 ? new Date(value) : null;
173    }
174
175    @Override
176    public Date getLastExchangeCompletedTimestamp() {
177        long value = lastExchangeCompletedTimestamp.getValue();
178        return value > 0 ? new Date(value) : null;
179    }
180
181    @Override
182    public String getLastExchangeCompletedExchangeId() {
183        return lastExchangeCompletedExchangeId;
184    }
185
186    @Override
187    public Date getFirstExchangeCompletedTimestamp() {
188        long value = firstExchangeCompletedTimestamp.getValue();
189        return value > 0 ? new Date(value) : null;
190    }
191
192    @Override
193    public String getFirstExchangeCompletedExchangeId() {
194        return firstExchangeCompletedExchangeId;
195    }
196
197    @Override
198    public Date getLastExchangeFailureTimestamp() {
199        long value = lastExchangeFailureTimestamp.getValue();
200        return value > 0 ? new Date(value) : null;
201    }
202
203    @Override
204    public String getLastExchangeFailureExchangeId() {
205        return lastExchangeFailureExchangeId;
206    }
207
208    @Override
209    public Date getFirstExchangeFailureTimestamp() {
210        long value = firstExchangeFailureTimestamp.getValue();
211        return value > 0 ? new Date(value) : null;
212    }
213
214    @Override
215    public String getFirstExchangeFailureExchangeId() {
216        return firstExchangeFailureExchangeId;
217    }
218
219    @Override
220    public boolean isStatisticsEnabled() {
221        return statisticsEnabled;
222    }
223
224    @Override
225    public void setStatisticsEnabled(boolean statisticsEnabled) {
226        this.statisticsEnabled = statisticsEnabled;
227    }
228
229    @Override
230    public void processExchange(Exchange exchange, String type) {
231        exchangesInflight.increment();
232        if ("route".equals(type)) {
233            long now = System.currentTimeMillis();
234            lastExchangeCreatedTimestamp.updateValue(now);
235        }
236    }
237
238    @Override
239    public void completedExchange(Exchange exchange, long time) {
240        increment();
241        exchangesCompleted.increment();
242        exchangesInflight.decrement();
243
244        if (ExchangeHelper.isFailureHandled(exchange)) {
245            failuresHandled.increment();
246        }
247        if (exchange.isExternalRedelivered()) {
248            externalRedeliveries.increment();
249        }
250
251        minProcessingTime.updateValue(time);
252        maxProcessingTime.updateValue(time);
253        totalProcessingTime.updateValue(time);
254        lastProcessingTime.updateValue(time);
255        deltaProcessingTime.updateValue(time);
256
257        long now = System.currentTimeMillis();
258        if (!firstExchangeCompletedTimestamp.isUpdated()) {
259            firstExchangeCompletedTimestamp.updateValue(now);
260        }
261
262        lastExchangeCompletedTimestamp.updateValue(now);
263        if (firstExchangeCompletedExchangeId == null) {
264            firstExchangeCompletedExchangeId = exchange.getExchangeId();
265        }
266        lastExchangeCompletedExchangeId = exchange.getExchangeId();
267
268        // update mean
269        long mean = 0;
270        long completed = exchangesCompleted.getValue();
271        if (completed > 0) {
272            mean = totalProcessingTime.getValue() / completed;
273        }
274        meanProcessingTime.updateValue(mean);
275    }
276
277    @Override
278    public void failedExchange(Exchange exchange) {
279        increment();
280        exchangesFailed.increment();
281        exchangesInflight.decrement();
282
283        if (ExchangeHelper.isRedelivered(exchange)) {
284            redeliveries.increment();
285        }
286        if (exchange.isExternalRedelivered()) {
287            externalRedeliveries.increment();
288        }
289
290        long now = System.currentTimeMillis();
291        if (!firstExchangeFailureTimestamp.isUpdated()) {
292            firstExchangeFailureTimestamp.updateValue(now);
293        }
294
295        lastExchangeFailureTimestamp.updateValue(now);
296        if (firstExchangeFailureExchangeId == null) {
297            firstExchangeFailureExchangeId = exchange.getExchangeId();
298        }
299        lastExchangeFailureExchangeId = exchange.getExchangeId();
300    }
301
302    @Override
303    public String dumpStatsAsXml(boolean fullStats) {
304        StringBuilder sb = new StringBuilder();
305        sb.append("<stats ");
306        sb.append(String.format("exchangesCompleted=\"%s\"", exchangesCompleted.getValue()));
307        sb.append(String.format(" exchangesFailed=\"%s\"", exchangesFailed.getValue()));
308        sb.append(String.format(" failuresHandled=\"%s\"", failuresHandled.getValue()));
309        sb.append(String.format(" redeliveries=\"%s\"", redeliveries.getValue()));
310        sb.append(String.format(" externalRedeliveries=\"%s\"", externalRedeliveries.getValue()));
311        sb.append(String.format(" minProcessingTime=\"%s\"", minProcessingTime.getValue()));
312        sb.append(String.format(" maxProcessingTime=\"%s\"", maxProcessingTime.getValue()));
313        sb.append(String.format(" totalProcessingTime=\"%s\"", totalProcessingTime.getValue()));
314        sb.append(String.format(" lastProcessingTime=\"%s\"", lastProcessingTime.getValue()));
315        sb.append(String.format(" deltaProcessingTime=\"%s\"", deltaProcessingTime.getValue()));
316        sb.append(String.format(" meanProcessingTime=\"%s\"", meanProcessingTime.getValue()));
317
318        if (fullStats) {
319            sb.append(String.format(" startTimestamp=\"%s\"", dateAsString(startTimestamp.getTime())));
320            sb.append(String.format(" resetTimestamp=\"%s\"", dateAsString(resetTimestamp.getTime())));
321            sb.append(String.format(" firstExchangeCompletedTimestamp=\"%s\"",
322                    dateAsString(firstExchangeCompletedTimestamp.getValue())));
323            sb.append(String.format(" firstExchangeCompletedExchangeId=\"%s\"", nullSafe(firstExchangeCompletedExchangeId)));
324            sb.append(String.format(" firstExchangeFailureTimestamp=\"%s\"",
325                    dateAsString(firstExchangeFailureTimestamp.getValue())));
326            sb.append(String.format(" firstExchangeFailureExchangeId=\"%s\"", nullSafe(firstExchangeFailureExchangeId)));
327            sb.append(String.format(" lastExchangeCreatedTimestamp=\"%s\"",
328                    dateAsString(lastExchangeCreatedTimestamp.getValue())));
329            sb.append(String.format(" lastExchangeCompletedTimestamp=\"%s\"",
330                    dateAsString(lastExchangeCompletedTimestamp.getValue())));
331            sb.append(String.format(" lastExchangeCompletedExchangeId=\"%s\"", nullSafe(lastExchangeCompletedExchangeId)));
332            sb.append(String.format(" lastExchangeFailureTimestamp=\"%s\"",
333                    dateAsString(lastExchangeFailureTimestamp.getValue())));
334            sb.append(String.format(" lastExchangeFailureExchangeId=\"%s\"", nullSafe(lastExchangeFailureExchangeId)));
335        }
336        sb.append("/>");
337        return sb.toString();
338    }
339
340    private static String dateAsString(long value) {
341        if (value <= 0) {
342            return "";
343        }
344        return new SimpleDateFormat(TIMESTAMP_FORMAT).format(value);
345    }
346
347    private static String nullSafe(String s) {
348        return s != null ? s : "";
349    }
350
351}