aws-xray-recorder-sdk-core/src/main/java/com/amazonaws/xray/jakarta/servlet/AWSXRayServletFilter.java [167:447]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        } else if (null == segmentNamingStrategy) {
            throw new ServletException(
                "The AWSXRayServletFilter requires either a fixedName init-param or an instance of SegmentNamingStrategy. "
                + "Add an init-param tag to the AWSXRayServletFilter's declaration in web.xml, using param-name: 'fixedName'. "
                + "Alternatively, pass an instance of SegmentNamingStrategy to the AWSXRayServletFilter constructor.");
        }
    }

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(
        ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (logger.isDebugEnabled()) {
            logger.debug("AWSXRayServletFilter is beginning to process request: " + request.toString());
        }
        Segment segment = preFilter(request, response);

        try {
            chain.doFilter(request, response);
        } catch (Throwable e) {
            segment.addException(e);
            throw e;
        } finally {
            if (request.isAsyncStarted()) {
                request.setAttribute(AWSXRayServletAsyncListener.ENTITY_ATTRIBUTE_KEY, segment);
                try {
                    request.getAsyncContext().addListener(listener);
                    if (recorder != null) {
                        recorder.clearTraceEntity();
                    }
                } catch (IllegalStateException ise) {
                    // race condition that occurs when async processing finishes before adding the listener
                    postFilter(request, response);
                }
            } else {
                postFilter(request, response);
            }

            if (logger.isDebugEnabled()) {
                logger.debug("AWSXRayServletFilter is finished processing request: " + request.toString());
            }
        }
    }

    @Nullable
    private HttpServletRequest castServletRequest(ServletRequest request) {
        try {
            return (HttpServletRequest) request;
        } catch (ClassCastException cce) {
            logger.warn("Unable to cast ServletRequest to HttpServletRequest.", cce);
        }
        return null;
    }

    @Nullable
    private HttpServletResponse castServletResponse(ServletResponse response) {
        try {
            return (HttpServletResponse) response;
        } catch (ClassCastException cce) {
            logger.warn("Unable to cast ServletResponse to HttpServletResponse.", cce);
        }
        return null;
    }

    private Optional<TraceHeader> getTraceHeader(HttpServletRequest request) {
        String traceHeaderString = request.getHeader(TraceHeader.HEADER_KEY);
        if (null != traceHeaderString) {
            return Optional.of(TraceHeader.fromString(traceHeaderString));
        }
        return Optional.empty();
    }

    private Optional<String> getHost(HttpServletRequest request) {
        return Optional.ofNullable(request.getHeader("Host"));
    }

    private Optional<String> getClientIp(HttpServletRequest request) {
        return Optional.ofNullable(request.getRemoteAddr());
    }

    private Optional<String> getXForwardedFor(HttpServletRequest request) {
        String forwarded = request.getHeader("X-Forwarded-For");
        if (forwarded != null) {
            return Optional.of(forwarded.split(",")[0].trim());
        }
        return Optional.empty();
    }

    private Optional<String> getUserAgent(HttpServletRequest request) {
        String userAgentHeaderString = request.getHeader("User-Agent");
        if (null != userAgentHeaderString) {
            return Optional.of(userAgentHeaderString);
        }
        return Optional.empty();
    }

    private Optional<Integer> getContentLength(HttpServletResponse response) {
        String contentLengthString = response.getHeader("Content-Length");
        if (null != contentLengthString && !contentLengthString.isEmpty()) {
            try {
                return Optional.of(Integer.parseInt(contentLengthString));
            } catch (NumberFormatException nfe) {
                logger.debug("Unable to parse Content-Length header from HttpServletResponse.", nfe);
            }
        }
        return Optional.empty();
    }

    private String getSegmentName(HttpServletRequest httpServletRequest) {
        if (segmentNamingStrategy == null) {
            throw new RuntimeException(
                "The AWSXRayServletFilter requires either a fixedName init-param or an instance of SegmentNamingStrategy. "
                + "Add an init-param tag to the AWSXRayServletFilter's declaration in web.xml, using param-name: 'fixedName'. "
                + "Alternatively, pass an instance of SegmentNamingStrategy to the AWSXRayServletFilter constructor.");
        }
        return segmentNamingStrategy.nameForRequest(httpServletRequest);
    }

    private SamplingResponse fromSamplingStrategy(HttpServletRequest httpServletRequest) {
        AWSXRayRecorder recorder = getRecorder();
        SamplingRequest samplingRequest = new SamplingRequest(
            getSegmentName(httpServletRequest),
            getHost(httpServletRequest).orElse(null), httpServletRequest.getRequestURI(), httpServletRequest.getMethod(),
            recorder.getOrigin());
        SamplingResponse sample = recorder.getSamplingStrategy().shouldTrace(samplingRequest);
        return sample;
    }

    private SampleDecision getSampleDecision(SamplingResponse sample) {
        if (sample.isSampled()) {
            logger.debug("Sampling strategy decided SAMPLED.");
            return SampleDecision.SAMPLED;
        } else {
            logger.debug("Sampling strategy decided NOT_SAMPLED.");
            return SampleDecision.NOT_SAMPLED;
        }
    }

    private AWSXRayRecorder getRecorder() {
        if (recorder == null) {
            recorder = AWSXRay.getGlobalRecorder();
        }
        return recorder;
    }

    public Segment preFilter(ServletRequest request, ServletResponse response) {
        AWSXRayRecorder recorder = getRecorder();
        HttpServletRequest httpServletRequest = castServletRequest(request);
        if (httpServletRequest == null) {
            logger.warn("Null value for incoming HttpServletRequest. Beginning NoOpSegment.");
            return recorder.beginNoOpSegment();
        }

        Optional<TraceHeader> incomingHeader = getTraceHeader(httpServletRequest);
        SamplingStrategy samplingStrategy = recorder.getSamplingStrategy();

        if (logger.isDebugEnabled() && incomingHeader.isPresent()) {
            logger.debug("Incoming trace header received: " + incomingHeader.get().toString());
        }

        SamplingResponse samplingResponse = fromSamplingStrategy(httpServletRequest);

        SampleDecision sampleDecision = incomingHeader.isPresent()
                                        ? incomingHeader.get().getSampled() : getSampleDecision(samplingResponse);
        if (SampleDecision.REQUESTED.equals(sampleDecision) || SampleDecision.UNKNOWN.equals(sampleDecision)) {
            sampleDecision = getSampleDecision(samplingResponse);
        }

        TraceID traceId = null;
        String parentId = null;
        if (incomingHeader.isPresent()) {
            TraceHeader header = incomingHeader.get();
            traceId = header.getRootTraceId();
            parentId = header.getParentId();
        }

        final Segment created;
        if (SampleDecision.SAMPLED.equals(sampleDecision)) {
            String segmentName = getSegmentName(httpServletRequest);
            created = traceId != null
                      ? recorder.beginSegment(segmentName, traceId, parentId)
                      : recorder.beginSegment(segmentName);
            if (samplingResponse.getRuleName().isPresent()) {
                logger.debug("Sampling strategy decided to use rule named: " + samplingResponse.getRuleName().get() + ".");
                created.setRuleName(samplingResponse.getRuleName().get());
            }
        } else { //NOT_SAMPLED
            String segmentName = getSegmentName(httpServletRequest);
            if (samplingStrategy.isForcedSamplingSupported()) {
                created = traceId != null
                          ? recorder.beginSegment(segmentName, traceId, parentId)
                          : recorder.beginSegment(segmentName);
                created.setSampled(false);
            } else {
                logger.debug("Creating Dummy Segment");
                created = traceId != null ? recorder.beginNoOpSegment(traceId) : recorder.beginNoOpSegment();
            }
        }

        Map<String, Object> requestAttributes = new HashMap<String, Object>();
        requestAttributes.put("url", httpServletRequest.getRequestURL().toString());
        requestAttributes.put("method", httpServletRequest.getMethod());

        Optional<String> userAgent = getUserAgent(httpServletRequest);
        if (userAgent.isPresent()) {
            requestAttributes.put("user_agent", userAgent.get());
        }

        Optional<String> xForwardedFor = getXForwardedFor(httpServletRequest);
        if (xForwardedFor.isPresent()) {
            requestAttributes.put("client_ip", xForwardedFor.get());
            requestAttributes.put("x_forwarded_for", true);
        } else {
            Optional<String> clientIp = getClientIp(httpServletRequest);
            if (clientIp.isPresent()) {
                requestAttributes.put("client_ip", clientIp.get());
            }
        }

        created.putHttp("request", requestAttributes);

        HttpServletResponse httpServletResponse = castServletResponse(response);
        if (httpServletResponse == null) {
            return created;
        }

        final TraceHeader responseHeader;
        if (incomingHeader.isPresent()) {
            // create a new header, and use the incoming header so we know what to do in regards to sending back the sampling
            // decision.
            responseHeader = new TraceHeader(created.getTraceId());
            if (SampleDecision.REQUESTED == incomingHeader.get().getSampled()) {
                responseHeader.setSampled(created.isSampled() ? SampleDecision.SAMPLED : SampleDecision.NOT_SAMPLED);
            }
        } else {
            // Create a new header, we're the tracing root. We wont return the sampling decision.
            responseHeader = new TraceHeader(created.getTraceId());
        }
        httpServletResponse.addHeader(TraceHeader.HEADER_KEY, responseHeader.toString());

        return created;
    }

    public void postFilter(ServletRequest request, ServletResponse response) {
        AWSXRayRecorder recorder = getRecorder();
        Segment segment = recorder.getCurrentSegment();
        if (null != segment) {
            HttpServletResponse httpServletResponse = castServletResponse(response);

            if (null != httpServletResponse) {
                Map<String, Object> responseAttributes = new HashMap<String, Object>();

                int responseCode = httpServletResponse.getStatus();
                switch (responseCode / 100) {
                    case 4:
                        segment.setError(true);
                        if (responseCode == 429) {
                            segment.setThrottle(true);
                        }
                        break;
                    case 5:
                        segment.setFault(true);
                        break;
                    default:
                        break;
                }
                responseAttributes.put("status", responseCode);


                Optional<Integer> contentLength = getContentLength(httpServletResponse);
                if (contentLength.isPresent()) {
                    responseAttributes.put("content_length", contentLength.get());
                }

                segment.putHttp("response", responseAttributes);
            }

            recorder.endSegment();
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



aws-xray-recorder-sdk-core/src/main/java/com/amazonaws/xray/javax/servlet/AWSXRayServletFilter.java [167:447]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        } else if (null == segmentNamingStrategy) {
            throw new ServletException(
                "The AWSXRayServletFilter requires either a fixedName init-param or an instance of SegmentNamingStrategy. "
                + "Add an init-param tag to the AWSXRayServletFilter's declaration in web.xml, using param-name: 'fixedName'. "
                + "Alternatively, pass an instance of SegmentNamingStrategy to the AWSXRayServletFilter constructor.");
        }
    }

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(
        ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (logger.isDebugEnabled()) {
            logger.debug("AWSXRayServletFilter is beginning to process request: " + request.toString());
        }
        Segment segment = preFilter(request, response);

        try {
            chain.doFilter(request, response);
        } catch (Throwable e) {
            segment.addException(e);
            throw e;
        } finally {
            if (request.isAsyncStarted()) {
                request.setAttribute(AWSXRayServletAsyncListener.ENTITY_ATTRIBUTE_KEY, segment);
                try {
                    request.getAsyncContext().addListener(listener);
                    if (recorder != null) {
                        recorder.clearTraceEntity();
                    }
                } catch (IllegalStateException ise) {
                    // race condition that occurs when async processing finishes before adding the listener
                    postFilter(request, response);
                }
            } else {
                postFilter(request, response);
            }

            if (logger.isDebugEnabled()) {
                logger.debug("AWSXRayServletFilter is finished processing request: " + request.toString());
            }
        }
    }

    @Nullable
    private HttpServletRequest castServletRequest(ServletRequest request) {
        try {
            return (HttpServletRequest) request;
        } catch (ClassCastException cce) {
            logger.warn("Unable to cast ServletRequest to HttpServletRequest.", cce);
        }
        return null;
    }

    @Nullable
    private HttpServletResponse castServletResponse(ServletResponse response) {
        try {
            return (HttpServletResponse) response;
        } catch (ClassCastException cce) {
            logger.warn("Unable to cast ServletResponse to HttpServletResponse.", cce);
        }
        return null;
    }

    private Optional<TraceHeader> getTraceHeader(HttpServletRequest request) {
        String traceHeaderString = request.getHeader(TraceHeader.HEADER_KEY);
        if (null != traceHeaderString) {
            return Optional.of(TraceHeader.fromString(traceHeaderString));
        }
        return Optional.empty();
    }

    private Optional<String> getHost(HttpServletRequest request) {
        return Optional.ofNullable(request.getHeader("Host"));
    }

    private Optional<String> getClientIp(HttpServletRequest request) {
        return Optional.ofNullable(request.getRemoteAddr());
    }

    private Optional<String> getXForwardedFor(HttpServletRequest request) {
        String forwarded = request.getHeader("X-Forwarded-For");
        if (forwarded != null) {
            return Optional.of(forwarded.split(",")[0].trim());
        }
        return Optional.empty();
    }

    private Optional<String> getUserAgent(HttpServletRequest request) {
        String userAgentHeaderString = request.getHeader("User-Agent");
        if (null != userAgentHeaderString) {
            return Optional.of(userAgentHeaderString);
        }
        return Optional.empty();
    }

    private Optional<Integer> getContentLength(HttpServletResponse response) {
        String contentLengthString = response.getHeader("Content-Length");
        if (null != contentLengthString && !contentLengthString.isEmpty()) {
            try {
                return Optional.of(Integer.parseInt(contentLengthString));
            } catch (NumberFormatException nfe) {
                logger.debug("Unable to parse Content-Length header from HttpServletResponse.", nfe);
            }
        }
        return Optional.empty();
    }

    private String getSegmentName(HttpServletRequest httpServletRequest) {
        if (segmentNamingStrategy == null) {
            throw new RuntimeException(
                "The AWSXRayServletFilter requires either a fixedName init-param or an instance of SegmentNamingStrategy. "
                + "Add an init-param tag to the AWSXRayServletFilter's declaration in web.xml, using param-name: 'fixedName'. "
                + "Alternatively, pass an instance of SegmentNamingStrategy to the AWSXRayServletFilter constructor.");
        }
        return segmentNamingStrategy.nameForRequest(httpServletRequest);
    }

    private SamplingResponse fromSamplingStrategy(HttpServletRequest httpServletRequest) {
        AWSXRayRecorder recorder = getRecorder();
        SamplingRequest samplingRequest = new SamplingRequest(
            getSegmentName(httpServletRequest),
            getHost(httpServletRequest).orElse(null), httpServletRequest.getRequestURI(), httpServletRequest.getMethod(),
            recorder.getOrigin());
        SamplingResponse sample = recorder.getSamplingStrategy().shouldTrace(samplingRequest);
        return sample;
    }

    private SampleDecision getSampleDecision(SamplingResponse sample) {
        if (sample.isSampled()) {
            logger.debug("Sampling strategy decided SAMPLED.");
            return SampleDecision.SAMPLED;
        } else {
            logger.debug("Sampling strategy decided NOT_SAMPLED.");
            return SampleDecision.NOT_SAMPLED;
        }
    }

    private AWSXRayRecorder getRecorder() {
        if (recorder == null) {
            recorder = AWSXRay.getGlobalRecorder();
        }
        return recorder;
    }

    public Segment preFilter(ServletRequest request, ServletResponse response) {
        AWSXRayRecorder recorder = getRecorder();
        HttpServletRequest httpServletRequest = castServletRequest(request);
        if (httpServletRequest == null) {
            logger.warn("Null value for incoming HttpServletRequest. Beginning NoOpSegment.");
            return recorder.beginNoOpSegment();
        }

        Optional<TraceHeader> incomingHeader = getTraceHeader(httpServletRequest);
        SamplingStrategy samplingStrategy = recorder.getSamplingStrategy();

        if (logger.isDebugEnabled() && incomingHeader.isPresent()) {
            logger.debug("Incoming trace header received: " + incomingHeader.get().toString());
        }

        SamplingResponse samplingResponse = fromSamplingStrategy(httpServletRequest);

        SampleDecision sampleDecision = incomingHeader.isPresent()
                                        ? incomingHeader.get().getSampled() : getSampleDecision(samplingResponse);
        if (SampleDecision.REQUESTED.equals(sampleDecision) || SampleDecision.UNKNOWN.equals(sampleDecision)) {
            sampleDecision = getSampleDecision(samplingResponse);
        }

        TraceID traceId = null;
        String parentId = null;
        if (incomingHeader.isPresent()) {
            TraceHeader header = incomingHeader.get();
            traceId = header.getRootTraceId();
            parentId = header.getParentId();
        }

        final Segment created;
        if (SampleDecision.SAMPLED.equals(sampleDecision)) {
            String segmentName = getSegmentName(httpServletRequest);
            created = traceId != null
                      ? recorder.beginSegment(segmentName, traceId, parentId)
                      : recorder.beginSegment(segmentName);
            if (samplingResponse.getRuleName().isPresent()) {
                logger.debug("Sampling strategy decided to use rule named: " + samplingResponse.getRuleName().get() + ".");
                created.setRuleName(samplingResponse.getRuleName().get());
            }
        } else { //NOT_SAMPLED
            String segmentName = getSegmentName(httpServletRequest);
            if (samplingStrategy.isForcedSamplingSupported()) {
                created = traceId != null
                          ? recorder.beginSegment(segmentName, traceId, parentId)
                          : recorder.beginSegment(segmentName);
                created.setSampled(false);
            } else {
                logger.debug("Creating Dummy Segment");
                created = traceId != null ? recorder.beginNoOpSegment(traceId) : recorder.beginNoOpSegment();
            }
        }

        Map<String, Object> requestAttributes = new HashMap<String, Object>();
        requestAttributes.put("url", httpServletRequest.getRequestURL().toString());
        requestAttributes.put("method", httpServletRequest.getMethod());

        Optional<String> userAgent = getUserAgent(httpServletRequest);
        if (userAgent.isPresent()) {
            requestAttributes.put("user_agent", userAgent.get());
        }

        Optional<String> xForwardedFor = getXForwardedFor(httpServletRequest);
        if (xForwardedFor.isPresent()) {
            requestAttributes.put("client_ip", xForwardedFor.get());
            requestAttributes.put("x_forwarded_for", true);
        } else {
            Optional<String> clientIp = getClientIp(httpServletRequest);
            if (clientIp.isPresent()) {
                requestAttributes.put("client_ip", clientIp.get());
            }
        }

        created.putHttp("request", requestAttributes);

        HttpServletResponse httpServletResponse = castServletResponse(response);
        if (httpServletResponse == null) {
            return created;
        }

        final TraceHeader responseHeader;
        if (incomingHeader.isPresent()) {
            // create a new header, and use the incoming header so we know what to do in regards to sending back the sampling
            // decision.
            responseHeader = new TraceHeader(created.getTraceId());
            if (SampleDecision.REQUESTED == incomingHeader.get().getSampled()) {
                responseHeader.setSampled(created.isSampled() ? SampleDecision.SAMPLED : SampleDecision.NOT_SAMPLED);
            }
        } else {
            // Create a new header, we're the tracing root. We wont return the sampling decision.
            responseHeader = new TraceHeader(created.getTraceId());
        }
        httpServletResponse.addHeader(TraceHeader.HEADER_KEY, responseHeader.toString());

        return created;
    }

    public void postFilter(ServletRequest request, ServletResponse response) {
        AWSXRayRecorder recorder = getRecorder();
        Segment segment = recorder.getCurrentSegment();
        if (null != segment) {
            HttpServletResponse httpServletResponse = castServletResponse(response);

            if (null != httpServletResponse) {
                Map<String, Object> responseAttributes = new HashMap<String, Object>();

                int responseCode = httpServletResponse.getStatus();
                switch (responseCode / 100) {
                    case 4:
                        segment.setError(true);
                        if (responseCode == 429) {
                            segment.setThrottle(true);
                        }
                        break;
                    case 5:
                        segment.setFault(true);
                        break;
                    default:
                        break;
                }
                responseAttributes.put("status", responseCode);


                Optional<Integer> contentLength = getContentLength(httpServletResponse);
                if (contentLength.isPresent()) {
                    responseAttributes.put("content_length", contentLength.get());
                }

                segment.putHttp("response", responseAttributes);
            }

            recorder.endSegment();
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



