/** * Helper method for adding tracing-related request attributes to the given request based on the given span. * * @param span The span for the overall request. * @param request The request object to add tracing-related request attributes to. */ protected void addTracingInfoToRequestAttributes(Span span, HttpServletRequest request) { request.setAttribute(TraceHeaders.TRACE_SAMPLED, span.isSampleable()); request.setAttribute(TraceHeaders.TRACE_ID, span.getTraceId()); request.setAttribute(TraceHeaders.SPAN_ID, span.getSpanId()); request.setAttribute(TraceHeaders.PARENT_SPAN_ID, span.getParentSpanId()); request.setAttribute(TraceHeaders.SPAN_NAME, span.getSpanName()); request.setAttribute(Span.class.getName(), span); }
private Span findCompletedSpan(String expectedSpanName, String expectedSpanHandler) { return spanRecorder.completedSpans .stream() .filter( s -> s.getSpanName().equals(expectedSpanName) && expectedSpanHandler.equals(s.getTags().get(WingtipsTags.SPAN_HANDLER)) ) .findFirst() .orElseThrow( () -> new RuntimeException( "Unable to find span with expected span name: " + expectedSpanName + " and span handler: " + expectedSpanHandler ) ); }
@Test public void changeSpanName_works_as_expected() { // given Span span = Span.newBuilder("origSpanName", Span.SpanPurpose.SERVER).build(); String newSpanName = UUID.randomUUID().toString(); assertThat(span.getSpanName()).isNotEqualTo(newSpanName); // when SpanMutator.changeSpanName(span, newSpanName); // then assertThat(span.getSpanName()).isEqualTo(newSpanName); }
@Test public void setSpanName_works_as_expected() { // given Span span = Span.newBuilder("origSpanName", SpanPurpose.SERVER).build(); String newSpanName = UUID.randomUUID().toString(); assertThat(span.getSpanName()).isNotEqualTo(newSpanName); // when span.setSpanName(newSpanName); // then assertThat(span.getSpanName()).isEqualTo(newSpanName); }
@Test public void getCurrentSpan_should_return_current_span() throws Exception { // given Tracer tracer = Tracer.getInstance(); tracer.startRequestWithRootSpan("test-span"); // when Span span = tracer.getCurrentSpan(); // then assertThat(span).isNotNull(); assertThat(span.getSpanName()).isEqualTo("test-span"); }
@Test public void doFilterInternal_should_set_request_attributes_to_new_span_info() throws ServletException, IOException { // given: filter RequestTracingFilter filter = getBasicFilter(); // when: doFilterInternal is called filter.doFilterInternal(requestMock, responseMock, spanCapturingFilterChain); // then: request attributes should be set with the new span's info assertThat(spanCapturingFilterChain.capturedSpan).isNotNull(); Span newSpan = spanCapturingFilterChain.capturedSpan; verify(requestMock).setAttribute(TraceHeaders.TRACE_SAMPLED, newSpan.isSampleable()); verify(requestMock).setAttribute(TraceHeaders.TRACE_ID, newSpan.getTraceId()); verify(requestMock).setAttribute(TraceHeaders.SPAN_ID, newSpan.getSpanId()); verify(requestMock).setAttribute(TraceHeaders.PARENT_SPAN_ID, newSpan.getParentSpanId()); verify(requestMock).setAttribute(TraceHeaders.SPAN_NAME, newSpan.getSpanName()); verify(requestMock).setAttribute(Span.class.getName(), newSpan); }
@Test public void doDetermineAndSetFinalSpanName_delegates_to_adapter_getFinalSpanName_and_changes_span_name_if_result_is_not_blank() { // given String adapterSpanNameResult = UUID.randomUUID().toString(); doReturn(adapterSpanNameResult).when(adapterMock).getFinalSpanName(anyObject(), anyObject()); Span span = Span.newBuilder("originalSpanName", SpanPurpose.SERVER).build(); assertThat(span.getSpanName()).isNotEqualTo(adapterSpanNameResult); // when implSpy.doDetermineAndSetFinalSpanName(span, requestObjectMock, responseObjectMock, errorMock, adapterMock); // then assertThat(span.getSpanName()).isEqualTo(adapterSpanNameResult); verify(adapterMock).getFinalSpanName(requestObjectMock, responseObjectMock); }
@Test public void startRequestWithRootSpan_wipes_out_any_existing_spans_on_the_stack() { // given: Tracer already has some Spans on the stack Tracer.getInstance().startRequestWithRootSpan("span1"); Tracer.getInstance().startSubSpan("span2", SpanPurpose.LOCAL_ONLY); assertThat(getSpanStackSize()).isEqualTo(2); // when: Tracer.startRequestWithRootSpan(String) is called to start a span without a parent Tracer.getInstance().startRequestWithRootSpan("noparent"); // then: a new span is started for it, and the other spans on the stack are removed assertThat(getSpanStackSize()).isEqualTo(1); Span span = Tracer.getInstance().getCurrentSpan(); assertThat(span).isNotNull(); assertThat(span.getSpanName()).isEqualTo("noparent"); }
@Test @UseDataProvider("spanStackDataProvider") public void starting_a_request_should_reset_span_stack_no_matter_what_the_span_stack_already_looked_like(Deque<Span> stackToUse) { // given getSpanStackThreadLocal().set(stackToUse); assertThat(getSpanStackFromTracer()).isSameAs(stackToUse); String newRequestSpanName = UUID.randomUUID().toString(); // when Span newRequestSpan = Tracer.getInstance().startRequestWithRootSpan(newRequestSpanName); // then assertThat(getSpanStackFromTracer()).isNotSameAs(stackToUse); assertThat(getSpanStackSize()).isEqualTo(1); assertThat(Tracer.getInstance().getCurrentSpan()).isEqualTo(newRequestSpan); assertThat(Tracer.getInstance().getCurrentSpan().getSpanName()).isEqualTo(newRequestSpanName); }
@Test public void completeSubSpan_should_do_nothing_if_there_is_only_one_span_on_the_stack() { // given: a single span on the stack Tracer.getInstance().startRequestWithRootSpan("somespan"); assertThat(Tracer.getInstance().getCurrentSpan()).isNotNull(); assertThat(getSpanStackSize()).isEqualTo(1); Span span = Tracer.getInstance().getCurrentSpan(); assertThat(span).isNotNull(); assertThat(span.getSpanName()).isEqualTo("somespan"); // when: completeSubSpan() is called Tracer.getInstance().completeSubSpan(); // then: nothing should be done because the stack only has one thing on it and completeSubSpan() requires at least two spans assertThat(span.isCompleted()).isFalse(); assertThat(Tracer.getInstance().getCurrentSpan()).isSameAs(span); assertThat(getSpanStackSize()).isEqualTo(1); }
@Test public void equals_returns_false_and_hashCode_different_if_spanName_is_different() { // given Span fullSpan1 = createFilledOutSpan(true); Span fullSpan2 = createFilledOutSpan(true); Whitebox.setInternalState(fullSpan2, "spanName", fullSpan1.getSpanName() + "_nope"); // expect assertThat(fullSpan1.equals(fullSpan2)).isFalse(); assertThat(fullSpan1.hashCode()).isNotEqualTo(fullSpan2.hashCode()); }
@Test public void startRequestWithChildSpan_wipes_out_any_existing_spans_on_the_stack() { // given: Tracer already has some Spans on the stack, and we have a parent span we're going to use Tracer.getInstance().startRequestWithRootSpan("span1"); Tracer.getInstance().startSubSpan("span2", SpanPurpose.LOCAL_ONLY); assertThat(getSpanStackSize()).isEqualTo(2); Span newSpanParent = Span.generateRootSpanForNewTrace("parentspan", SpanPurpose.CLIENT).build(); // when: Tracer.startRequestWithChildSpan(Span, String) is called to start a span with a parent Tracer.getInstance().startRequestWithChildSpan(newSpanParent, "childspan"); // then: a new span is started that has the given parent, and the other spans on the stack are removed assertThat(getSpanStackSize()).isEqualTo(1); Span span = Tracer.getInstance().getCurrentSpan(); assertThat(span).isNotNull(); assertThat(span.getSpanName()).isEqualTo("childspan"); }
@Test @UseDataProvider("nullAndEmptyStrings") public void fromRequestWithHeaders_sets_span_name_to_unspecified_value_if_span_name_is_missing_or_empty(String nullOrEmptySpanName) { // given 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); // when Span result = HttpRequestTracingUtils.fromRequestWithHeaders(request, USER_ID_HEADER_KEYS); // then assertThat(result.getSpanName()).isEqualTo(HttpRequestTracingUtils.UNSPECIFIED_SPAN_NAME); }
@Override public zipkin.Span convertWingtipsSpanToZipkinSpan(Span wingtipsSpan, Endpoint zipkinEndpoint, String localComponentNamespace) { String traceId = wingtipsSpan.getTraceId(); long startEpochMicros = wingtipsSpan.getSpanStartTimeEpochMicros(); long durationMicros = TimeUnit.NANOSECONDS.toMicros(wingtipsSpan.getDurationNanos()); zipkin.Span.Builder builder = createNewZipkinSpanBuilderWithSpanPurposeAnnotations(wingtipsSpan, startEpochMicros, durationMicros, zipkinEndpoint, localComponentNamespace) .id(nullSafeLong(wingtipsSpan.getSpanId())) .name(wingtipsSpan.getSpanName()) .parentId(nullSafeLong(wingtipsSpan.getParentSpanId())) .timestamp(startEpochMicros) .traceIdHigh(traceId.length() == 32 ? nullSafeLong(traceId, 0) : 0) .traceId(nullSafeLong(traceId)) .duration(durationMicros); addAllTagsToBuilderAsBinaryAnnotations(builder, wingtipsSpan.getTags(), zipkinEndpoint); addAllAnnotationsToBuilder(builder, wingtipsSpan.getTimestampedAnnotations(), zipkinEndpoint); return builder.build(); }
private Pair<Span, Map<String, String>> generateUpstreamSpanHeaders() { Span span = Span.newBuilder("upstreamSpan", Span.SpanPurpose.CLIENT).build(); Map<String, String> headers = MapBuilder .builder(TraceHeaders.TRACE_ID, span.getTraceId()) .put(TraceHeaders.SPAN_ID, span.getSpanId()) .put(TraceHeaders.SPAN_NAME, span.getSpanName()) .put(TraceHeaders.TRACE_SAMPLED, String.valueOf(span.isSampleable())) .build(); return Pair.of(span, headers); }
private Pair<Span, Map<String, String>> generateUpstreamSpanHeaders() { Span span = Span.newBuilder("upstreamSpan", Span.SpanPurpose.CLIENT).build(); Map<String, String> headers = MapBuilder .builder(TraceHeaders.TRACE_ID, span.getTraceId()) .put(TraceHeaders.SPAN_ID, span.getSpanId()) .put(TraceHeaders.SPAN_NAME, span.getSpanName()) .put(TraceHeaders.TRACE_SAMPLED, String.valueOf(span.isSampleable())) .build(); return Pair.of(span, headers); }
private Pair<Span, Map<String, String>> generateUpstreamSpanHeaders(boolean includeUserId) { Span.Builder spanBuilder = Span.newBuilder("upstreamSpan", Span.SpanPurpose.CLIENT); if (includeUserId) { spanBuilder.withUserId("user-" + UUID.randomUUID().toString()); } Span span = spanBuilder.build(); MapBuilder<String, String> headersBuilder = MapBuilder .builder(TraceHeaders.TRACE_ID, span.getTraceId()) .put(TraceHeaders.SPAN_ID, span.getSpanId()) .put(TraceHeaders.SPAN_NAME, span.getSpanName()) .put(TraceHeaders.TRACE_SAMPLED, String.valueOf(span.isSampleable())); if (span.getUserId() != null) { headersBuilder.put(USER_ID_HEADER_KEY, span.getUserId()); } return Pair.of(span, headersBuilder.build()); }
private Pair<Span, Map<String, String>> generateUpstreamSpanHeaders(boolean includeUserId) { Span.Builder spanBuilder = Span.newBuilder("upstreamSpan", Span.SpanPurpose.CLIENT); if (includeUserId) { spanBuilder.withUserId("user-" + UUID.randomUUID().toString()); } Span span = spanBuilder.build(); MapBuilder<String, String> headersBuilder = MapBuilder .builder(TraceHeaders.TRACE_ID, span.getTraceId()) .put(TraceHeaders.SPAN_ID, span.getSpanId()) .put(TraceHeaders.SPAN_NAME, span.getSpanName()) .put(TraceHeaders.TRACE_SAMPLED, String.valueOf(span.isSampleable())); if (span.getUserId() != null) { headersBuilder.put(USER_ID_HEADER_KEY, span.getUserId()); } return Pair.of(span, headersBuilder.build()); }
private Pair<Span, Map<String, String>> generateUpstreamSpanHeaders() { Span span = Span.newBuilder("upstreamSpan", Span.SpanPurpose.CLIENT).build(); Map<String, String> headers = MapBuilder .builder(TraceHeaders.TRACE_ID, span.getTraceId()) .put(TraceHeaders.SPAN_ID, span.getSpanId()) .put(TraceHeaders.SPAN_NAME, span.getSpanName()) .put(TraceHeaders.TRACE_SAMPLED, String.valueOf(span.isSampleable())) .build(); return Pair.of(span, headers); }
private Pair<Span, Map<String, String>> generateUpstreamSpanHeaders() { Span span = Span.newBuilder("upstreamSpan", Span.SpanPurpose.CLIENT).build(); Map<String, String> headers = MapBuilder .builder(TraceHeaders.TRACE_ID, span.getTraceId()) .put(TraceHeaders.SPAN_ID, span.getSpanId()) .put(TraceHeaders.SPAN_NAME, span.getSpanName()) .put(TraceHeaders.TRACE_SAMPLED, String.valueOf(span.isSampleable())) .build(); return Pair.of(span, headers); }