This article focuses on integrating RabbitMQ with SkyWalking to build complete distributed tracing for asynchronous messaging, connecting HTTP requests, message publishing, message consumption, and downstream calls into one continuous trace. It addresses fragmented logs, difficult troubleshooting, and invisible performance bottlenecks. Keywords: RabbitMQ, SkyWalking, Distributed Tracing.
Technical Specifications Snapshot
| Parameter | Description |
|---|---|
| Languages | Java, YAML, Bash |
| Protocols | AMQP, HTTP, sw8 |
| Use Cases | Asynchronous microservice communication, message tracing, APM observability |
| Reference Versions | RabbitMQ 3.x, SkyWalking 9.7.0, Spring Boot |
| Core Dependencies | spring-boot-starter-amqp, SkyWalking Java Agent |
| Deployment Model | Run OAP and UI with Docker, attach the Agent to the JVM |
| Stars | Not provided in the original content |
AI Visual Insight: This image serves as the article’s thematic illustration, introducing the combined RabbitMQ and SkyWalking scenario. It highlights how, once a message broker becomes part of the observability stack, the producer, broker, and consumer can all be unified within the same trace.
Asynchronous message flows must be included in the distributed tracing system
In microservice architectures, HTTP request paths are usually easy to observe. But once a service decouples business logic through RabbitMQ, the call chain often breaks between message publishing and message consumption. Developers then have to reconstruct the path from logs and business IDs, which makes troubleshooting expensive and slow.
SkyWalking solves this by turning message publishing through basicPublish and message reception through handleDelivery into traceable spans. As a result, the entire path—from the user request entry point to message delivery and consumer-side processing—appears as one continuous trace in the UI.
SkyWalking’s tracing model makes it a strong fit for RabbitMQ
SkyWalking defines a complete request as a trace, an individual operation as a span, and connects cross-thread and cross-process calls through context propagation. In RabbitMQ scenarios, that context is typically passed through message headers.
# SkyWalking core configuration
agent.service_name=order-service
collector.backend_service=127.0.0.1:11800
plugin.rabbitmq.trace_message_header=true # Enable message header propagation for tracing
This configuration names the service, points the agent to the OAP backend, and explicitly enables RabbitMQ message header tracing.
You must deploy the SkyWalking backend before it can receive tracing data
A practical approach is to start OAP and the UI with Docker first. In a test environment, the default in-memory storage is enough. This lets you quickly verify whether RabbitMQ producer and consumer traces are being reported to SkyWalking.
docker pull apache/skywalking-oap-server:9.7.0
docker pull apache/skywalking-ui:9.7.0
# Start the OAP service
docker run --name skywalking-oap -d \
-p 11800:11800 -p 12800:12800 \
apache/skywalking-oap-server:9.7.0
# Start the UI
docker run --name skywalking-ui -d \
-p 8080:8080 \
--link skywalking-oap:oap \
-e SW_OAP_ADDRESS=oap:12800 \
apache/skywalking-ui:9.7.0
This script completes a quick deployment of OAP and the UI. You can then open http://localhost:8080 to inspect traces.
Java applications gain non-intrusive tracing through the Agent
For Java, the best way to integrate SkyWalking is to attach the Agent with a JVM parameter instead of modifying business code. Once the Agent loads correctly, it automatically enhances key Spring AMQP and RabbitMQ Client execution points.
java -javaagent:/path/to/skywalking-agent/skywalking-agent.jar \
-jar order-service.jar
This startup command injects tracing logic at runtime and enables zero-intrusion instrumentation.
The producer-side goal is to inject the sw8 message header automatically
The producer does not need to manage the Trace ID manually. It only needs the Agent attached and a normal Spring AMQP message publishing flow. SkyWalking intercepts the send operation and writes the sw8 context into the message headers.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
These dependencies provide the web interface and RabbitMQ messaging support that the producer example requires.
@Configuration
public class RabbitMQConfig {
public static final String ORDER_EXCHANGE = "order.exchange";
public static final String ORDER_QUEUE = "order.queue";
public static final String ORDER_ROUTING_KEY = "order.create";
@Bean
public DirectExchange orderExchange() {
return new DirectExchange(ORDER_EXCHANGE); // Define a direct exchange
}
@Bean
public Queue orderQueue() {
return new Queue(ORDER_QUEUE, true); // Define a durable queue
}
@Bean
public Binding orderBinding() {
return BindingBuilder.bind(orderQueue())
.to(orderExchange())
.with(ORDER_ROUTING_KEY); // Bind the routing key
}
}
This configuration defines the exchange, queue, and routing binding that provide a stable carrier for traceable message delivery.
You do not need to write tracing code when sending messages
@RestController
@RequestMapping("/orders")
public class OrderController {
@Autowired
private RabbitTemplate rabbitTemplate;
@PostMapping
public ResponseEntity
<String> createOrder(@RequestBody OrderRequest request) {
String orderId = UUID.randomUUID().toString(); // Generate an order ID
rabbitTemplate.convertAndSend(
RabbitMQConfig.ORDER_EXCHANGE,
RabbitMQConfig.ORDER_ROUTING_KEY,
orderId // Send the order message
);
return ResponseEntity.ok("Order created: " + orderId);
}
}
This controller triggers order creation and message publishing. The SkyWalking Agent automatically writes the current trace context into the message headers.
The consumer-side goal is to restore the context and continue the trace
The consumer should not create a completely new trace. Instead, it should continue the trace started by the producer. When the Agent is active, this process is fully automatic, and the business code does not need to know about sw8.
@Component
public class OrderConsumer {
private static final Logger log = LoggerFactory.getLogger(OrderConsumer.class);
@RabbitListener(queues = RabbitMQConfig.ORDER_QUEUE)
public void handleOrderCreate(String orderId) {
log.info("Processing order: {}", orderId); // Record the consumption log
try {
Thread.sleep(500); // Simulate time-consuming processing
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // Restore the interrupt flag
}
}
}
This consumer demonstrates the simplest message handling flow. SkyWalking restores the trace context before the listener method runs.
End-to-end validation should reveal four categories of spans
After deployment, start RabbitMQ, the producer, and the consumer, then call the order API. In SkyWalking UI, you should see at least the HTTP entry span, the message publishing span, the message consumption span, and any downstream spans created inside the consumer.
curl -X POST http://localhost:8081/orders \
-H "Content-Type: application/json" \
-d '{"userId":"123","items":["itemA"]}'
This command triggers a complete business flow so you can verify that asynchronous tracing is fully connected in the UI.
Consider manual context propagation only when automatic enhancement fails
If your project uses the native RabbitMQ Client directly, or an internal abstraction layer prevents the Agent from recognizing the call site, you can manually write the context into message headers. The principle is simple: prefer automatic propagation first, and use manual fallback only when necessary.
ContextCarrier carrier = new ContextCarrier();
ContextManager.inject(carrier); // Inject the current tracing context
Map<String, Object> headers = new HashMap<>();
CarrierItem item = carrier.items();
while (item.hasNext()) {
item = item.next();
headers.put(item.getHeadKey(), item.getHeadValue()); // Write into the message headers
}
This code manually injects tracing headers on the producer side and is suitable for message publishing paths that the Agent cannot cover.
Check these three facts first during troubleshooting
First, confirm that the application startup logs show that the Agent loaded successfully. Second, verify that the RabbitMQ message properties contain sw8. Third, confirm that both the producer and consumer have the Agent attached and use clear, distinct service names.
If you see significant latency or missing data, RabbitMQ itself is usually not the root cause. The problem is more often related to OAP storage, network connectivity, or poor sampling configuration. In production, do not rely on H2 for long-term use. Switch to persistent storage such as Elasticsearch instead.
SkyWalking provides clear integration advantages for RabbitMQ observability
Compared with solutions that require manual instrumentation, SkyWalking stands out through its non-intrusive Java Agent, plugin-based RabbitMQ support, automatic topology generation, and mature handling of asynchronous context propagation. That makes it a strong choice for Java microservice teams that want to roll out observability quickly.
Best practices should focus on stability and diagnosability
Keep Agent versions consistent, standardize agent.service_name naming, preserve message header propagation, inject Trace IDs into logs, and avoid promoting test-environment settings directly into production. These details determine whether your traces can support real troubleshooting instead of merely appearing functional.
FAQ
FAQ 1: Why can I see the HTTP trace but not the RabbitMQ message trace?
The most common reason is that the Agent is not active, or plugin.rabbitmq.trace_message_header=true is not enabled. You should also check whether the outgoing message headers actually contain the sw8 field.
FAQ 2: Why do both the producer and the consumer report data, but the trace is still broken?
In most cases, the context is not being propagated successfully across both ends. Common causes include message headers being stripped by middleware, the consumer running without the Agent, or a custom client bypassing SkyWalking’s plugin enhancement points.
FAQ 3: Does SkyWalking noticeably slow down RabbitMQ workloads?
Under normal conditions, the overhead is small and typically appears as light CPU and memory usage. Latency tends to increase only when the sampling rate is too high or OAP storage capacity is insufficient under high throughput. In those cases, optimize both sampling and storage strategy.
Core Summary: This article provides a complete integration blueprint for RabbitMQ and SkyWalking, covering OAP/UI deployment, Java Agent configuration, producer and consumer integration, sw8 header propagation, trace validation, and troubleshooting. It helps you build visual, diagnosable, and measurable end-to-end tracing in asynchronous architectures.