HttpRequestTracingUtils { public static Span fromRequestWithHeaders(RequestWithHeaders request, List<String> userIdHeaderKeys) { if (request == null) return null; String traceId = getTraceId(request); if (traceId == null) return null; String spanName = getHeaderWithAttributeAsBackup(request, TraceHeaders.SPAN_NAME); if (spanName == null || spanName.length() == 0) spanName = UNSPECIFIED_SPAN_NAME; String spanIdFromRequest = getSpanId(request); Span.Builder spanBuilder = Span.newBuilder(spanName, SpanPurpose.CLIENT) .withTraceId(traceId) .withParentSpanId(getParentSpanId(request)) .withSpanId(spanIdFromRequest) .withSampleable(getSpanSampleableFlag(request)) .withUserId(getUserIdFromRequestWithHeaders(request, userIdHeaderKeys)); if (spanIdFromRequest == null) { spanBuilder.withTag(SPAN_FROM_HEADERS_WHERE_CALLER_DID_NOT_SEND_SPAN_ID_TAG_KEY, "true"); } return spanBuilder.build(); } private  HttpRequestTracingUtils(); static Span fromRequestWithHeaders(RequestWithHeaders request, List<String> userIdHeaderKeys); static boolean hasInvalidSpanIdBecauseCallerDidNotSendOne(Span span); static boolean hasInvalidParentIdBecauseCallerDidNotSendSpanId(Span span); static String getUserIdFromRequestWithHeaders(RequestWithHeaders request, List<String> userIdHeaderKeys); static void propagateTracingHeaders(HttpObjectForPropagation httpObjectForPropagation, Span span); static String convertSampleableBooleanToExpectedB3Value(boolean sampleable); @SuppressWarnings("ConstantConditions") static @NotNull String generateSafeSpanName(
        @Nullable REQ request,
        @Nullable RES response,
        @NotNull HttpTagAndSpanNamingAdapter<REQ, RES> adapter
    ); static @NotNull String generateSafeSpanName(
        @Nullable String requestHttpMethod,
        @Nullable String pathTemplate,
        @Nullable Integer responseStatusCode
    ); static @NotNull String getFallbackSpanNameForHttpRequest(
        @Nullable String prefix,
        @Nullable String httpMethod
    ); static final String UNSPECIFIED_SPAN_NAME; static final String SPAN_FROM_HEADERS_WHERE_CALLER_DID_NOT_SEND_SPAN_ID_TAG_KEY; static final String CHILD_OF_SPAN_FROM_HEADERS_WHERE_CALLER_DID_NOT_SEND_SPAN_ID_TAG_KEY; }
@Test public void fromRequestWithHeaders_returns_null_if_passed_null_request() { assertThat(HttpRequestTracingUtils.fromRequestWithHeaders(null, USER_ID_HEADER_KEYS)).isNull(); }
@Test public void fromRequestWithHeaders_returns_null_if_request_is_missing_trace_id_header() { given(request.getHeader(TraceHeaders.TRACE_ID)).willReturn(null); given(request.getHeader(TraceHeaders.TRACE_SAMPLED)).willReturn(null); given(request.getHeader(TraceHeaders.SPAN_ID)).willReturn(null); given(request.getHeader(TraceHeaders.PARENT_SPAN_ID)).willReturn(null); Span newSpan = HttpRequestTracingUtils.fromRequestWithHeaders(request, USER_ID_HEADER_KEYS); assertThat(newSpan).isNull(); }
@Test @UseDataProvider("nullAndEmptyStrings") public void fromRequestWithHeaders_sets_span_name_to_unspecified_value_if_span_name_is_missing_or_empty(String nullOrEmptySpanName) { given(request.getHeader(TraceHeaders.TRACE_ID)).willReturn(UUID.randomUUID().toString()); given(request.getHeader(TraceHeaders.SPAN_NAME)).willReturn(nullOrEmptySpanName); given(request.getAttribute(TraceHeaders.SPAN_NAME)).willReturn(nullOrEmptySpanName); Span result = HttpRequestTracingUtils.fromRequestWithHeaders(request, USER_ID_HEADER_KEYS); assertThat(result.getSpanName()).isEqualTo(HttpRequestTracingUtils.UNSPECIFIED_SPAN_NAME); }
@Test @UseDataProvider("nullAndEmptyStrings") public void fromRequestWithHeaders_sets_sampleable_to_true_if_sampled_header_is_null_or_missing_from_both_headers_and_attributes(String nullOrEmptySampledString) { given(request.getHeader(TraceHeaders.TRACE_ID)).willReturn(sampleTraceID); given(request.getHeader(TraceHeaders.TRACE_SAMPLED)).willReturn(nullOrEmptySampledString); given(request.getAttribute(TraceHeaders.TRACE_SAMPLED)).willReturn(nullOrEmptySampledString); Span newSpan = HttpRequestTracingUtils.fromRequestWithHeaders(request, USER_ID_HEADER_KEYS); assertThat(newSpan.isSampleable()).isTrue(); }
@Test public void fromRequestWithHeaders_sets_sampleable_to_attribute_value_if_sampled_header_is_missing_but_attribute_exists() { given(request.getHeader(TraceHeaders.TRACE_ID)).willReturn(sampleTraceID); given(request.getHeader(TraceHeaders.TRACE_SAMPLED)).willReturn(null); given(request.getAttribute(TraceHeaders.TRACE_SAMPLED)).willReturn(false); Span newSpan = HttpRequestTracingUtils.fromRequestWithHeaders(request, USER_ID_HEADER_KEYS); assertThat(newSpan.isSampleable()).isFalse(); }
@Test public void fromRequestWithHeaders_sets_sampleable_to_attribute_value_if_sampled_header_is_empty_but_attribute_exists() { given(request.getHeader(TraceHeaders.TRACE_ID)).willReturn(sampleTraceID); given(request.getHeader(TraceHeaders.TRACE_SAMPLED)).willReturn(" "); given(request.getAttribute(TraceHeaders.TRACE_SAMPLED)).willReturn(false); Span newSpan = HttpRequestTracingUtils.fromRequestWithHeaders(request, USER_ID_HEADER_KEYS); assertThat(newSpan.isSampleable()).isFalse(); }
@DataProvider(value = { "0 | false", "1 | true", "2 | true", "42 | true", "false | false", "FALSE | false", "FaLsE | false", "true | true", "TRUE | true", "TrUe | true", "true | true", "bad | true", }, splitBy = "\\|") @Test public void fromRequestWithHeaders_extracts_sampleable_as_expected(String receivedValue, boolean expectedSampleableResult) { { given(request.getHeader(TraceHeaders.TRACE_ID)).willReturn(sampleTraceID); given(request.getHeader(TraceHeaders.TRACE_SAMPLED)).willReturn(receivedValue); given(request.getAttribute(TraceHeaders.TRACE_SAMPLED)).willReturn(null); Span newSpan = HttpRequestTracingUtils.fromRequestWithHeaders(request, USER_ID_HEADER_KEYS); assertThat(newSpan.isSampleable()).isEqualTo(expectedSampleableResult); } { given(request.getHeader(TraceHeaders.TRACE_ID)).willReturn(sampleTraceID); given(request.getHeader(TraceHeaders.TRACE_SAMPLED)).willReturn(null); given(request.getAttribute(TraceHeaders.TRACE_SAMPLED)).willReturn(receivedValue); Span newSpan = HttpRequestTracingUtils.fromRequestWithHeaders(request, USER_ID_HEADER_KEYS); assertThat(newSpan.isSampleable()).isEqualTo(expectedSampleableResult); } }