Failed to Creation of subsegment with @SQSListener for AWS Xray

217 Views Asked by At

My application is configured to add subsegment for sqs when it is received HTTP call requsting send SQS.

I've added libraries by the AWS guideline[1].

So that it works to add subsegment sending a message without receiving messages with @SQSListner.

But, I've been stuck implementing AWS xray with @SQSListner with the errors below.

Aleady, I've tried to add an AOP pointcut before starting receiveMessage to create subsegment named 'AmazonSQS'.

But, it's not work that I expected that's why I register this ticket.

Please guide me if you have implemented with @SQSListener or understood what I'm wrong and how to fix it.

Error Log

java.lang.RuntimeException: Failed to begin subsegment named 'AmazonSQS': segment cannot be found.
    at com.amazonaws.xray.strategy.LogErrorContextMissingStrategy.contextMissing(LogErrorContextMissingStrategy.java:36)
    at com.amazonaws.xray.contexts.ThreadLocalSegmentContext.beginSubsegment(ThreadLocalSegmentContext.java:39)
    at com.amazonaws.xray.AWSXRayRecorder.beginSubsegment(AWSXRayRecorder.java:616)
    at com.amazonaws.xray.handlers.TracingHandler.beforeRequest(TracingHandler.java:186)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.runBeforeRequestHandlers(AmazonHttpClient.java:853)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:794)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:781)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:755)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:715)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:697)
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:561)
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:541)
    at com.amazonaws.services.sqs.AmazonSQSClient.doInvoke(AmazonSQSClient.java:2329)
    at com.amazonaws.services.sqs.AmazonSQSClient.invoke(AmazonSQSClient.java:2296)
    at com.amazonaws.services.sqs.AmazonSQSClient.invoke(AmazonSQSClient.java:2285)
    at com.amazonaws.services.sqs.AmazonSQSClient.executeReceiveMessage(AmazonSQSClient.java:1715)
    at com.amazonaws.services.sqs.AmazonSQSClient.receiveMessage(AmazonSQSClient.java:1683)
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$AsynchronousMessageListener.run(SimpleMessageListenerContainer.java:336)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:833)

2023-09-19 09:51:05.731 ERROR 11360 --- [enerContainer-1] c.a.x.s.LogErrorContextMissingStrategy   : Suppressing AWS X-Ray context missing exception (SegmentNotFoundException): No segment in progress.
2023-09-19 09:51:05.731 DEBUG 11360 --- [enerContainer-1] c.a.x.s.LogErrorContextMissingStrategy   : Attempted to find context at:
 
java.lang.RuntimeException: No segment in progress.
    at com.amazonaws.xray.strategy.LogErrorContextMissingStrategy.contextMissing(LogErrorContextMissingStrategy.java:36)
    at com.amazonaws.xray.AWSXRayRecorder.getCurrentSegment(AWSXRayRecorder.java:668)
    at com.amazonaws.xray.handlers.TracingHandler.beforeRequest(TracingHandler.java:194)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.runBeforeRequestHandlers(AmazonHttpClient.java:853)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:794)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:781)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:755)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:715)
    at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:697)
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:561)
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:541)
    at com.amazonaws.services.sqs.AmazonSQSClient.doInvoke(AmazonSQSClient.java:2329)
    at com.amazonaws.services.sqs.AmazonSQSClient.invoke(AmazonSQSClient.java:2296)
    at com.amazonaws.services.sqs.AmazonSQSClient.invoke(AmazonSQSClient.java:2285)
    at com.amazonaws.services.sqs.AmazonSQSClient.executeReceiveMessage(AmazonSQSClient.java:1715)
    at com.amazonaws.services.sqs.AmazonSQSClient.receiveMessage(AmazonSQSClient.java:1683)
    at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$AsynchronousMessageListener.run(SimpleMessageListenerContainer.java:336)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:833)

[1] https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-java-aop-spring.html

Sample code and configuration

pom.xml

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-java-sdk-bom</artifactId>
      <version>1.12.468</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-xray-recorder-sdk-bom</artifactId>
      <version>2.14.0</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

  <!-- (...) -->

