Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

Logging is essential in software development as it aids in recording every footprint of an application. It helps with tracking the activities and state of an application. Essentially, it’s useful for debugging purposes.

Apache Camel provides a component, interface, and interceptor to log messages and exchanges. It simplifies logging by providing a layer of abstraction over various logging frameworks.

In this tutorial, we’ll look at four ways to log messages and exchanges in a Camel application.

2. Using Log EIP

Apache Camel 2.2 provides a lightweight log() DSL to log human-readable messages from a route. Its major use case is to output a message to the log console quickly. Also, we can use it with Camel Simple expression language to further log details from a route to the log console.

Let’s see an example that copies a file from one folder to another:

class FileCopierCamelRoute extends RouteBuilder {
    void configure() {
        from("file:data/inbox?noop=true")
          .log("We got an incoming file ${file:name} containing: ${body}")
          .to("file:data/outbox")
          .log("Successfully transfer file: ${file:name}");
    }
}

In the code above, we configure a RouteBuilder that transfers files from the inbox to the outbox folder. First, we define the location of the incoming file. Next, we use the log() DSL to output a human-readable log on the incoming file and its content. Also, we use Simple expression language to get the file name and the content of the file as part of the log message.

Here’s the log output:

14:39:23.389 [Camel (camel-1) thread #1 - file://data/inbox] INFO  route1 - We got an incoming file welcome.txt containing: Welcome to Baeldung
14:39:23.423 [Camel (camel-1) thread #1 - file://data/inbox] INFO  route1 - Successlly transfer file: welcome.txt

The log() DSL is lightweight compared to the Log component and Tracer interceptor.

Furthermore, we can explicitly specify the log level and name:

// ...
.log(LoggingLevel.DEBUG,"Output Process","The Process ${id}")
// ...

Here, we indicate the log level and name before passing the log message. We also have the WARN, TRACE, and OFF options as log levels. When the debug level is not specified, the log() DSL uses INFO.

3. Using the Processor Interface

The Processor is an important interface in Apache Camel that gives access to exchange for further manipulation. It gives us the flexibility to alter the exchange body. However, we can also use it to output human-readable log messages.

Primarily, the Processor is not a logging tool. Therefore, we need to create a Logger instance to use it with. Apache Camel uses the SLF4J library by default. Let’s create a Logger instance:

private static final Logger LOGGER = LoggerFactory.getLogger(FileCopierCamelRoute.class);

Next, let’s see an example that passes a message to a bean for further manipulation:

void configure() {
    from("file:data/inbox?noop=true")
     .to("log:com.baeldung.apachecamellogging?level=INFO")
     .process(process -> {
         LOGGER.info("We are passing the message to a FileProcesor bean to capitalize the message body");
     })
     .bean(FileProcessor.class)
     .to("file:data/outbox")
}

Here, we pass the incoming message to the FileProcessor bean to convert the file content to uppercase. However, we log a piece of information before the message is passed to the bean for process by creating an instance of the Processor.

Finally, let’s see the log output:

14:50:47.048 [Camel (camel-1) thread #1 - file://data/inbox] INFO  c.b.a.FileCopierCamelRoute - We are passing the message to a FileProcesor to Capitalize the message body

From the output above, the custom log message is output to the console.

4. Using Log Component

Apache Camel provides a Log component that helps log Camel Message to a console output. To use the Log component, we can route messages to it:

void configure() {
    from("file:data/inbox?noop=true")
      .to("log:com.baeldung.apachecamellogging?level=INFO")
      .bean(FileProcessor.class)
      .to("file:data/outbox")
      .to("log:com.baeldung.apachecamellogging")
}

Here, we use the Log component in two places. First, we log the message body at the INFO logging level by using the level option. Also, we log the message body after manipulating the file but we didn’t specify the logging level.

Notably, in a case where the logging level is not specified, the Log component uses the INFO level as the default.

Here’s the log output:

09:36:32.432 [Camel (camel-1) thread #1 - file://data/inbox] INFO  com.baeldung.apachecamellogging - Exchange[ExchangePattern: InOnly, BodyType: org.apache.camel.component.file.GenericFile, Body: [Body is file based: GenericFile[welcome.txt]]]
09:36:32.454 [Camel (camel-1) thread #1 - file://data/inbox] INFO  com.baeldung.apachecamellogging - Exchange[ExchangePattern: InOnly, BodyType: String, Body: WELCOME TO BAELDUNG]

Also, we can make the output less verbose by adding showBodyType and maxChars option:

.to("log:com.baeldung.apachecamellogging?showBodyType=false&maxChars=20")

In the code above, we ignore the message body time and streamline the body characters to 20.

5. Using Tracer

Tracer is part of Apache Camel architecture that helps log how messages are routed during runtime. It keeps track of exchange snapshots during the process of routing. It can intercept message movement from one node to another.

To use a Tracer, we have to enable it in the route configuration method:

getContext().setTracing(true);

This enables the Tracer interceptor to intercept all exchange processes and log them to the log console.

Let’s see an example code that enables Tracer to keep track of the exchange process:

void configure() {
    getContext().setTracing(true);
    from("file:data/json?noop=true")
      .unmarshal().json(JsonLibrary.Jackson)
      .bean(FileProcessor.class, "transform")
      .marshal().json(JsonLibrary.Jackson)
      .to("file:data/output");
}

In the code above, we copy a JSON file from a source and convert it to a data structure that Camel can manipulate. We pass the content to a bean to alter the file content. Next, we convert the message to JSON and send it to the intended destination.

Here’s the log from the Tracer interceptor:

// ...
09:23:10.767 [Camel (camel-1) thread #1 - file://data/json] INFO  FileCopierTracerCamelRoute:14 - *--> [route1      ] [from[file:data/json?noop=true]   ]
09:23:10.768 [Camel (camel-1) thread #1 - file://data/json] INFO  FileCopierTracerCamelRoute:14 -      [route1      ] [log:input?level=INFO             ]
// ...

In the output above, the Tracer records every process and exchanges that occur from the producer down to the consumer. This can be useful for debugging.

Notably, the log output is verbose, but for simplicity, we show the essential log message.

6. Conclusion

In this article, we learned four ways to log in to Apache Camel. Additionally, we saw examples that use the log() DSL, Tracer, Processor, and Log component to log messages to the console. The log() DSL and the Processor interface are ideal for human-readable logs, while the Log component and Tracer are suitable for more complex logs used in debugging.

As always, the source code for the examples is available over on GitHub.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.