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.PerformanceCounter;
025import org.apache.camel.api.management.mbean.ManagedPerformanceCounterMBean;
026import org.apache.camel.spi.ManagementStrategy;
027import org.apache.camel.util.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    public void init(ManagementStrategy strategy) {
057        super.init(strategy);
058        this.exchangesCompleted = new Statistic("org.apache.camel.exchangesCompleted", this, Statistic.UpdateMode.COUNTER);
059        this.exchangesFailed = new Statistic("org.apache.camel.exchangesFailed", this, Statistic.UpdateMode.COUNTER);
060        this.exchangesInflight = new Statistic("org.apache.camel.exchangesInflight", this, Statistic.UpdateMode.COUNTER);
061
062        this.failuresHandled = new Statistic("org.apache.camel.failuresHandled", this, Statistic.UpdateMode.COUNTER);
063        this.redeliveries = new Statistic("org.apache.camel.redeliveries", this, Statistic.UpdateMode.COUNTER);
064        this.externalRedeliveries = new Statistic("org.apache.camel.externalRedeliveries", this, Statistic.UpdateMode.COUNTER);
065
066        this.minProcessingTime = new Statistic("org.apache.camel.minimumProcessingTime", this, Statistic.UpdateMode.MINIMUM);
067        this.maxProcessingTime = new Statistic("org.apache.camel.maximumProcessingTime", this, Statistic.UpdateMode.MAXIMUM);
068        this.totalProcessingTime = new Statistic("org.apache.camel.totalProcessingTime", this, Statistic.UpdateMode.COUNTER);
069        this.lastProcessingTime = new Statistic("org.apache.camel.lastProcessingTime", this, Statistic.UpdateMode.VALUE);
070        this.deltaProcessingTime = new Statistic("org.apache.camel.deltaProcessingTime", this, Statistic.UpdateMode.DELTA);
071        this.meanProcessingTime = new Statistic("org.apache.camel.meanProcessingTime", this, Statistic.UpdateMode.VALUE);
072
073        this.firstExchangeCompletedTimestamp = new Statistic("org.apache.camel.firstExchangeCompletedTimestamp", this, Statistic.UpdateMode.VALUE);
074        this.firstExchangeFailureTimestamp = new Statistic("org.apache.camel.firstExchangeFailureTimestamp", this, Statistic.UpdateMode.VALUE);
075        this.lastExchangeCompletedTimestamp = new Statistic("org.apache.camel.lastExchangeCompletedTimestamp", this, Statistic.UpdateMode.VALUE);
076        this.lastExchangeFailureTimestamp = new Statistic("org.apache.camel.lastExchangeFailureTimestamp", this, Statistic.UpdateMode.VALUE);
077    }
078
079    @Override
080    public synchronized void reset() {
081        super.reset();
082        exchangesCompleted.reset();
083        exchangesFailed.reset();
084        exchangesInflight.reset();
085        failuresHandled.reset();
086        redeliveries.reset();
087        externalRedeliveries.reset();
088        minProcessingTime.reset();
089        maxProcessingTime.reset();
090        totalProcessingTime.reset();
091        lastProcessingTime.reset();
092        deltaProcessingTime.reset();
093        meanProcessingTime.reset();
094        firstExchangeCompletedTimestamp.reset();
095        firstExchangeCompletedExchangeId = null;
096        firstExchangeFailureTimestamp.reset();
097        firstExchangeFailureExchangeId = null;
098        lastExchangeCompletedTimestamp.reset();
099        lastExchangeCompletedExchangeId = null;
100        lastExchangeFailureTimestamp.reset();
101        lastExchangeFailureExchangeId = null;
102    }
103
104    public long getExchangesCompleted() throws Exception {
105        return exchangesCompleted.getValue();
106    }
107
108    public long getExchangesFailed() throws Exception {
109        return exchangesFailed.getValue();
110    }
111
112    public long getExchangesInflight() {
113        return exchangesInflight.getValue();
114    }
115
116    public long getFailuresHandled() throws Exception {
117        return failuresHandled.getValue();
118    }
119
120    public long getRedeliveries() throws Exception {
121        return redeliveries.getValue();
122    }
123
124    public long getExternalRedeliveries() throws Exception {
125        return externalRedeliveries.getValue();
126    }
127
128    public long getMinProcessingTime() throws Exception {
129        return minProcessingTime.getValue();
130    }
131
132    public long getMeanProcessingTime() throws Exception {
133        return meanProcessingTime.getValue();
134    }
135
136    public long getMaxProcessingTime() throws Exception {
137        return maxProcessingTime.getValue();
138    }
139
140    public long getTotalProcessingTime() throws Exception {
141        return totalProcessingTime.getValue();
142    }
143
144    public long getLastProcessingTime() throws Exception {
145        return lastProcessingTime.getValue();
146    }
147
148    public long getDeltaProcessingTime() throws Exception {
149        return deltaProcessingTime.getValue();
150    }
151
152    public Date getLastExchangeCompletedTimestamp() {
153        long value = lastExchangeCompletedTimestamp.getValue();
154        return value > 0 ? new Date(value) : null;
155    }
156
157    public String getLastExchangeCompletedExchangeId() {
158        return lastExchangeCompletedExchangeId;
159    }
160
161    public Date getFirstExchangeCompletedTimestamp() {
162        long value = firstExchangeCompletedTimestamp.getValue();
163        return value > 0 ? new Date(value) : null;
164    }
165
166    public String getFirstExchangeCompletedExchangeId() {
167        return firstExchangeCompletedExchangeId;
168    }
169
170    public Date getLastExchangeFailureTimestamp() {
171        long value = lastExchangeFailureTimestamp.getValue();
172        return value > 0 ? new Date(value) : null;
173    }
174
175    public String getLastExchangeFailureExchangeId() {
176        return lastExchangeFailureExchangeId;
177    }
178
179    public Date getFirstExchangeFailureTimestamp() {
180        long value = firstExchangeFailureTimestamp.getValue();
181        return value > 0 ? new Date(value) : null;
182    }
183
184    public String getFirstExchangeFailureExchangeId() {
185        return firstExchangeFailureExchangeId;
186    }
187
188    public boolean isStatisticsEnabled() {
189        return statisticsEnabled;
190    }
191
192    public void setStatisticsEnabled(boolean statisticsEnabled) {
193        this.statisticsEnabled = statisticsEnabled;
194    }
195
196    public synchronized void processExchange(Exchange exchange) {
197        exchangesInflight.increment();
198    }
199
200    public synchronized void completedExchange(Exchange exchange, long time) {
201        increment();
202        exchangesCompleted.increment();
203        exchangesInflight.decrement();
204
205        if (ExchangeHelper.isFailureHandled(exchange)) {
206            failuresHandled.increment();
207        }
208        Boolean externalRedelivered = exchange.isExternalRedelivered();
209        if (externalRedelivered != null && externalRedelivered) {
210            externalRedeliveries.increment();
211        }
212
213        minProcessingTime.updateValue(time);
214        maxProcessingTime.updateValue(time);
215        totalProcessingTime.updateValue(time);
216        lastProcessingTime.updateValue(time);
217        deltaProcessingTime.updateValue(time);
218
219        long now = new Date().getTime();
220        if (firstExchangeCompletedTimestamp.getUpdateCount() == 0) {
221            firstExchangeCompletedTimestamp.updateValue(now);
222        }
223
224        lastExchangeCompletedTimestamp.updateValue(now);
225        if (firstExchangeCompletedExchangeId == null) {
226            firstExchangeCompletedExchangeId = exchange.getExchangeId();
227        }
228        lastExchangeCompletedExchangeId = exchange.getExchangeId();
229
230        // update mean
231        long count = exchangesCompleted.getValue();
232        long mean = count > 0 ? totalProcessingTime.getValue() / count : 0;
233        meanProcessingTime.updateValue(mean);
234    }
235
236    public synchronized void failedExchange(Exchange exchange) {
237        increment();
238        exchangesFailed.increment();
239        exchangesInflight.decrement();
240
241        if (ExchangeHelper.isRedelivered(exchange)) {
242            redeliveries.increment();
243        }
244        Boolean externalRedelivered = exchange.isExternalRedelivered();
245        if (externalRedelivered != null && externalRedelivered) {
246            externalRedeliveries.increment();
247        }
248
249        long now = new Date().getTime();
250        if (firstExchangeFailureTimestamp.getUpdateCount() == 0) {
251            firstExchangeFailureTimestamp.updateValue(now);
252        }
253
254        lastExchangeFailureTimestamp.updateValue(now);
255        if (firstExchangeFailureExchangeId == null) {
256            firstExchangeFailureExchangeId = exchange.getExchangeId();
257        }
258        lastExchangeFailureExchangeId = exchange.getExchangeId();
259    }
260
261    public String dumpStatsAsXml(boolean fullStats) {
262        StringBuilder sb = new StringBuilder();
263        sb.append("<stats ");
264        sb.append(String.format("exchangesCompleted=\"%s\"", exchangesCompleted.getValue()));
265        sb.append(String.format(" exchangesFailed=\"%s\"", exchangesFailed.getValue()));
266        sb.append(String.format(" failuresHandled=\"%s\"", failuresHandled.getValue()));
267        sb.append(String.format(" redeliveries=\"%s\"", redeliveries.getValue()));
268        sb.append(String.format(" externalRedeliveries=\"%s\"", externalRedeliveries.getValue()));
269        sb.append(String.format(" minProcessingTime=\"%s\"", minProcessingTime.getValue()));
270        sb.append(String.format(" maxProcessingTime=\"%s\"", maxProcessingTime.getValue()));
271        sb.append(String.format(" totalProcessingTime=\"%s\"", totalProcessingTime.getValue()));
272        sb.append(String.format(" lastProcessingTime=\"%s\"", lastProcessingTime.getValue()));
273        sb.append(String.format(" deltaProcessingTime=\"%s\"", deltaProcessingTime.getValue()));
274        sb.append(String.format(" meanProcessingTime=\"%s\"", meanProcessingTime.getValue()));
275
276        if (fullStats) {
277            sb.append(String.format(" startTimestamp=\"%s\"", dateAsString(startTimestamp.getValue())));
278            sb.append(String.format(" resetTimestamp=\"%s\"", dateAsString(resetTimestamp.getValue())));
279            sb.append(String.format(" firstExchangeCompletedTimestamp=\"%s\"", dateAsString(firstExchangeCompletedTimestamp.getValue())));
280            sb.append(String.format(" firstExchangeCompletedExchangeId=\"%s\"", nullSafe(firstExchangeCompletedExchangeId)));
281            sb.append(String.format(" firstExchangeFailureTimestamp=\"%s\"", dateAsString(firstExchangeFailureTimestamp.getValue())));
282            sb.append(String.format(" firstExchangeFailureExchangeId=\"%s\"", nullSafe(firstExchangeFailureExchangeId)));
283            sb.append(String.format(" lastExchangeCompletedTimestamp=\"%s\"", dateAsString(lastExchangeCompletedTimestamp.getValue())));
284            sb.append(String.format(" lastExchangeCompletedExchangeId=\"%s\"", nullSafe(lastExchangeCompletedExchangeId)));
285            sb.append(String.format(" lastExchangeFailureTimestamp=\"%s\"", dateAsString(lastExchangeFailureTimestamp.getValue())));
286            sb.append(String.format(" lastExchangeFailureExchangeId=\"%s\"", nullSafe(lastExchangeFailureExchangeId)));
287        }
288        sb.append("/>");
289        return sb.toString();
290    }
291
292    private static String dateAsString(long value) {
293        if (value == 0) {
294            return "";
295        }
296        return new SimpleDateFormat(TIMESTAMP_FORMAT).format(value);
297    }
298    
299    private static String nullSafe(String s) {
300        return s != null ? s : "";
301    }
302
303}