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