.withParentSpanId(parentSpanId) .withSpanName(spanName) .withSampleable(sampleableForFullyCompleteSpan) .withUserId(userId) .withSpanPurpose(spanPurpose)
/** * @param spanName The {@link Span#getSpanName()} to use for the new child sub-span. * @param spanPurpose The {@link SpanPurpose} for the new child span. See the javadocs for {@link SpanPurpose} for full details on what each enum option * means. If you pass in null for this then {@link SpanPurpose#UNKNOWN} will be used. * @return A new uncompleted span representing a child of this instance. The returned instance's {@link #getParentSpanId()} will be this instance's * {@link #getSpanId()}, its {@link #getSpanName()} will be the given value, its {@link #getSpanId()} will be randomly generated, and its * {@link #getSpanStartTimeEpochMicros()} and {@link #getSpanStartTimeNanos()} values will be set to the appropriate values based on when this * method is called. It will share this instance's {@link #getTraceId()}, {@link #isSampleable()}, and {@link #getUserId()} values. */ public Span generateChildSpan(String spanName, SpanPurpose spanPurpose) { return Span.newBuilder(spanName, spanPurpose) .withTraceId(this.getTraceId()) .withSampleable(this.isSampleable()) .withUserId(this.getUserId()) .withParentSpanId(this.getSpanId()) .withSpanId(TraceAndSpanIdGenerator.generateId()) .withSpanStartTimeEpochMicros(TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis())) .withSpanStartTimeNanos(System.nanoTime()) .withDurationNanos(null) .build(); }
@Test public void doFilterInternal_should_use_user_id_from_parent_span_info_if_present_in_request_headers( ) throws ServletException, IOException { // given: filter and request that has parent span info RequestTracingFilter spyFilter = spy(getBasicFilter()); given(requestMock.getHeader(ALT_USER_ID_HEADER_KEY)).willReturn("testUserId"); Span parentSpan = Span.newBuilder("someParentSpan", null) .withParentSpanId(TraceAndSpanIdGenerator.generateId()) .withSampleable(false) .withUserId("someUser") .build(); given(requestMock.getHeader(TraceHeaders.TRACE_ID)).willReturn(parentSpan.getTraceId()); given(requestMock.getHeader(TraceHeaders.SPAN_ID)).willReturn(parentSpan.getSpanId()); given(requestMock.getHeader(TraceHeaders.PARENT_SPAN_ID)).willReturn(parentSpan.getParentSpanId()); given(requestMock.getHeader(TraceHeaders.SPAN_NAME)).willReturn(parentSpan.getSpanName()); given(requestMock.getHeader(TraceHeaders.TRACE_SAMPLED)).willReturn(String.valueOf(parentSpan.isSampleable())); given(requestMock.getServletPath()).willReturn("/some/path"); given(requestMock.getMethod()).willReturn("GET"); // when: doFilterInternal is called spyFilter.doFilterInternal(requestMock, responseMock, spanCapturingFilterChain); // then: the span that is created should use the parent span info as its parent assertThat(spanCapturingFilterChain.capturedSpan).isNotNull(); Span newSpan = spanCapturingFilterChain.capturedSpan; assertThat(newSpan.getUserId()).isEqualTo("testUserId"); }
) { Span origCallSpan = Span.newBuilder("origCall", Span.SpanPurpose.CLIENT) .withSampleable(sampled) .build(); Map<String, String> tracingHeaders = new HashMap<>();
.withParentSpanId(getSpanIdFromRequest(request, TraceHeaders.PARENT_SPAN_ID, false)) .withSpanId(getSpanIdFromRequest(request, TraceHeaders.SPAN_ID, true)) .withSampleable(getSpanSampleableFlag(request)) .withUserId(getUserIdFromRequestWithHeaders(request, userIdHeaderKeys)) .build();
: Span.generateRootSpanForNewTrace(spanName, spanPurpose).withSampleable(isNextRootSpanSampleable()).build();
Span parentSpan = Span.newBuilder("someParentSpan", null) .withParentSpanId(TraceAndSpanIdGenerator.generateId()) .withSampleable(false) .withUserId("someUser") .build();
.withTraceId(traceId) .withParentSpanId(parentSpanId) .withSampleable(sampleable) .withUserId(userId) .build();
@DataProvider(value = { "true", "false" }) @Test public void propagateTracingHeaders_uses_B3_spec_for_sampleable_header_value( boolean sampleable ) { // given Span span = Span.newBuilder("foo", SpanPurpose.CLIENT) .withSampleable(sampleable) .build(); // when WingtipsSpringUtil.propagateTracingHeaders(httpMessageMock, span); // then verify(headersMock).set(TRACE_SAMPLED, convertSampleableBooleanToExpectedB3Value(span.isSampleable())); }
@DataProvider(value = { "true", "false" }) @Test public void propagateTracingHeaders_uses_B3_spec_for_sampleable_header_value( boolean sampleable ) { // given Span span = Span.newBuilder("foo", SpanPurpose.CLIENT) .withSampleable(sampleable) .build(); // when HttpRequestTracingUtils.propagateTracingHeaders(httpObjectForPropagationMock, span); // then verify(httpObjectForPropagationMock) .setHeader(TRACE_SAMPLED, convertSampleableBooleanToExpectedB3Value(span.isSampleable())); }
@DataProvider(value = { "true", "false" }) @Test public void propagateTracingHeaders_uses_B3_spec_for_sampleable_header_value( boolean sampleable ) { // given Span span = Span.newBuilder("foo", Span.SpanPurpose.CLIENT) .withSampleable(sampleable) .build(); // when WingtipsApacheHttpClientUtil.propagateTracingHeaders(requestMock, span); // then verify(requestMock) .setHeader(TRACE_SAMPLED, convertSampleableBooleanToExpectedB3Value(span.isSampleable())); }