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; 018 019import org.apache.camel.AsyncCallback; 020import org.apache.camel.Exchange; 021import org.apache.camel.Ordered; 022import org.apache.camel.Processor; 023import org.apache.camel.api.management.PerformanceCounter; 024import org.apache.camel.management.mbean.ManagedPerformanceCounter; 025import org.apache.camel.processor.CamelInternalProcessorAdvice; 026import org.apache.camel.processor.DelegateAsyncProcessor; 027import org.apache.camel.util.StopWatch; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031/** 032 * JMX enabled processor or advice that uses the {@link org.apache.camel.management.mbean.ManagedCounter} for instrumenting 033 * processing of exchanges. 034 * <p/> 035 * This implementation has been optimised to work in dual mode, either as an advice or as a processor. 036 * The former is faster and the latter is required when the error handler has been configured with redelivery enabled. 037 * 038 * @version 039 */ 040public class InstrumentationProcessor extends DelegateAsyncProcessor implements CamelInternalProcessorAdvice<StopWatch>, Ordered { 041 042 private static final Logger LOG = LoggerFactory.getLogger(InstrumentationProcessor.class); 043 private PerformanceCounter counter; 044 private String type; 045 046 public InstrumentationProcessor(String type, Processor processor) { 047 super(processor); 048 this.type = type; 049 } 050 051 public void setCounter(Object counter) { 052 ManagedPerformanceCounter mpc = null; 053 if (counter instanceof ManagedPerformanceCounter) { 054 mpc = (ManagedPerformanceCounter) counter; 055 } 056 057 if (this.counter instanceof DelegatePerformanceCounter) { 058 ((DelegatePerformanceCounter) this.counter).setCounter(mpc); 059 } else if (mpc != null) { 060 this.counter = mpc; 061 } else if (counter instanceof PerformanceCounter) { 062 this.counter = (PerformanceCounter) counter; 063 } 064 } 065 066 @Override 067 public boolean process(final Exchange exchange, final AsyncCallback callback) { 068 // only record time if stats is enabled 069 final StopWatch watch = (counter != null && counter.isStatisticsEnabled()) ? new StopWatch() : null; 070 071 // mark beginning to process the exchange 072 if (watch != null) { 073 beginTime(exchange); 074 } 075 076 return processor.process(exchange, new AsyncCallback() { 077 public void done(boolean doneSync) { 078 try { 079 // record end time 080 if (watch != null) { 081 recordTime(exchange, watch.taken()); 082 } 083 } finally { 084 // and let the original callback know we are done as well 085 callback.done(doneSync); 086 } 087 } 088 089 @Override 090 public String toString() { 091 return InstrumentationProcessor.this.toString(); 092 } 093 }); 094 } 095 096 protected void beginTime(Exchange exchange) { 097 counter.processExchange(exchange); 098 } 099 100 protected void recordTime(Exchange exchange, long duration) { 101 if (LOG.isTraceEnabled()) { 102 LOG.trace("{}Recording duration: {} millis for exchange: {}", new Object[]{type != null ? type + ": " : "", duration, exchange}); 103 } 104 105 if (!exchange.isFailed() && exchange.getException() == null) { 106 counter.completedExchange(exchange, duration); 107 } else { 108 counter.failedExchange(exchange); 109 } 110 } 111 112 public String getType() { 113 return type; 114 } 115 116 public void setType(String type) { 117 this.type = type; 118 } 119 120 @Override 121 public StopWatch before(Exchange exchange) throws Exception { 122 // only record time if stats is enabled 123 StopWatch answer = counter != null && counter.isStatisticsEnabled() ? new StopWatch() : null; 124 if (answer != null) { 125 beginTime(exchange); 126 } 127 return answer; 128 } 129 130 @Override 131 public void after(Exchange exchange, StopWatch watch) throws Exception { 132 // record end time 133 if (watch != null) { 134 recordTime(exchange, watch.taken()); 135 } 136 } 137 138 @Override 139 public String toString() { 140 return "InstrumentProcessorAdvice"; 141 } 142 143 @Override 144 public int getOrder() { 145 // we want instrumentation before calling the processor (but before tracer/debugger) 146 return Ordered.LOWEST - 2; 147 } 148}