All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.camel.processor.interceptor.Tracer Maven / Gradle / Ivy

There is a newer version: 4.6.0
Show newest version
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.camel.processor.interceptor;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import org.apache.camel.CamelContext;
import org.apache.camel.Endpoint;
import org.apache.camel.LoggingLevel;
import org.apache.camel.Predicate;
import org.apache.camel.Processor;
import org.apache.camel.Service;
import org.apache.camel.model.ProcessorDefinition;
import org.apache.camel.model.RouteDefinitionHelper;
import org.apache.camel.processor.CamelLogProcessor;
import org.apache.camel.spi.ExchangeFormatter;
import org.apache.camel.spi.InterceptStrategy;
import org.apache.camel.util.CamelLogger;

/**
 * An interceptor strategy for tracing routes
 *
 * @version 
 */
public class Tracer implements InterceptStrategy, Service {
    private static final String JPA_TRACE_EVENT_MESSAGE = "org.apache.camel.processor.interceptor.jpa.JpaTraceEventMessage";

    private TraceFormatter formatter = new DefaultTraceFormatter();
    private boolean enabled = true;
    private String logName = Tracer.class.getName();
    private LoggingLevel logLevel = LoggingLevel.INFO;
    private Predicate traceFilter;
    private boolean traceInterceptors;
    private boolean traceExceptions = true;
    private boolean logStackTrace;
    private boolean traceOutExchanges;
    private String destinationUri;
    private Endpoint destination;
    private boolean useJpa;
    private CamelLogProcessor logger;
    private TraceInterceptorFactory traceInterceptorFactory = new DefaultTraceInterceptorFactory();
    private final List traceHandlers = new CopyOnWriteArrayList();
    private String jpaTraceEventMessageClassName = JPA_TRACE_EVENT_MESSAGE;
    private boolean jmxTraceNotifications;
    private int traceBodySize = 10000;
    
    public Tracer() {
        traceHandlers.add(new DefaultTraceEventHandler(this));
    }

    /**
     * Creates a new tracer.
     *
     * @param context Camel context
     * @return a new tracer
     */
    public static Tracer createTracer(CamelContext context) {
        Tracer tracer = new Tracer();
        // lets see if we have a formatter if so use it
        TraceFormatter formatter = context.getRegistry().lookupByNameAndType("traceFormatter", TraceFormatter.class);
        if (formatter != null) {
            tracer.setFormatter(formatter);
        }
        return tracer;
    }

    /**
     * A helper method to return the Tracer instance if one is enabled
     *
     * @return the tracer or null if none can be found
     */
    public static Tracer getTracer(CamelContext context) {
        List list = context.getInterceptStrategies();
        for (InterceptStrategy interceptStrategy : list) {
            if (interceptStrategy instanceof Tracer) {
                return (Tracer) interceptStrategy;
            }
        }
        return null;
    }

    /**
     * Gets the logger to be used for tracers that can format and log a given exchange.
     *
     * @param formatter the exchange formatter
     * @return the logger to use
     */
    public synchronized CamelLogProcessor getLogger(ExchangeFormatter formatter) {
        if (logger == null) {
            logger = new CamelLogProcessor(new CamelLogger(getLogName(), getLogLevel()), formatter);
        }
        return logger;
    }

    public Processor wrapProcessorInInterceptors(CamelContext context, ProcessorDefinition definition,
                                                 Processor target, Processor nextTarget) throws Exception {
        // Force the creation of an id, otherwise the id is not available when the trace formatter is
        // outputting trace information
        RouteDefinitionHelper.forceAssignIds(context, definition);
        return getTraceInterceptorFactory().createTraceInterceptor(definition, target, formatter, this);
    }

    public TraceFormatter getFormatter() {
        return formatter;
    }

    public DefaultTraceFormatter getDefaultTraceFormatter() {
        if (formatter instanceof DefaultTraceFormatter) {
            return (DefaultTraceFormatter) formatter;
        }
        return null;
    }

    public void setFormatter(TraceFormatter formatter) {
        this.formatter = formatter;
    }

