amazon-sqs-java-messaging-lib icon indicating copy to clipboard operation
amazon-sqs-java-messaging-lib copied to clipboard

Is there a way to obtain AWS Trace Header as part JMSListener headers ?

Open ghoshrahul opened this issue 3 years ago • 1 comments
trafficstars

Hi,

Amazon SQS supports tracing of message passed through it's queue using the system attribute. However on the consumer/receiver end, we are using JMSListener, with the basic configuration to receive message from the queue.

Is there a way to obtain the system attribute by using JMSListener? We would want to trace the entire message flow and figure the bottlenecks in our application.

Kindly point us to the documentation, or sample code that can be used for achieving this.

<dependency> <groupId>com.amazonaws</groupId> <artifactId>amazon-sqs-java-messaging-lib</artifactId> <version>1.0.8</version> </dependency>

Let me know if any additional information is required

ghoshrahul avatar May 06 '22 05:05 ghoshrahul

I have a similar problem. We use the Java Opentelemetry agent spring-jms auto-instrumentation to get a full trace of producer -> consumer. This instrumentation expects either a traceparent or AWSTraceHeader property to be present in the properties map of the SQSMessage.

It seems the current implementation of com.amazon.sqs.javamessaging.message.SQSMessage does not allow for custom properties depending on System Attributes or Message Attributes.

I've managed to fix this by overloading the class in the Classpath with my own implementation. Just a copy-paste of the whole class, but in the constructer, I've added the following:

package com.amazon.sqs.javamessaging.message;

public class SQSMessage implements Message {
    ...
    SQSMessage(Acknowledger acknowledger, String queueUrl, software.amazon.awssdk.services.sqs.model.Message sqsMessage) throws JMSException {
        ...
        if(systemAttributes.containsKey(MessageSystemAttributeName.fromValue("AWSTraceHeader"))) {
            String awsTraceHeader = systemAttributes.get(MessageSystemAttributeName.fromValue("AWSTraceHeader"));
            String[] parts = awsTraceHeader.split(";");
            String root = null, parent = null, sampled = null;
            for (String part : parts) {
                if (part.startsWith("Root=")) {
                    root = part.substring(5);
                } else if (part.startsWith("Parent=")) {
                    parent = part.substring(7);
                } else if (part.startsWith("Sampled=")) {
                    sampled = part.substring(8);
                }
            }

            if(root != null && parent != null && sampled != null) {
                String[] rootParts = root.split("-");
                String traceId = rootParts[1] + rootParts[2];

                String spanId = parent;

                String flags = "00";
                if ("1".equals(sampled)) {
                    flags = "01";
                }

                properties.put("traceparent", new JMSMessagePropertyValue(String.format("00-%s-%s-%s", traceId, spanId, flags), STRING));
            }
        }
        ...
    }
    ...
}

This is pretty dirty fix as it does not handle upgrades very well as we need to diff possible changes (luckily this class does not change very often) + we have to make sure that our overloaded class is the first one the classloader will find.

It would be very useful to have some kind of message post-processing function that can do this during the processReceivedMessages(List<Message> messages) call

susverwimp avatar Jul 04 '24 15:07 susverwimp