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.
Tip | ||
---|---|---|
| ||
Checkout which dependencies are required by Camel for logging purpose. |
From Camel 2.12 onwards you must explicit enable tracing on CamelContext to use it. In XML DSL you do this by setting <camelContext trace="true" ...>
and in Java you do camelContext.setTracing(true)
.
Options
Div | |||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| |||||||||||||||||||||||||||||||||||||||||||||
|
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 the org.apache.camel.processor.interceptor.DefaultTraceFormatter
to format the log line.
DefaultTraceFormatter
has the following options:
Div | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Tip | ||
---|---|---|
| ||
Camel Tracer will by default not log stream or files bodies from Camel 2.8 onwards. You can force Camel to log those by setting the property on the CamelContext properties
|
Example:
Code Block |
---|
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.
Showing from and to
The trace log will output both the from and to so you can see where the Exchange came from, such as:
Code Block |
---|
>>> direct:start --> process(MyProcessor) >>> process(MyProcessor) --> to(mock:a) >>> to(mock:a) --> to(mock:b) |
Enabling
To enable tracer from the main run
Code Block |
---|
java org.apache.camel.spring.Main -t |
or
Code Block |
---|
java org.apache.camel.spring.Main -trace |
and the tracer will be active.
Enabling from Java DSL
Code Block |
---|
context.setTracing(true); |
You can configure tracing at a higher granularity as you can configure it on camel context and then override and set it per route as well. For instance you could just enable tracer for one particular route.
Code Block |
---|
INFO TraceInterceptor - ID-davsclaus-local-54403-1246038742624-0-0 >>> from(direct:start) --> MyProcessor , Pattern:InOnly, Headers:{to=James}, BodyType:String, Body:Hello London INFO TraceInterceptor - ID-davsclaus-local-54403-1246038742624-0-0 >>> MyProcessor --> mock:a , Pattern:InOnly, Headers:{to=James}, BodyType:String, Body:Hello London INFO TraceInterceptor - ID-davsclaus-local-54403-1246038742624-0-0 >>> mock:a --> mock:b , Pattern:InOnly, Headers:{to=James}, BodyType:String, Body:Hello London ... INFO TraceInterceptor - ID-davsclaus-local-54403-1246038742624-0-1 >>> from(direct:start) --> MyProcessor , Pattern:InOnly, Headers:{from=Claus}, BodyType:String, Body:This is Copenhagen calling INFO TraceInterceptor - ID-davsclaus-local-54403-1246038742624-0-1 >>> MyProcessor --> mock:a , Pattern:InOnly, Headers:{from=Claus}, BodyType:String, Body:This is Copenhagen calling INFO TraceInterceptor - ID-davsclaus-local-54403-1246038742624-0-1 >>> mock:a --> 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:
Code Block |
---|
public void configure() throws Exception { // add tracer as an interceptor so it will log the exchange executions at runtime // this can aid us to understand/see how the exchanges is routed etc. Tracer tracer = new Tracer(); formatter.getDefaultTraceFormatter().setShowBreadCrumb(false); formatter.getDefaultTraceFormatter().setShowNode(false); ... getContext().addInterceptStrategy(tracer); |
Using predicates to filter exchanges
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:
Code Block | ||||
---|---|---|---|---|
| ||||
Tracer tracer = new Tracer(); // set the level to FATAL so we can easily spot it tracer.setLogLevel(LoggingLevel.FATAL); // and only trace if the body contains London as text tracer.setTraceFilter(body().contains(constant("London"))); |
Enabling from Spring XML
There is now a trace attribute you can specify on the *<camelContext/> for example
Code Block |
---|
<camelContext trace="true" xmlns="http://activemq.apache.org/camel/schema/spring"> ... </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
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.
Wiki Markup |
---|
{snippet:id=e1|lang=xml|url=camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/interceptor/tracerConfigurationTest.xml} |
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:
Wiki Markup |
---|
{snippet:id=e1|lang=xml|url=camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/interceptor/traceFormatterTest.xml} |
Enable tracing of out messages
You can trace messages coming out of processing steps. To enable this, configure the tracer as follows
Wiki Markup |
---|
{snippet:id=tracingOutExchanges|title=Java DSL|lang=java|url=camel/trunk/camel-core/src/test/java/org/apache/camel/processor/TraceInterceptorWithOutBodyTraceTest.java} |
or
Wiki Markup |
---|
{snippet:id=tracingOutExchanges|title=Spring DSL|lang=xml|url=camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/traceInterceptorWithOutBodyTrace.xml} |
Running with these options, you'll get output similar to:
Code Block |
---|
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
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:
Wiki Markup |
---|
{snippet:id=e1|lang=java|url=camel/trunk/camel-core/src/test/java/org/apache/camel/processor/interceptor/TraceFormatterTest.java} |
And here we have our custom logger that implements the TraceFormatter
interface where we can construct the log message how we like:
Wiki Markup |
---|
{snippet:id=e2|lang=java|url=camel/trunk/camel-core/src/test/java/org/apache/camel/processor/interceptor/TraceFormatterTest.java} |
Using Destination for custom processing and routing
Tracer 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 TraceEventMessage 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 in some implementations be accessed using
getTracedExchange()
(though with JPA based tracer you cannot get the original Exchange).
Warning |
---|
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 TraceEventMessage synchronously from the point of interception. When its completed Camel will continue routing the original Exchange.
The sample below demonstrates this feature, where we route traced Exchanges to the direct:traced
route:
Wiki Markup |
---|
{snippet:id=e1|lang=java|url=camel/trunk/camel-core/src/test/java/org/apache/camel/processor/interceptor/TraceInterceptorDestinationTest.java} |
Then we can configure a route for the traced messages:
Code Block |
---|
from("direct:traced").process(new MyTraceMessageProcessor()).to("file://myapp/logs/trace); |
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
.
Wiki Markup |
---|
{snippet:id=e2|lang=java|url=camel/trunk/camel-core/src/test/java/org/apache/camel/processor/interceptor/TraceInterceptorDestinationTest.java} |
Using JPA as datastore for trace messages
See Tracer Example for complete documentation and how to use this feature.
Traced route path during runtime
Tracer also traces the actual route path taken during runtime. Camel will store the route path taken on the UnitOfWork when Tracer is enabled.
The example below demonstrates how we can use that for error handling where we can determine at which node in the route graph the error triggered.
First we define our route:
Wiki Markup |
---|
{snippet:id=e1|lang=java|url=camel/trunk/camel-core/src/test/java/org/apache/camel/processor/TraceableUnitOfWorkTest.java} |
And then our custom error processor where we can handle the exception and figure out at which node the exception occurred.
Wiki Markup |
---|
{snippet:id=e2|lang=java|url=camel/trunk/camel-core/src/test/java/org/apache/camel/processor/TraceableUnitOfWorkTest.java} |