    public void setEnabled(boolean flag) {
        enabled = flag;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public boolean isTraceInterceptors() {
        return traceInterceptors;
    }

    /**
     * Sets whether interceptors should be traced or not
     */
    public void setTraceInterceptors(boolean traceInterceptors) {
        this.traceInterceptors = traceInterceptors;
    }

    public Predicate getTraceFilter() {
        return traceFilter;
    }

    /**
     * Sets a predicate to be used as filter when tracing
     */
    public void setTraceFilter(Predicate traceFilter) {
        this.traceFilter = traceFilter;
    }

    public LoggingLevel getLogLevel() {
        return logLevel;
    }

    /**
     * Sets the logging level to output tracing. Will use INFO level by default.
     */
    public void setLogLevel(LoggingLevel logLevel) {
        this.logLevel = logLevel;
        // update logger if its in use
        if (logger != null) {
            logger.getLogger().setLevel(logLevel);
        }
    }

    public boolean isTraceExceptions() {
        return traceExceptions;
    }

    /**
     * Sets whether thrown exceptions should be traced
     */
    public void setTraceExceptions(boolean traceExceptions) {
        this.traceExceptions = traceExceptions;
    }

    public boolean isLogStackTrace() {
        return logStackTrace;
    }

    /**
     * Sets whether thrown exception stacktrace should be traced, if disabled then only the exception message is logged
     */
    public void setLogStackTrace(boolean logStackTrace) {
        this.logStackTrace = logStackTrace;
    }

    public String getLogName() {
        return logName;
    }

    /**
     * Sets the logging name to use.
     * Will default use org.apache.camel.processor.interceptor.TraceInterceptor.
     */
    public void setLogName(String logName) {
        this.logName = logName;
        // update logger if its in use
        if (logger != null) {
            logger.getLogger().setLogName(logName);
        }
    }

    /**
     * Sets whether exchanges coming out of processors should be traced
     */
    public void setTraceOutExchanges(boolean traceOutExchanges) {
        this.traceOutExchanges = traceOutExchanges;
    }

    public boolean isTraceOutExchanges() {
        return traceOutExchanges;
    }

    public String getDestinationUri() {
        return destinationUri;
    }

    /**
     * Sets an optional destination to send the traced Exchange.
     * 

* Can be used to store tracing as files, in a database or whatever. The routing of the Exchange * will happen synchronously and the original route will first continue when this destination routing * has been completed. */ public void setDestinationUri(String destinationUri) { this.destinationUri = destinationUri; } public Endpoint getDestination() { return destination; } /** * See {@link #setDestinationUri(String)} */ public void setDestination(Endpoint destination) { this.destination = destination; } public boolean isUseJpa() { return useJpa; } /** * Sets whether we should use a JpaTraceEventMessage instead of * an ordinary {@link org.apache.camel.processor.interceptor.DefaultTraceEventMessage} *

* Use this to allow persistence of trace events into a database using JPA. * This requires camel-jpa in the classpath. */ public void setUseJpa(boolean useJpa) { this.useJpa = useJpa; } public TraceInterceptorFactory getTraceInterceptorFactory() { return this.traceInterceptorFactory; } /** * Set the factory to be used to create the trace interceptor. * It is expected that the factory will create a subclass of TraceInterceptor. *

* Use this to take complete control of how trace events are handled. * The TraceInterceptorFactory should only be set before any routes are created, hence this * method is not thread safe. */ public void setTraceInterceptorFactory(TraceInterceptorFactory traceInterceptorFactory) { this.traceInterceptorFactory = traceInterceptorFactory; } /** * * @return the first trace event handler */ @Deprecated public TraceEventHandler getTraceHandler() { return traceHandlers.get(0); } /** * * @return list of tracehandlers */ public List getTraceHandlers() { return traceHandlers; } /** * Set the object to be used to perform tracing. *

* Use this to take more control of how trace events are persisted. * Setting the traceHandler provides a simpler mechanism for controlling tracing * than the TraceInterceptorFactory. * The TraceHandler should only be set before any routes are created, hence this * method is not thread safe. */ @Deprecated public void setTraceHandler(TraceEventHandler traceHandler) { this.traceHandlers.clear(); this.traceHandlers.add(traceHandler); } /** * Add the given tracehandler */ public void addTraceHandler(TraceEventHandler traceHandler) { this.traceHandlers.add(traceHandler); } /** * Remove the given tracehandler */ public void removeTraceHandler(TraceEventHandler traceHandler) { this.traceHandlers.remove(traceHandler); } public String getJpaTraceEventMessageClassName() { return jpaTraceEventMessageClassName; } /** * Set the fully qualified name of the class to be used by the JPA event tracing. *

* The class must exist in the classpath and be available for dynamic loading. * The class name should only be set before any routes are created, hence this * method is not thread safe. */ public void setJpaTraceEventMessageClassName(String jpaTraceEventMessageClassName) { this.jpaTraceEventMessageClassName = jpaTraceEventMessageClassName; } public boolean isJmxTraceNotifications() { return jmxTraceNotifications; } public void setJmxTraceNotifications(boolean jmxTraceNotifications) { this.jmxTraceNotifications = jmxTraceNotifications; } public int getTraceBodySize() { return traceBodySize; } public void setTraceBodySize(int traceBodySize) { this.traceBodySize = traceBodySize; } public void start() throws Exception { // noop } public void stop() throws Exception { traceHandlers.clear(); } @Override public String toString() { return "Tracer"; } }