WingtipsApacheHttpClientInterceptor implements HttpRequestInterceptor, HttpResponseInterceptor { @Override public void process(HttpRequest request, HttpContext context) { Tracer tracer = Tracer.getInstance(); if (surroundCallsWithSubspan) { Span spanToClose = tracer.startSpanInCurrentContext( getSubspanSpanName(request, tagAndNamingStrategy, tagAndNamingAdapter), Span.SpanPurpose.CLIENT ); tagAndNamingStrategy.handleRequestTagging(spanToClose, request, tagAndNamingAdapter); context.setAttribute(SPAN_TO_CLOSE_HTTP_CONTEXT_ATTR_KEY, spanToClose); } propagateTracingHeaders(request, tracer.getCurrentSpan()); } WingtipsApacheHttpClientInterceptor();  WingtipsApacheHttpClientInterceptor(boolean surroundCallsWithSubspan);  WingtipsApacheHttpClientInterceptor(
        boolean surroundCallsWithSubspan,
        HttpTagAndSpanNamingStrategy<HttpRequest, HttpResponse> tagAndNamingStrategy,
        HttpTagAndSpanNamingAdapter<HttpRequest, HttpResponse> tagAndNamingAdapter
    ); @Override void process(HttpRequest request, HttpContext context); @Override void process(HttpResponse response, HttpContext context); static T addTracingInterceptors(T builder); static T addTracingInterceptors(T builder, boolean surroundCallsWithSubspan); static final WingtipsApacheHttpClientInterceptor DEFAULT_IMPL; static final HttpRequestInterceptor DEFAULT_REQUEST_IMPL; static final HttpResponseInterceptor DEFAULT_RESPONSE_IMPL; }
@DataProvider(value = { "SUBSPAN_IS_NOT_AVAILABLE_IN_HTTP_CONTEXT", "SUBSPAN_IS_AVAILABLE_IN_HTTP_CONTEXT_BUT_REQUEST_IS_NOT", "SUBSPAN_AND_REQUEST_ARE_AVAILABLE_IN_HTTP_CONTEXT", "SUBSPAN_AND_REQUEST_ARE_AVAILABLE_IN_HTTP_CONTEXT_BUT_REQUEST_IS_NOT_HTTP_REQUEST" }) @Test public void process_response_works_as_expected( ProcessResponseScenario scenario ) { Span spanMock = scenario.spanMockSupplier.get(); if (spanMock != null) { httpContext.setAttribute(SPAN_TO_CLOSE_HTTP_CONTEXT_ATTR_KEY, spanMock); } Object requestObj = scenario.requestObjSupplier.get(); if (requestObj != null) { httpContext.setAttribute(HttpCoreContext.HTTP_REQUEST, requestObj); } HttpRequest expectedRequestObjForTagging = (requestObj instanceof HttpRequest) ? (HttpRequest) requestObj : null; interceptor.process(responseMock, httpContext); if (spanMock != null) { assertThat(strategyResponseTaggingAndFinalSpanNameMethodCalled.get()).isTrue(); assertThat(strategyResponseTaggingArgs.get()).isNotNull(); strategyResponseTaggingArgs.get().verifyArgs( spanMock, expectedRequestObjForTagging, responseMock, null, interceptor.tagAndNamingAdapter ); verify(spanMock).close(); } else { assertThat(strategyResponseTaggingAndFinalSpanNameMethodCalled.get()).isFalse(); assertThat(strategyResponseTaggingArgs.get()).isNull(); } }
@Test public void process_response_closes_span_no_matter_what() { Span spanMock = mock(Span.class); httpContext = spy(httpContext); httpContext.setAttribute(SPAN_TO_CLOSE_HTTP_CONTEXT_ATTR_KEY, spanMock); RuntimeException expectedEx = new RuntimeException("boom"); doThrow(expectedEx).when(httpContext).getAttribute(HttpCoreContext.HTTP_REQUEST); Throwable ex = catchThrowable(() -> interceptor.process(responseMock, httpContext)); assertThat(ex).isSameAs(expectedEx); verify(httpContext).getAttribute(HttpCoreContext.HTTP_REQUEST); verify(spanMock).close(); }