Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add sqs docs for java apm #19736

Draft
wants to merge 2 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
---
title: Use AWS SQS for message queues
tags:
- Agents
- Java agent
- Instrumentation
metaDescription: "How to improve instrumentation of the Amazon SQS SDK for Java applications using New Relic's APM"
redirects:
- /docs/agents/java-agent/instrumentation//instrument-aws-sqs-message-queues
freshnessValidatedDate: never
---

The Java Agent suports instrumentation for AWS SQS message queues. Our SQS instrumentation creates message broker traces but customers
may want extra information about the usage of the SQS SDK. This document provides examples on how to do it.

To see all supported SQS libraries, check the [Java compatibility and requirements page](/docs/agents/java-agent/getting-started/compatibility-requirements-java-agent).

## View SQS Distributed Tracing

Out of the box, our AWS SQS SDK instrumentation adds distributed trace headers as message attributes to SQS messages.
However for message recieven operations, we don't offer an out of the box way to accept these headers.
Instead we recommend cxustomers to use custom instrumentation to read the distributed trace headers.

Here is an example of how to read the distributed trace headers from an SQS message using the V2 SDK:


```java
public void v2Retrieve(SqsClient sqsClient, String queueUrl) {
List<Message> msgs = receiveMessages(queueUrl);
for (Message msg : msgs) {
handleMessage(msg);
}
}

// Since calling the SDK to recieve messages is a batch call, it is not recommended to accept distributed trace headers
// in the same transaction as the SDK call. Distributed traces can only have one parent span.
@Trace(dispatcher = true, metricName = "v2/receiveMessages")
public List<Message> receiveMessages(SqsClient sqsClient, String queueUrl) {
ReceiveMessageRequest request = ReceiveMessageRequest.builder()
.queueUrl(queueUrl)
.maxNumberOfMessages(10)
.build();

List<Message> messages = sqsClient.receiveMessage(request).messages();
if (messages.isEmpty()) {
logger.info("[v2 API] No messages received");
}
return messages;
}

// Here we accept distributed trace headers in a seperate transaction from the SDK call.
@Trace(dispatcher = true, metricName = "v2/handleMessage")
public void handleMessage(Message msg, SqsClient sqsClient, String queueUrl) {
// We use a wrapper class that helps extract the distributed trace headers
SQSReceivedMessageHeaders headers = new SQSReceivedMessageHeaders(msg);
// Here we accept the distributed trace headers
NewRelic.getAgent().getTransaction().acceptDistributedTraceHeaders(TransportType.Other, headers);


// Process your message here

DeleteMessageRequest deleteMessageRequest = DeleteMessageRequest.builder()
.queueUrl(queueUrl)
.receiptHandle(msg.receiptHandle())
.build();
sqsClient.deleteMessage(deleteMessageRequest);
}
```

Below is the wrapper class `SQSReceivedMessageHeaders` that extracts the distributed trace headers from the SQS message:

```java
import com.newrelic.api.agent.HeaderType;
import com.newrelic.api.agent.Headers;
import software.amazon.awssdk.services.sqs.model.Message;
import software.amazon.awssdk.services.sqs.model.MessageAttributeValue;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public class SQSReceivedMessageHeaders implements Headers {

private Message message = null;

public SQSReceivedMessageHeaders(Message msg) {
message = msg;
}

@Override
public HeaderType getHeaderType() {
return HeaderType.MESSAGE;
}

@Override
public String getHeader(String name) {
String value = null;
Map<String, MessageAttributeValue> msgAttributes = message.messageAttributes();
MessageAttributeValue msgAttributeValue = msgAttributes.get(name);
if(msgAttributeValue != null) {
if(msgAttributeValue.dataType().equalsIgnoreCase("string")) {
value = msgAttributeValue.stringValue();
}
}
return value;
}

@Override
public Collection<String> getHeaders(String name) {
List<String> list = new ArrayList<String>();
String value = getHeader(name);
if(value != null && !value.isEmpty()) {
list.add(value);
}
return list;
}

@Override
public void setHeader(String name, String value) {
// Not supported
}

@Override
public void addHeader(String name, String value) {
// Not supported
}

@Override
public Collection<String> getHeaderNames() {
if(message != null) {
Map<String, MessageAttributeValue> attributes = message.messageAttributes();
if(attributes != null) return attributes.keySet();
}
return Collections.emptyList();
}

@Override
public boolean containsHeader(String name) {
return getHeaderNames().contains(name);
}

}
```
2 changes: 2 additions & 0 deletions src/nav/apm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ pages:
path: /docs/new-relic-solutions/best-practices-guides/full-stack-observability/browser-monitoring-best-practices-java
- title: Instrument Kafka message queues
path: /docs/apm/agents/java-agent/instrumentation/java-agent-instrument-kafka-message-queues
- title: Instrument Amazon SQS
path: /docs/apm/agents/java-agent/instrumentation/instrument-aws-sqs-message-queues
- title: Use RabbitMQ or JMS for message queues
path: /docs/apm/agents/java-agent/instrumentation/use-rabbitmq-or-jms-message-queues
- title: Instrumentation modules
Expand Down
Loading