/** * @param request The incoming request. * @return A new {@link Span} for the overall request. This inspects the incoming request's headers to determine * if it should continue an existing trace with a child span, or whether a brand new trace needs to be started. * {@link #getInitialSpanName(HttpServletRequest, HttpTagAndSpanNamingStrategy, HttpTagAndSpanNamingAdapter)} * is used to generate the initial span name. */ protected Span createNewSpanForRequest(HttpServletRequest request) { // See if there's trace info in the incoming request's headers. If so it becomes the parent trace. Tracer tracer = Tracer.getInstance(); final Span parentSpan = HttpSpanFactory.fromHttpServletRequest(request, getUserIdHeaderKeys()); Span newSpan; if (parentSpan != null) { logger.debug("Found parent Span {}", parentSpan); newSpan = tracer.startRequestWithChildSpan( parentSpan, getInitialSpanName(request, tagAndNamingStrategy, tagAndNamingAdapter) ); } else { newSpan = tracer.startRequestWithRootSpan( getInitialSpanName(request, tagAndNamingStrategy, tagAndNamingAdapter), HttpSpanFactory.getUserIdFromHttpServletRequest(request, getUserIdHeaderKeys()) ); logger.debug("Parent span not found, starting a new span {}", newSpan); } return newSpan; }
@DataProvider(value = { // Name from strategy always wins "someStrategyName | GET | /some/http/route | someStrategyName", // Null/blank name from strategy defers to HttpSpanFactory.getSpanName(). "null | GET | /some/http/route | GET /some/http/route", " | GET | /some/http/route | GET /some/http/route", "[whitespace] | GET | /some/http/route | GET /some/http/route", "null | null | /some/http/route | UNKNOWN_HTTP_METHOD /some/http/route", "null | null | null | UNKNOWN_HTTP_METHOD" }, splitBy = "\\|") @Test public void getInitialSpanName_works_as_expected( String strategyResult, String httpMethod, String httpRoute, String expectedResult ) { // given RequestTracingFilter filter = getBasicFilter(); if ("[whitespace]".equals(strategyResult)) { strategyResult = " \t\r\n "; } initialSpanNameFromStrategy.set(strategyResult); doReturn(httpMethod).when(requestMock).getMethod(); doReturn(httpRoute).when(requestMock).getAttribute(KnownZipkinTags.HTTP_ROUTE); // when String result = filter.getInitialSpanName(requestMock, tagAndNamingStrategy, tagAndNamingAdapterMock); // then assertThat(result).isEqualTo(expectedResult); assertThat(strategyInitialSpanNameMethodCalled.get()).isTrue(); strategyInitialSpanNameArgs.get().verifyArgs(requestMock, tagAndNamingAdapterMock); }
@DataProvider(value = { "true", "false" }) @Test public void doFilterInternal_should_use_getInitialSpanName_for_span_name( boolean parentSpanExists ) throws ServletException, IOException { // given RequestTracingFilter filterSpy = spy(getBasicFilter()); filterSpy.tagAndNamingStrategy = tagAndNamingStrategy; filterSpy.tagAndNamingAdapter = tagAndNamingAdapterMock; String expectedSpanName = UUID.randomUUID().toString(); doReturn(expectedSpanName).when(filterSpy).getInitialSpanName( any(HttpServletRequest.class), any(HttpTagAndSpanNamingStrategy.class), any(HttpTagAndSpanNamingAdapter.class) ); if (parentSpanExists) { given(requestMock.getHeader(TraceHeaders.TRACE_ID)).willReturn(TraceAndSpanIdGenerator.generateId()); given(requestMock.getHeader(TraceHeaders.SPAN_ID)).willReturn(TraceAndSpanIdGenerator.generateId()); } // when filterSpy.doFilterInternal(requestMock, responseMock, spanCapturingFilterChain); // then assertThat(spanCapturingFilterChain.captureSpanCopyAtTimeOfDoFilter).isNotNull(); assertThat(spanCapturingFilterChain.captureSpanCopyAtTimeOfDoFilter.getSpanName()).isEqualTo(expectedSpanName); verify(filterSpy).getInitialSpanName(requestMock, tagAndNamingStrategy, tagAndNamingAdapterMock); }
assertThat(newSpan.getParentSpanId()).isEqualTo(parentSpan.getSpanId()); assertThat(newSpan.getSpanName()).isEqualTo( filter.getInitialSpanName(requestMock, filter.tagAndNamingStrategy, filter.tagAndNamingAdapter) ); assertThat(newSpan.isSampleable()).isEqualTo(parentSpan.isSampleable());