Amazon SQS and AWS X-Ray - AWS X-Ray

Amazon SQS and AWS X-Ray

AWS X-Ray integrates with Amazon Simple Queue Service (Amazon SQS) to trace messages that are passed through an Amazon SQS queue. If a service traces requests by using the X-Ray SDK, Amazon SQS can send the tracing header and continue to propagate the original trace from the sender to the consumer with a consistent trace ID. Trace continuity enables users to track, analyze, and debug throughout downstream services.

            Service map from Lambda through the Amazon SQS queue.

Amazon SQS supports the following tracing header instrumentation:

  • Default HTTP Header – The X-Ray SDK automatically populates the trace header as an HTTP header when you call Amazon SQS through the AWS SDK. The default trace header is carried by X-Amzn-Trace-Id and corresponds to all messages included in a SendMessage or SendMessageBatch request. To learn more about the default HTTP header, see Tracing header.

  • AWSTraceHeader System Attribute – The AWSTraceHeader is a message system attribute reserved by Amazon SQS to carry the X-Ray trace header with messages in the queue. AWSTraceHeader is available for use even when auto-instrumentation through the X-Ray SDK is not, for example when building a tracing SDK for a new language. When both header instrumentations are set, the message system attribute overrides the HTTP trace header.

When running on Amazon EC2, Amazon SQS supports processing one message at a time. This applies when running on an on-premises host, and when using container services, such as AWS Fargate, Amazon ECS, or AWS App Mesh.

The trace header is excluded from both Amazon SQS message size and message attribute quotas. Enabling X-Ray tracing will not exceed your Amazon SQS quotas. To learn more about AWS quotas, see Amazon SQS Quotas.


It is not currently possible to connect a trace passed into an SQS queue to the Lambda consuming it on the other end. This is because although the trace header is propagated in the SQS message, you cannot set it in the Lambda because segments in Lambda are immutable.

Send the HTTP trace header

Sender components in Amazon SQS can send the trace header automatically through the SendMessageBatch or SendMessage call. When AWS SDK clients are instrumented, they can be automatically tracked through all languages supported through the X-Ray SDK. Traced AWS services and resources that you access within those services (for example, an Amazon S3 bucket or Amazon SQS queue), appear as downstream nodes on the service map in the X-Ray console.

To learn how to trace AWS SDK calls with your preferred language, see the following topics in the supported SDKs:

Retrieve the trace header and recover trace context

To continue context propagation with Amazon SQS, you must manually instrument the handoff to the receiver component.

There are three main steps to recovering the trace context:

  • Receive the message from the queue for the AWSTraceHeader attribute by calling the ReceiveMessage API.

  • Retrieve the trace header from the attribute.

  • Recover the trace ID from the header. Optionally, add more metrics to the segment.

The following is an example implementation written with the X-Ray SDK for Java.

Example : Retrieve the trace header and recover trace context

// Receive the message from the queue, specifying the "AWSTraceHeader" ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest() .withQueueUrl(QUEUE_URL) .withAttributeNames("AWSTraceHeader"); List<Message> messages = sqs.receiveMessage(receiveMessageRequest).getMessages(); if (!messages.isEmpty()) { Message message = messages.get(0); // Retrieve the trace header from the AWSTraceHeader message system attribute String traceHeaderStr = message.getAttributes().get("AWSTraceHeader"); if (traceHeaderStr != null) { TraceHeader traceHeader = TraceHeader.fromString(traceHeaderStr); // Recover the trace context from the trace header Segment segment = AWSXRay.getCurrentSegment(); segment.setTraceId(traceHeader.getRootTraceId()); segment.setParentId(traceHeader.getParentId()); segment.setSampled(traceHeader.getSampled().equals(TraceHeader.SampleDecision.SAMPLED)); } }