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.processor.interceptor; 018 019import java.util.List; 020import java.util.concurrent.CopyOnWriteArrayList; 021 022import org.apache.camel.CamelContext; 023import org.apache.camel.Endpoint; 024import org.apache.camel.LoggingLevel; 025import org.apache.camel.Predicate; 026import org.apache.camel.Processor; 027import org.apache.camel.Service; 028import org.apache.camel.model.ProcessorDefinition; 029import org.apache.camel.model.RouteDefinitionHelper; 030import org.apache.camel.processor.CamelLogProcessor; 031import org.apache.camel.spi.ExchangeFormatter; 032import org.apache.camel.spi.InterceptStrategy; 033import org.apache.camel.util.CamelLogger; 034 035/** 036 * An interceptor strategy for tracing routes 037 * 038 * @version 039 */ 040@Deprecated 041public class Tracer implements InterceptStrategy, Service { 042 private static final String JPA_TRACE_EVENT_MESSAGE = "org.apache.camel.processor.interceptor.jpa.JpaTraceEventMessage"; 043 044 private TraceFormatter formatter = new DefaultTraceFormatter(); 045 private boolean enabled = true; 046 private String logName = Tracer.class.getName(); 047 private LoggingLevel logLevel = LoggingLevel.INFO; 048 private Predicate traceFilter; 049 private boolean traceInterceptors; 050 private boolean traceExceptions = true; 051 private boolean logStackTrace; 052 private boolean traceOutExchanges; 053 private String destinationUri; 054 private Endpoint destination; 055 private boolean useJpa; 056 private CamelLogProcessor logger; 057 private TraceInterceptorFactory traceInterceptorFactory = new DefaultTraceInterceptorFactory(); 058 private final List<TraceEventHandler> traceHandlers = new CopyOnWriteArrayList<TraceEventHandler>(); 059 private String jpaTraceEventMessageClassName = JPA_TRACE_EVENT_MESSAGE; 060 private boolean jmxTraceNotifications; 061 private int traceBodySize = 10000; 062 063 public Tracer() { 064 traceHandlers.add(new DefaultTraceEventHandler(this)); 065 } 066 067 /** 068 * Creates a new tracer. 069 * 070 * @param context Camel context 071 * @return a new tracer 072 */ 073 public static Tracer createTracer(CamelContext context) { 074 Tracer tracer = new Tracer(); 075 // lets see if we have a formatter if so use it 076 TraceFormatter formatter = context.getRegistry().lookupByNameAndType("traceFormatter", TraceFormatter.class); 077 if (formatter != null) { 078 tracer.setFormatter(formatter); 079 } 080 return tracer; 081 } 082 083 /** 084 * A helper method to return the Tracer instance if one is enabled 085 * 086 * @return the tracer or null if none can be found 087 */ 088 public static Tracer getTracer(CamelContext context) { 089 List<InterceptStrategy> list = context.getInterceptStrategies(); 090 for (InterceptStrategy interceptStrategy : list) { 091 if (interceptStrategy instanceof Tracer) { 092 return (Tracer) interceptStrategy; 093 } 094 } 095 return null; 096 } 097 098 /** 099 * Gets the logger to be used for tracers that can format and log a given exchange. 100 * 101 * @param formatter the exchange formatter 102 * @return the logger to use 103 */ 104 public synchronized CamelLogProcessor getLogger(ExchangeFormatter formatter) { 105 if (logger == null) { 106 logger = new CamelLogProcessor(new CamelLogger(getLogName(), getLogLevel()), formatter, null, null); 107 } 108 return logger; 109 } 110 111 public Processor wrapProcessorInInterceptors(CamelContext context, ProcessorDefinition<?> definition, 112 Processor target, Processor nextTarget) throws Exception { 113 // Force the creation of an id, otherwise the id is not available when the trace formatter is 114 // outputting trace information 115 RouteDefinitionHelper.forceAssignIds(context, definition); 116 return getTraceInterceptorFactory().createTraceInterceptor(definition, target, formatter, this); 117 } 118 119 public TraceFormatter getFormatter() { 120 return formatter; 121 } 122 123 public DefaultTraceFormatter getDefaultTraceFormatter() { 124 if (formatter instanceof DefaultTraceFormatter) { 125 return (DefaultTraceFormatter) formatter; 126 } 127 return null; 128 } 129 130 public void setFormatter(TraceFormatter formatter) { 131 this.formatter = formatter; 132 } 133 134 public void setEnabled(boolean flag) { 135 enabled = flag; 136 } 137 138 public boolean isEnabled() { 139 return enabled; 140 } 141 142 public boolean isTraceInterceptors() { 143 return traceInterceptors; 144 } 145 146 /** 147 * Sets whether interceptors should be traced or not 148 */ 149 public void setTraceInterceptors(boolean traceInterceptors) { 150 this.traceInterceptors = traceInterceptors; 151 } 152 153 public Predicate getTraceFilter() { 154 return traceFilter; 155 } 156 157 /** 158 * Sets a predicate to be used as filter when tracing 159 */ 160 public void setTraceFilter(Predicate traceFilter) { 161 this.traceFilter = traceFilter; 162 } 163 164 public LoggingLevel getLogLevel() { 165 return logLevel; 166 } 167 168 /** 169 * Sets the logging level to output tracing. Will use <tt>INFO</tt> level by default. 170 */ 171 public void setLogLevel(LoggingLevel logLevel) { 172 this.logLevel = logLevel; 173 // update logger if its in use 174 if (logger != null) { 175 logger.getLogger().setLevel(logLevel); 176 } 177 } 178 179 public boolean isTraceExceptions() { 180 return traceExceptions; 181 } 182 183 /** 184 * Sets whether thrown exceptions should be traced 185 */ 186 public void setTraceExceptions(boolean traceExceptions) { 187 this.traceExceptions = traceExceptions; 188 } 189 190 public boolean isLogStackTrace() { 191 return logStackTrace; 192 } 193 194 /** 195 * Sets whether thrown exception stacktrace should be traced, if disabled then only the exception message is logged 196 */ 197 public void setLogStackTrace(boolean logStackTrace) { 198 this.logStackTrace = logStackTrace; 199 } 200 201 public String getLogName() { 202 return logName; 203 } 204 205 /** 206 * Sets the logging name to use. 207 * Will default use <tt>org.apache.camel.processor.interceptor.TraceInterceptor<tt>. 208 */ 209 public void setLogName(String logName) { 210 this.logName = logName; 211 // update logger if its in use 212 if (logger != null) { 213 logger.getLogger().setLogName(logName); 214 } 215 } 216 217 /** 218 * Sets whether exchanges coming out of processors should be traced 219 */ 220 public void setTraceOutExchanges(boolean traceOutExchanges) { 221 this.traceOutExchanges = traceOutExchanges; 222 } 223 224 public boolean isTraceOutExchanges() { 225 return traceOutExchanges; 226 } 227 228 public String getDestinationUri() { 229 return destinationUri; 230 } 231 232 /** 233 * Sets an optional destination to send the traced Exchange. 234 * <p/> 235 * Can be used to store tracing as files, in a database or whatever. The routing of the Exchange 236 * will happen synchronously and the original route will first continue when this destination routing 237 * has been completed. 238 */ 239 public void setDestinationUri(String destinationUri) { 240 this.destinationUri = destinationUri; 241 } 242 243 public Endpoint getDestination() { 244 return destination; 245 } 246 247 /** 248 * See {@link #setDestinationUri(String)} 249 */ 250 public void setDestination(Endpoint destination) { 251 this.destination = destination; 252 } 253 254 public boolean isUseJpa() { 255 return useJpa; 256 } 257 258 /** 259 * Sets whether we should use a JpaTraceEventMessage instead of 260 * an ordinary {@link org.apache.camel.processor.interceptor.DefaultTraceEventMessage} 261 * <p/> 262 * Use this to allow persistence of trace events into a database using JPA. 263 * This requires camel-jpa in the classpath. 264 */ 265 public void setUseJpa(boolean useJpa) { 266 this.useJpa = useJpa; 267 } 268 269 public TraceInterceptorFactory getTraceInterceptorFactory() { 270 return this.traceInterceptorFactory; 271 } 272 273 /** 274 * Set the factory to be used to create the trace interceptor. 275 * It is expected that the factory will create a subclass of TraceInterceptor. 276 * <p/> 277 * Use this to take complete control of how trace events are handled. 278 * The TraceInterceptorFactory should only be set before any routes are created, hence this 279 * method is not thread safe. 280 */ 281 public void setTraceInterceptorFactory(TraceInterceptorFactory traceInterceptorFactory) { 282 this.traceInterceptorFactory = traceInterceptorFactory; 283 } 284 285 /** 286 * 287 * @return the first trace event handler 288 */ 289 @Deprecated 290 public TraceEventHandler getTraceHandler() { 291 return traceHandlers.get(0); 292 } 293 294 /** 295 * 296 * @return list of tracehandlers 297 */ 298 public List<TraceEventHandler> getTraceHandlers() { 299 return traceHandlers; 300 } 301 302 /** 303 * Set the object to be used to perform tracing. 304 * <p/> 305 * Use this to take more control of how trace events are persisted. 306 * Setting the traceHandler provides a simpler mechanism for controlling tracing 307 * than the TraceInterceptorFactory. 308 * The TraceHandler should only be set before any routes are created, hence this 309 * method is not thread safe. 310 */ 311 @Deprecated 312 public void setTraceHandler(TraceEventHandler traceHandler) { 313 this.traceHandlers.clear(); 314 this.traceHandlers.add(traceHandler); 315 } 316 317 /** 318 * Add the given tracehandler 319 */ 320 public void addTraceHandler(TraceEventHandler traceHandler) { 321 this.traceHandlers.add(traceHandler); 322 } 323 324 /** 325 * Remove the given tracehandler 326 */ 327 public void removeTraceHandler(TraceEventHandler traceHandler) { 328 this.traceHandlers.remove(traceHandler); 329 } 330 331 public String getJpaTraceEventMessageClassName() { 332 return jpaTraceEventMessageClassName; 333 } 334 335 /** 336 * Set the fully qualified name of the class to be used by the JPA event tracing. 337 * <p/> 338 * The class must exist in the classpath and be available for dynamic loading. 339 * The class name should only be set before any routes are created, hence this 340 * method is not thread safe. 341 */ 342 public void setJpaTraceEventMessageClassName(String jpaTraceEventMessageClassName) { 343 this.jpaTraceEventMessageClassName = jpaTraceEventMessageClassName; 344 } 345 346 public boolean isJmxTraceNotifications() { 347 return jmxTraceNotifications; 348 } 349 350 public void setJmxTraceNotifications(boolean jmxTraceNotifications) { 351 this.jmxTraceNotifications = jmxTraceNotifications; 352 } 353 354 public int getTraceBodySize() { 355 return traceBodySize; 356 } 357 358 public void setTraceBodySize(int traceBodySize) { 359 this.traceBodySize = traceBodySize; 360 } 361 362 public void start() throws Exception { 363 // noop 364 } 365 366 public void stop() throws Exception { 367 traceHandlers.clear(); 368 } 369 370 @Override 371 public String toString() { 372 return "Tracer"; 373 } 374}