1

I have implemented different microservice where internal communication is taking place by camel and rabbitMQ with different exchange and queue. I'm using camel-zipkin for tracing, and log4j2 for logging.

Ex:

  • Service1 Publish message to RabbitMQ ( i.e Exchange 1 -> Queue 1) where Service2 Consume message
  • Service2 Publish message to RabbitMQ ( i.e Exchange 1 -> Queue 2) where Service3 Consume message and so on.

I am using Springboot 1.5.12.RELEASE and Camel 2.21.5 version with the following dependencies (of camel):

  • camel-spring-boot-starter
  • camel-rabbitmq-starter
  • camel-core
  • camel-spring
  • camel-zipkin-starter
  • camel-test
  • camel-test-spring

I need suggestion for my two problems

  1. span-id, trace-id are not getting printed in logs. I have necessary placeholders added in my log4j2.xml.
  2. Whenever a message is sent to an exchange a unique span-id and trace-id is getting generated.

My Questions are :

  1. Is it possible to have a unique traceID for entire data traverse from Service 1 to Service N.
  2. How can I print span-id, trace-id to logs.

Sample Code :

Pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.12.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.camel</groupId>
    <artifactId>example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>example</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <camel.version>2.21.5</camel.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

        <!-- Camel Dependency -->
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-spring-boot-starter</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-rabbitmq-starter</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-core</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-spring</artifactId>
            <version>${camel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-zipkin-starter</artifactId>
            <version>${camel.version}</version>
        </dependency>


        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-test</artifactId>
            <version>${camel.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-test-spring</artifactId>
            <version>${camel.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

SpringBoot Application

@SpringBootApplication
@CamelZipkin
public class ExampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(ExampleApplication.class, args);
    }

}

RabbitMQConfig



@EnableRabbit
@Profile("default")
@Configuration
public class RabbitMQConfig {

    @Value("${camel.component.rabbitmq.hostname}")
    private String host;

    @Value("${camel.component.rabbitmq.port-number:5672}")
    private int port;

    @Value("${camel.component.rabbitmq.username}")
    private String username;

    @Value("${camel.component.rabbitmq.password}")
    private String password;

    @Value("${camel.component.rabbitmq.vhost}")
    private String virtualHost;


    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host, port);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost(virtualHost);
        connectionFactory.setCacheMode(CacheMode.CONNECTION);

        return connectionFactory;
    }

    @Bean
    public Channel amqpChannel(ConnectionFactory connectionFactory) throws IOException {
        Connection connection = connectionFactory.createConnection();
        Channel channel = connection.createChannel(false);
        Map<String, Object> args = new HashMap<>();
        args.put("x-delayed-type", "direct");
        channel.exchangeDeclare("example-service", "x-delayed-message", true, false, args);

        return channel;
    }
}

Controller adding message to queue

@RestController
public class MessageController {

    private static final Logger log = LoggerFactory.getLogger(MessageController.class);

    @Autowired
    protected ProducerTemplate producer;

    @PostMapping(value = "send/message")
    public void sendMessageTopic(@RequestBody MessageDto message) {
        log.debug("In controller sending message ");
        producer.requestBody("rabbitmq:example-service?routingKey=example-service.ers.send&queue=example-service-ers-send", message);


    }

}

RouteBuilder


@Component
public class AppRouteBuilder extends RouteBuilder {

    @Autowired
    private MessageActivity messageActivity;

    @Autowired
    private SmsActivity smsActivity;

    @Override
    public void configure() throws Exception {
        // TODO Auto-generated method stub

        from("rabbitmq:example-service?routingKey=example-service.ers.send&queue=example-service-ers-send")
                .bean(messageActivity).end();

        from("rabbitmq:example-service?routingKey=example-service.sms.send&queue=example-service-sms-send")
                .bean(smsActivity).end();
    }

}

MessageActivity

@Service
public class MessageActivity {

    private static final Logger log = LoggerFactory.getLogger(MessageActivity.class);

    @Autowired
    protected ProducerTemplate producer;

    public void doAction() {

        log.debug("Hello in message activity ");

        producer.requestBody("rabbitmq:example-service?routingKey=example-service.sms.send&queue=example-service-sms-send", "Hello from message");

    }
}

SmsActivity

@Service
public class SmsActivity {

    private static final Logger log = LoggerFactory.getLogger(SmsActivity.class);

    public void doAction() {

        log.debug("Hello in sms activity ");
    }
}

Output

2019-12-03T21:07:54.316+07:00|2|INFO|example-service|,,|50382|http-nio-8080-exec-2|o.a.c.c.C.[.[.[/]|Initializing Spring FrameworkServlet 'dispatcherServlet'
2019-12-03T21:07:54.452+07:00|2|DEBUG|example-service|,,|50382|http-nio-8080-exec-2|c.c.e.MessageController|In controller sending message 
2019-12-03T21:07:54.552+07:00|2|DEBUG|example-service|,,|50382|Camel (camel-1) thread #4 - RabbitMQConsumer|c.c.e.b.MessageActivity|Hello in message activity 
2019-12-03T21:07:54.580+07:00|2|DEBUG|example-service|,,|50382|Camel (camel-1) thread #6 - RabbitMQConsumer|c.c.e.b.SmsActivity|Hello in sms activity 
RamPrakash
  • 1,687
  • 3
  • 20
  • 25
Prabhat
  • 11
  • 3
  • 1
    It seems what you want is to add [MDC](https://logging.apache.org/log4j/2.x/manual/thread-context.html) for logging span and trace related information to logs. Camel does not do this by default for you. Check out [this blog post](https://developers.redhat.com/blog/2016/05/12/persistent-custom-mdc-logging-in-apache-camel/) on how to enable MDC logging in Camel. Note that MDC works upon a thread-local context, therefore information will only be present if it was set on the processing thread beforehand. – Roman Vottner Dec 03 '19 at 16:58
  • 1
    In regards to creating new span or traces please have a look a [ZipkinTraer](https://github.com/apache/camel/blob/master/components/camel-zipkin/src/main/java/org/apache/camel/zipkin/ZipkinTracer.java) to see when exactly new IDs will be generated. Enabling debug-log for camel-zipkin related classes, such as the `ZipkinTracer` might reveal some more insights – Roman Vottner Dec 03 '19 at 17:04
  • Actually it is creating new span and trace every-time it is publishing to rabbitmq, I want to avoid that. I also want to log span(X-B3-SpanId) and trace(X-B3-TraceId) , something similar to when we use spring-cloud-starter-zipkin. – Prabhat Dec 04 '19 at 06:33

0 Answers0