spring-boothealth-checkaws-xray

Stop AWS XRay tracing the Spring Boot healthcheck endpoint


I am instrumenting my Sprint Boot application with AWS XRay which is working really nicely using aws-xray-recorder-sdk-spring. However I'm only interested in the user interaction with my application, rather than the system health check, but I'm having trouble disabling the instrumentation of the health check.

From what I understand from the documentation, this should be controlled via a @Pointcut. You can see below that I've tried to configure the @Pointcut to exclude spring health checks via !within(org.springframework.boot.actuate.health.*), but the health check is still being instrumented, as you can see from the XRay debug logging below.

Does anyone know how I can achieve this?

@Aspect
@Component
public class XRayInspector extends BaseAbstractXRayInterceptor {
    @Override
    @Pointcut("@within(com.amazonaws.xray.spring.aop.XRayEnabled) && !springHealthChecks()")
    public void xrayEnabledClasses() {
    }

    @Pointcut("within(org.springframework.boot.actuate.health.*)")
    public void springHealthChecks() {
    }

    @Override
    protected Map<String, Map<String, Object>> generateMetadata(ProceedingJoinPoint proceedingJoinPoint, Subsegment subsegment) {
        return super.generateMetadata(proceedingJoinPoint, subsegment);
    }
}

2023-05-05T14:40:10.710Z DEBUG 8 --- [io-8080-exec-10] com.amazonaws.xray.emitters.UDPEmitter   : {
  "name" : "Test Service",
  "id" : "5bcf87b917b29e69",
  "start_time" : 1.683297610683E9,
  "trace_id" : "1-6455154a-b6544c2518e7bd28a18a3267",
  "end_time" : 1.683297610709E9,
  "http" : {
    "request" : {
      "method" : "GET",
      "client_ip" : "127.0.0.1",
      "url" : "http://localhost:8080/testservice/management/health",
      "user_agent" : "curl/7.88.1"
    },
    "response" : {
      "status" : 200
    }
  },
  "aws" : {
    "xray" : {
      "sdk_version" : "2.9.1",
      "sdk" : "X-Ray for Java"
    }
  },
  "service" : {
    "runtime_version" : "17.0.6",
    "runtime" : "OpenJDK 64-Bit Server VM"
  }
}

Solution

  • You can achieve this by extending AWSXRayServletFilter.class and configuring you own filter. This way you can exclude endpoints you don't want to track

    Exmaple code:

    import com.amazonaws.xray.javax.servlet.AWSXRayServletFilter;
    import java.io.IOException;
    import java.util.List;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    
    public class XrayEndpointFilter extends AWSXRayServletFilter {
    
        private final List<String> ignoredEndpoints;
    
    
        XrayEndpointFilter(final List<String> ignoredEndpoints) {
            super("appName");
            this.ignoredEndpoints = ignoredEndpoints;
        }
    
        @Override
        public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
                throws ServletException, IOException {
    
            final String uri = ((HttpServletRequest) request).getRequestURI();
    
            boolean shouldFilter = ignoredEndpoints.stream()
                    .map(Pattern::compile)
                    .map(pattern -> pattern.matcher(uri))
                    .anyMatch(Matcher::find);
    
            if (shouldFilter) {
                chain.doFilter(request, response);
            } else {
                super.doFilter(request, response, chain);
            }
        }
    }