L'agent Java prend en charge instrumentation pour le fichier d'attente des messages AWS SQS. Bien que notre instrumentation SQS génère une trace de courtier de messages, vous souhaiterez peut-être des informations supplémentaires sur l'utilisation du SDK SQS.
Pour voir toutes les bibliothèques SQS prises en charge, reportez-vous à la page de compatibilité et d'exigencesJava .
Important
Les utilisateurs de Java Agent 8.18.0 doivent activer manuellement l'instrumentation SQS. Vous pouvez activer cette instrumentation dans votre fichier newrelic.yml
:
class_transformer: aws-java-sdk-sqs: enabled: true
Vous pouvez également définir la propriété système -Dnewrelic.config.class_transformer.aws-java-sdk-sqs.enabled=true
ou la variable d’environnement NEW_RELIC_CLASS_TRANSFORMER_AWS_JAVA_SDK_SQS_ENABLED=true
.
L'instrumentation est activée par défaut pour les autres versions de l'agent Java.
Afficher le tracing distribué SQS
AWS L'SQS SDK inclut instrumentation automatiquement les traceen-têtes distribués comme attribut de message pour les messages SQS. Cette fonctionnalité est disponible à partir de la version 2.1.0. Cependant, pour les opérations de récepteur de messages, il n'existe pas de méthode intégrée pour traiter ces en-têtes. Nous vous proposons de mettre en œuvre instrumentation personnalisée pour lire les en-têtes des tracedistribuées.
Voici un exemple de lecture des en-têtes tracedistribués à partir d'un message SQS à l'aide du SDK V2 :
// This method will call the SDK to receive messages and then process them public void readMessages(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); }
Voici la classe wrapper SQSReceivedMessageHeaders
qui extrait les en-têtes tracedistribués du message SQS :
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); }
}