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 */
017 package org.apache.camel.processor.interceptor;
018
019 import java.util.List;
020
021 import org.apache.camel.CamelContext;
022 import org.apache.camel.Endpoint;
023 import org.apache.camel.LoggingLevel;
024 import org.apache.camel.Predicate;
025 import org.apache.camel.Processor;
026 import org.apache.camel.Service;
027 import org.apache.camel.model.ProcessorDefinition;
028 import org.apache.camel.processor.Logger;
029 import org.apache.camel.spi.ExchangeFormatter;
030 import org.apache.camel.spi.InterceptStrategy;
031 import org.apache.commons.logging.LogFactory;
032
033 /**
034 * An interceptor strategy for tracing routes
035 *
036 * @version $Revision: 836213 $
037 */
038 public class Tracer implements InterceptStrategy, Service {
039
040 private TraceFormatter formatter = new DefaultTraceFormatter();
041 private boolean enabled = true;
042 private String logName = Tracer.class.getName();
043 private LoggingLevel logLevel = LoggingLevel.INFO;
044 private Predicate traceFilter;
045 private boolean traceInterceptors;
046 private boolean traceExceptions = true;
047 private boolean logStackTrace;
048 private boolean traceOutExchanges;
049 private String destinationUri;
050 private Endpoint destination;
051 private boolean useJpa;
052 private Logger logger;
053
054 /**
055 * Creates a new tracer.
056 *
057 * @param context Camel context
058 * @return a new tracer
059 */
060 public static Tracer createTracer(CamelContext context) {
061 Tracer tracer = new Tracer();
062 // lets see if we have a formatter if so use it
063 TraceFormatter formatter = context.getRegistry().lookup("traceFormatter", TraceFormatter.class);
064 if (formatter != null) {
065 tracer.setFormatter(formatter);
066 }
067 return tracer;
068 }
069
070 /**
071 * A helper method to return the Tracer instance if one is enabled
072 *
073 * @return the tracer or null if none can be found
074 */
075 public static Tracer getTracer(CamelContext context) {
076 List<InterceptStrategy> list = context.getInterceptStrategies();
077 for (InterceptStrategy interceptStrategy : list) {
078 if (interceptStrategy instanceof Tracer) {
079 return (Tracer)interceptStrategy;
080 }
081 }
082 return null;
083 }
084
085 /**
086 * Gets the logger to be used for tracers that can format and log a given exchange.
087 *
088 * @param formatter the exchange formatter
089 * @return the logger to use
090 */
091 public synchronized Logger getLogger(ExchangeFormatter formatter) {
092 if (logger == null) {
093 logger = new Logger(LogFactory.getLog(getLogName()), formatter);
094 logger.setLevel(getLogLevel());
095 }
096 return logger;
097 }
098
099 public Processor wrapProcessorInInterceptors(CamelContext context, ProcessorDefinition<?> definition,
100 Processor target, Processor nextTarget) throws Exception {
101
102 // Force the creation of an id, otherwise the id is not available when the trace formatter is
103 // outputting trace information
104 definition.idOrCreate(context.getNodeIdFactory());
105 return new TraceInterceptor(definition, target, formatter, this);
106 }
107
108 public TraceFormatter getFormatter() {
109 return formatter;
110 }
111
112 public DefaultTraceFormatter getDefaultTraceFormatter() {
113 if (formatter instanceof DefaultTraceFormatter) {
114 return (DefaultTraceFormatter) formatter;
115 }
116 return null;
117 }
118
119 public void setFormatter(TraceFormatter formatter) {
120 this.formatter = formatter;
121 }
122
123 public void setEnabled(boolean flag) {
124 enabled = flag;
125 }
126
127 public boolean isEnabled() {
128 return enabled;
129 }
130
131 public boolean isTraceInterceptors() {
132 return traceInterceptors;
133 }
134
135 /**
136 * Sets whether interceptors should be traced or not
137 */
138 public void setTraceInterceptors(boolean traceInterceptors) {
139 this.traceInterceptors = traceInterceptors;
140 }
141
142 public Predicate getTraceFilter() {
143 return traceFilter;
144 }
145
146 /**
147 * Sets a predicate to be used as filter when tracing
148 */
149 public void setTraceFilter(Predicate traceFilter) {
150 this.traceFilter = traceFilter;
151 }
152
153 public LoggingLevel getLogLevel() {
154 return logLevel;
155 }
156
157 /**
158 * Sets the logging level to output tracing. Will use <tt>INFO</tt> level by default.
159 */
160 public void setLogLevel(LoggingLevel logLevel) {
161 this.logLevel = logLevel;
162 // update logger if its in use
163 if (logger != null) {
164 logger.setLevel(logLevel);
165 }
166 }
167
168 public boolean isTraceExceptions() {
169 return traceExceptions;
170 }
171
172 /**
173 * Sets whether thrown exceptions should be traced
174 */
175 public void setTraceExceptions(boolean traceExceptions) {
176 this.traceExceptions = traceExceptions;
177 }
178
179 public boolean isLogStackTrace() {
180 return logStackTrace;
181 }
182
183 /**
184 * Sets whether thrown exception stacktrace should be traced, if disabled then only the exception message is logged
185 */
186 public void setLogStackTrace(boolean logStackTrace) {
187 this.logStackTrace = logStackTrace;
188 }
189
190 public String getLogName() {
191 return logName;
192 }
193
194 /**
195 * Sets the logging name to use.
196 * Will default use <tt>org.apache.camel.processor.interceptor.TraceInterceptor<tt>.
197 */
198 public void setLogName(String logName) {
199 this.logName = logName;
200 // update logger if its in use
201 if (logger != null) {
202 logger.setLogName(logName);
203 }
204 }
205
206 /**
207 * Sets whether exchanges coming out of processors should be traced
208 */
209 public void setTraceOutExchanges(boolean traceOutExchanges) {
210 this.traceOutExchanges = traceOutExchanges;
211 }
212
213 public boolean isTraceOutExchanges() {
214 return traceOutExchanges;
215 }
216
217 public String getDestinationUri() {
218 return destinationUri;
219 }
220
221 /**
222 * Sets an optional destination to send the traced Exchange.
223 * <p/>
224 * Can be used to store tracing as files, in a database or whatever. The routing of the Exchange
225 * will happen synchronously and the original route will first continue when this destination routing
226 * has been completed.
227 */
228 public void setDestinationUri(String destinationUri) {
229 this.destinationUri = destinationUri;
230 }
231
232 public Endpoint getDestination() {
233 return destination;
234 }
235
236 /**
237 * See {@link #setDestinationUri(String)}
238 */
239 public void setDestination(Endpoint destination) {
240 this.destination = destination;
241 }
242
243 public boolean isUseJpa() {
244 return useJpa;
245 }
246
247 /**
248 * Sets whether we should use a JpaTraceEventMessage instead of
249 * an ordinary {@link org.apache.camel.processor.interceptor.DefaultTraceEventMessage}
250 * <p/>
251 * Use this to allow persistence of trace events into a database using JPA.
252 * This requires camel-jpa in the classpath.
253 */
254 public void setUseJpa(boolean useJpa) {
255 this.useJpa = useJpa;
256 }
257
258 @Override
259 public String toString() {
260 return "Tracer";
261 }
262
263 public void start() throws Exception {
264 }
265
266 public void stop() throws Exception {
267 }
268 }