Tracer Interceptor
Camel supports a tracer interceptor that is used for logging the route executions at INFO level.
The Tracer is an InterceptStrategy which can be applied to a DefaultCamelContext or SpringCamelContext to ensure that there is a TracerInterceptor created for every node in the DSL.
You can enable or disable the Tracer's logging dynamically, by calling the tracer's setEnabled method.
Options
Trace has been improved in Camel 1.5 to be more configurable with these options:
Option |
Default |
Description |
formatter |
|
Sets the Trace Formatter to use. Will default use org.apache.camel.processor.interceptor.DefaultTraceFormatter. |
enabled |
true |
Flag to enable or disable this tracer |
logLevel |
INFO |
The logging level to use: FATAL, ERROR, WARN, INFO, DEBUG, TRACE |
logName |
|
The log name to use. Will default use org.apache.camel.processor.interceptor.TraceInterceptor. |
traceFilter |
null |
An exchange Predicate to filter the tracing. |
traceInterceptors |
false |
Flag to enable or disable tracing of interceptors |
traceExceptions |
true |
Flag to enable or disable tracing of thrown exception during processing of the exchange |
destination |
null |
Camel 2.0: Optional Destination to route TraceEvent exchange containing TraceEventMessage with details about the trace. Can be used for custom processing to store traces in database using JPA. |
Formatting
The tracer formats the execution of exchanges to log lines. They are logged at INFO level in the log category: org.apache.camel.processor.interceptor.TraceInterceptor.
The tracer uses by default TraceFormatter to format the log line.
TraceFormatter has the following options:
Option |
Default |
Description |
breadCrumbLength |
0 |
Camel 1.5.1: Fixed length of the bread crumb. 0 = no fixed length. Setting a value to e.g. 80 allows the tracer logs to be aligned for easier reading. |
nodeLength |
0 |
Camel 2.0: Fixed length of the node. 0 = no fixed length. Setting a value to e.g. 40 allows the tracer logs to be aligned for easier reading. |
showBreadCrumb |
true |
Outputs the unique unit of work for the exchange. To be used for correlation so you can identify the same exchange. |
showNode |
true |
The destination node. |
showExchangeId |
false |
To output the unique exchange id. Currently the breadcrumb is sufficient. |
showShortExchangeId |
false |
Camel 1.5.1: To output the unique exchange id in short form, without the hostname. |
showProperties |
true |
Output the exchange properties |
showHeaders |
true |
Output the in message headers |
showBodyType |
true |
Output the in body Java type |
showBody |
true |
Output the in body |
showOutBodyType |
false |
Camel 2.0: Output the out body Java type |
showOutBody |
false |
Camel 2.0: Output the out body |
showExchangePattern |
true |
Camel 1.5: Output the exchange pattern |
showException |
true |
Camel 1.5: Output the exception if the exchange has failed |
Example:
ID-claus-acer/4412-1222625653890/2-0 -> to(mock:a) , Pattern:InOnly , Headers:{to=James} , BodyType:String , Body:Hello London
ID-claus-acer/3690-1214458315718/2-0 is the breadcrumb with the unique correlation id.
node3 is the id of the node in the route path. Is always shown.
To[mock:a] is the destination node.
InOnly is the exchange pattern. Is always shown.
Then the rest is properties, headers and the body.
Enabling
To enable tracer from the main run
java org.apache.camel.spring.Main -t
or
java org.apache.camel.spring.Main -trace
and the tracer will be active.
Enabling from Java DSL
The tracer can be enabled by adding it to the interceptor chain to the camel context. This is demonstrated in the unit test below.
Notice: We could have changed the properties on the Tracer object before adding it, if we e.g. don't like the default settings.
public void testSendingSomeMessages() throws Exception {
template.sendBodyAndHeader("direct:start", "Hello London", "to", "James");
template.sendBodyAndHeader("direct:start", "This is Copenhagen calling", "from", "Claus");
}
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
public void configure() throws Exception {
getContext().addInterceptStrategy(new Tracer());
from("direct:start").
process(new Processor() {
public void process(Exchange exchange) throws Exception {
}
@Override
public String toString() {
return "MyProcessor";
}
}).
to("mock:a").
to("mock:b");
}
};
}
Running the test we get the trace information logged at INFO level:
INFO TraceInterceptor - ID-claus-acer/4412-1222625653890/2-0 -> process(MyProcessor) , Pattern:InOnly , Headers:{to=James} , BodyType:String , Body:Hello London
INFO TraceInterceptor - ID-claus-acer/4412-1222625653890/2-0 -> to(mock:a) , Pattern:InOnly , Headers:{to=James} , BodyType:String , Body:Hello London
INFO TraceInterceptor - ID-claus-acer/4412-1222625653890/2-0 -> to(mock:b) , Pattern:InOnly , Headers:{to=James} , BodyType:String , Body:Hello London
INFO TraceInterceptor - ID-claus-acer/4412-1222625653890/2-1 -> process(MyProcessor) , Pattern:InOnly , Headers:{from=Claus} , BodyType:String , Body:This is Copenhagen calling
INFO TraceInterceptor - ID-claus-acer/4412-1222625653890/2-1 -> to(mock:a) , Pattern:InOnly , Headers:{from=Claus} , BodyType:String , Body:This is Copenhagen calling
INFO TraceInterceptor - ID-claus-acer/4412-1222625653890/2-1 -> to(mock:b) , Pattern:InOnly , Headers:{from=Claus} , BodyType:String , Body:This is Copenhagen calling
Configuring from Java DSL
The tracer options can be configured from the Java DSL like this:
public void configure() throws Exception {
Tracer tracer = new Tracer();
tracer.getFormatter().setShowBreadCrumb(false);
tracer.getFormatter().setShowNode(false);
...
getContext().addInterceptStrategy(tracer);
Using predicates to filter exchanges
Available as of Camel 1.5
In the code below we want the tracer only to trace if the body contains the text London. As this is just an example can of course set any Predicate that matches your criteria:
Tracer tracer = new Tracer();
tracer.setLogLevel(LoggingLevel.FATAL);
tracer.setTraceFilter(body().contains(constant("London")));
tracer.getFormatter().setShowExchangePattern(false);
Enabling from Spring XML
There is now a trace attribute you can specify on the *<camelContext/> for example
<camelContext trace="true" xmlns="http:>
...
</camelContext>
You can see this in action with the SpringTraceTest and its spring.xml file
Another option is to just include a spring XML which defines the Tracer bean such as the one that is automatically included if you run the Main with -t above.
Configuration from Spring
In Camel 1.5 you can configure the tracer as a Spring bean. Just add a bean with the bean class org.apache.camel.processor.interceptor.Tracer and Camel will use it as the Tracer.
<bean id="camelTracer" class="org.apache.camel.processor.interceptor.Tracer">
<property name="traceExceptions" value="false"/>
<property name="traceInterceptors" value="true"/>
<property name="logLevel" value="FATAL"/>
<property name="logName" value="com.mycompany.messages"/>
</bean>
<camelContext id="camel" trace="true" xmlns="http://activemq.apache.org/camel/schema/spring">
<route>
<from uri="direct:start"/>
<to uri="mock:result"/>
</route>
</camelContext>
Formatting from Spring
In Camel 1.5 you can configure the formatting of tracer as a Spring bean. Just add a bean with the id traceFormatter and Camel will lookup this id and use the formatter, as the example below illustrates:
<bean id="traceFormatter" class="org.apache.camel.processor.interceptor.TraceFormatter">
<property name="showBody" value="true"/>
<property name="showBodyType" value="false"/>
<property name="showBreadCrumb" value="false"/>
</bean>
<camelContext id="camel" trace="true" xmlns="http://activemq.apache.org/camel/schema/spring">
<route>
<from uri="direct:start"/>
<to uri="mock:result"/>
</route>
</camelContext>
Enable tracing of out messages
Available as of Camel 2.0
You can now trace messages coming out of processing steps. To enable this, configure the tracer as follows
Tracer tracer = new Tracer();
tracer.setTraceOutExchanges(true);
DefaultTraceFormatter formatter = new DefaultTraceFormatter();
formatter.setShowOutBody(true);
formatter.setShowOutBodyType(true);
tracer.setFormatter(formatter);
getContext().addInterceptStrategy(tracer);
or
<bean id="camelTracer" class="org.apache.camel.processor.interceptor.Tracer">
<property name="traceOutExchanges" value="true" />
</bean>
<bean id="traceFormatter" class="org.apache.camel.processor.interceptor.TraceFormatter">
<property name="showOutBody" value="true" />
<property name="showOutBodyType" value="true" />
</bean>
Running with these options, you'll get output similar to:
INFO TraceInterceptor - ID-mojo/59899-1225474989226/2-0 -> transform(body) , Pattern:InOnly , Headers:{to=James} , BodyType:String , Body:Hello London
INFO TraceInterceptor - transform(body) -> ID-mojo/59899-1225474989226/2-0 , Pattern:InOnly , Headers:{to=James} , BodyType:String , Body:Hello London , OutBodyType:String , OutBody:Hello London
Using Custom Formatter
Avaiable as of Camel 2.0
You can now implement your own org.apache.camel.processor.interceptor.TraceFormatter to be used for logging trace messages to the log.
The sample below shows how to configure a Tracer from Java DSL using custom formatter:
Tracer tracer = new Tracer();
MyTraceFormatter formatter = new MyTraceFormatter();
tracer.setFormatter(formatter);
getContext().addInterceptStrategy(tracer);
And here we have our custom logger that implements the TraceFormatter interface where we can construct the log message how we like:
class MyTraceFormatter implements TraceFormatter {
public Object format(TraceInterceptor interceptor, ProcessorType node, Exchange exchange) {
return "***" + exchange.getIn().getBody(String.class) + "***";
}
}
Using Destination for custom processing and routing
Avaiable as of Camel 2.0
Tracer now supports custom processing of trace events. This can be used to route a trace event to a JPA endpoint for persistence in a database.
This works by Camel creates a new TraceEventExchange containing:
- snapshot of the original traced Exchange as a immutable TraceEventMessage containing String values of the fields, when the interception occurred. This ensures the fields contains the exact data at the given time of interception.
- the original Exchange can be accessed using getTracedExchange()
|
Beware to access the original Exchange to avoid causing any side effects or alter its state. Prefer to access the information from TraceEventMessage |
Camel routes the TraceEventExchange synchronously from the point of interception. When its completed Camel will continue routing the original Exchange.
The sample below demonstrates this feature:
Tracer tracer = new Tracer();
tracer.setDestination(context.getEndpoint("direct:traced"));
tracer.setLogLevel(LoggingLevel.OFF);
getContext().addInterceptStrategy(tracer);
Then we can configure a route for the traced messages:
from("direct:traced").process(new MyTraceMessageProcessor()).to("file:
And our processor where we can process the TraceEventMessage. Here we want to create a CSV format of the trace event to be stored as a file. We do this by constructing the CSV String and the replace the IN body with our String instead of the TraceEventMessage.
class MyTraceMessageProcessor implements Processor {
public void process(Exchange exchange) throws Exception {
TraceEventMessage msg = exchange.getIn().getBody(TraceEventMessage.class);
String s = msg.getFromEndpointUri() + ";" + msg.getNode() + ";" + msg.getExchangeId() + ";" + msg.getBody();
exchange.getIn().setBody(s);
}
}
See Also