<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-aws</artifactId>
    <version>2.2.6.RELEASE</version>
  </dependency>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-aws-messaging</artifactId>
    <version>2.2.6.RELEASE</version>
  </dependency>
  <dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk-sqs</artifactId>
  </dependency>
  <dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>amazon-sqs-java-messaging-lib</artifactId>
    <version>2.0.1</version>
  </dependency>
  <dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-xray-recorder-sdk-core</artifactId>
  </dependency>
  <dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-xray-recorder-sdk-apache-http</artifactId>
  </dependency>
  <dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-xray-recorder-sdk-aws-sdk</artifactId>
  </dependency>
  <dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-xray-recorder-sdk-aws-sdk-instrumentor</artifactId>
  </dependency>
  <dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-xray-recorder-sdk-sql-postgres</artifactId>
  </dependency>
  <dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-xray-recorder-sdk-slf4j</artifactId>
  </dependency>
  <dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-xray-recorder-sdk-spring</artifactId>
  </dependency>
</dependencies>

AmazonSQSSenderImpl.java

@RequiredArgsConstructor
@Service
@XRayEnabled
public class AmazonSQSSenderImpl implements AmazonSQSSender {
  @Value("${cloud.aws.sqs.queue.url}")
  private String url;
  private final ObjectMapper objectMapper;
  private final AmazonSQS amazonSQS;

  /**
   * Send message
   */
  @Override
  public SendMessageResult sendMessage1(EcmDto msg) throws JsonProcessingException {
    Map<String, MessageAttributeValue> messageAttributes = new HashMap<>();
    messageAttributes.put("AttributeOne", new MessageAttributeValue()
      .withStringValue("This is an attribute sendMessage1")
      .withDataType("String"));
    SendMessageRequest sendMessageStandardQueue = new SendMessageRequest()
      .withQueueUrl(url)
      .withMessageBody(objectMapper.writeValueAsString(msg))
      .withMessageAttributes(messageAttributes);
    return amazonSQS.sendMessage(sendMessageStandardQueue);
  }
}

AwsSqsListener.java

@Slf4j
@Service
@RequiredArgsConstructor
@XRayEnabled
public class AwsSqsListener {
  @SqsListener(value = "${cloud.aws.sqs.queue.url}", deletionPolicy = SqsMessageDeletionPolicy.NEVER)
  public void listenUdwrDemd(@Payload String info, @Headers Map<String, String> headers, Acknowledgment ack) {
    log.info("-------------------------------------start SqsListener url");
    log.info("-------------------------------------info {}", info);
    log.info("-------------------------------------headers {}", headers);
    ack.acknowledge();
  }
}

XRayInspector.java

@Aspect
@Component
public class XRayInspector extends BaseAbstractXRayInterceptor {
  @Override
  protected Map<String, Map<String, Object>> generateMetadata(ProceedingJoinPoint proceedingJoinPoint, Subsegment subsegment) {
    return super.generateMetadata(proceedingJoinPoint, subsegment);
  }

  @Override
  @Pointcut("@within(com.amazonaws.xray.spring.aop.XRayEnabled) && bean(*Controller)")
  public void xrayEnabledClasses() {
  }
}

WebConfig.java

@Configuration
public class WebConfig implements WebMvcConfigurer {
  @Value("${spring.application.name}")
  String applicationName;

  @Override
  public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**")
      .allowedOrigins("*");
  }

  @Bean
  public Filter tracingFilter() {
    return new AWSXRayServletFilter(applicationName.toUpperCase());
  }
}

Application.java

@SpringBootApplication
public class Application {
  public static void main(String[] args) {
    SpringApplication api = new SpringApplication(Application.class);
    api.addListeners(new ApplicationPidFileWriter());
    api.run(args);
  }
}

Create subsegment for AWS Xray implementing with @SQSListener

1

There are 1 best solutions below

0
Lei Wang On

XRay data model requires the Subsegment has to have a parent Segment, which is retrieved from ThreadLocal, else user gets ContextMissing error.

Could you try to instrument the incoming request by following X-Ray doc? It will automatically generate Segment for incoming request and will be parent of SQS Subsegment later.