/** * Calls {@link Tracer#unregisterFromThread()} and {@link MDC#clear()} to reset this thread's tracing and * MDC state to be completely clean, then (optionally) resets the span stack and MDC info to the arguments * provided. If the span stack argument is null then the span stack will *not* be reset, and similarly if the MDC * info is null then the MDC info will *not* be reset. So if both are null then when this method finishes the trace * stack and MDC will be left in a blank state. * * @deprecated Please move to the Java 8 version of this class and method ({@code AsyncWingtipsHelper} or the static * {@code AsyncWingtipsHelperStatic}) whenever possible. */ @Deprecated public static void unlinkTracingFromCurrentThread(Deque<Span> spanStackToResetFor, Map<String, String> mdcContextMapToResetFor) { Tracer.getInstance().unregisterFromThread(); MDC.clear(); if (mdcContextMapToResetFor != null) MDC.setContextMap(mdcContextMapToResetFor); if (spanStackToResetFor != null) Tracer.getInstance().registerWithThread(spanStackToResetFor); }
/** * Calls {@link Tracer#unregisterFromThread()} and {@link org.slf4j.MDC#clear()} to reset this thread's tracing and * MDC state to be completely clean, then (optionally) resets the trace stack and MDC info to the arguments * provided. If the trace stack argument is null then the trace stack will *not* be reset, and similarly if the MDC * info is null then the MDC info will *not* be reset. So if both are null then when this method finishes the trace * stack and MDC will be left in a blank state. */ public static void unlinkTracingAndMdcFromCurrentThread(Deque<Span> distributedTraceStackToResetFor, Map<String, String> mdcContextMapToResetFor) { Tracer.getInstance().unregisterFromThread(); MDC.clear(); if (mdcContextMapToResetFor != null) MDC.setContextMap(mdcContextMapToResetFor); if (distributedTraceStackToResetFor != null) Tracer.getInstance().registerWithThread(distributedTraceStackToResetFor); }
/** * Calls {@link Tracer#unregisterFromThread()} and {@link org.slf4j.MDC#clear()} to reset this thread's tracing and * MDC state to be completely clean, then (optionally) resets the trace stack and MDC info to the arguments * provided. If the trace stack argument is null then the trace stack will *not* be reset, and similarly if the MDC * info is null then the MDC info will *not* be reset. So if both are null then when this method finishes the trace * stack and MDC will be left in a blank state. */ public static void unlinkTracingAndMdcFromCurrentThread(Deque<Span> distributedTraceStackToResetFor, Map<String, String> mdcContextMapToResetFor) { Tracer.getInstance().unregisterFromThread(); MDC.clear(); if (mdcContextMapToResetFor != null) MDC.setContextMap(mdcContextMapToResetFor); if (distributedTraceStackToResetFor != null) Tracer.getInstance().registerWithThread(distributedTraceStackToResetFor); }
@Test public void doChannelRead_does_not_propagate_errors_if_unexpected_exceptions_occur_during_endpoint_timing_annotations() { // given Span spanMock = mock(Span.class); Tracer.getInstance().registerWithThread(new ArrayDeque<>(Collections.singleton(spanMock))); assertThat(Tracer.getInstance().getCurrentSpan()).isEqualTo(spanMock); TracingState tracingStateForTest = TracingState.getCurrentThreadTracingState(); doReturn(tracingStateForTest.getLeft()).when(stateMock).getDistributedTraceStack(); doReturn(tracingStateForTest.getRight()).when(stateMock).getLoggerMdcContextMap(); doReturn(true).when(taggingStrategySpy).shouldAddEndpointStartAnnotation(); doThrow(new RuntimeException("intentional exception")).when(taggingStrategySpy).endpointStartAnnotationName(); doReturn(true).when(taggingStrategySpy).shouldAddEndpointFinishAnnotation(); doThrow(new RuntimeException("intentional exception")).when(taggingStrategySpy).endpointFinishAnnotationName(); ResponseInfo<?> responseInfoMock = mock(ResponseInfo.class); // when handlerSpy.doChannelRead(ctxMock, msg); futureThatWillBeAttachedToSpy.complete(responseInfoMock); Object result = futureThatWillBeAttachedToSpy.join(); // then verify(taggingStrategySpy).endpointStartAnnotationName(); verify(taggingStrategySpy).endpointFinishAnnotationName(); assertThat(result).isSameAs(responseInfoMock); // We verified that the methods were called that would have thrown exceptions, and nothing propagated. So // we're good. }
@Test public void registerWithThread_should_do_nothing_if_copy_of_same_stack_is_passed_in() { // given Tracer tracer = Tracer.getInstance(); tracer.startRequestWithRootSpan("foo"); Span subspan = tracer.startSubSpan("bar", SpanPurpose.LOCAL_ONLY); assertThat(MDC.get(Tracer.TRACE_ID_MDC_KEY)).isEqualTo(subspan.getTraceId()); assertThat(MDC.get(Tracer.SPAN_JSON_MDC_KEY)).isEqualTo(subspan.toJSON()); // when Deque<Span> spanStack = getSpanStackThreadLocal().get(); tracer.registerWithThread(new LinkedList<>(spanStack)); // then assertThat(getSpanStackThreadLocal().get()).isEqualTo(spanStack); assertThat(MDC.get(Tracer.TRACE_ID_MDC_KEY)).isEqualTo(subspan.getTraceId()); assertThat(MDC.get(Tracer.SPAN_JSON_MDC_KEY)).isEqualTo(subspan.toJSON()); }
@Test public void doChannelInactive_does_not_try_to_recomplete_span_if_already_completed() throws Exception { // given Span span = setupTracingForChannelInactive(false); Deque<Span> deque = new LinkedList<>(); deque.add(span); Tracer.getInstance().registerWithThread(deque); Tracer.getInstance().completeRequestSpan(); Assertions.assertThat(span.isCompleted()).isTrue(); long durationNanosBefore = span.getDurationNanos(); // when PipelineContinuationBehavior result = handler.doChannelInactive(ctxMock); // then Assertions.assertThat(span.isCompleted()).isTrue(); // no change Assertions.assertThat(span.getDurationNanos()).isEqualTo(durationNanosBefore); verify(requestInfoMock).releaseAllResources(); verify(proxyRouterStateMock).cancelRequestStreaming(any(), any()); verify(proxyRouterStateMock).cancelDownstreamRequest(any()); Assertions.assertThat(result).isEqualTo(PipelineContinuationBehavior.CONTINUE); }
@Test public void registerWithThread_should_do_nothing_if_same_stack_is_passed_in() { // given Tracer tracer = Tracer.getInstance(); tracer.startRequestWithRootSpan("foo"); Span subspan = tracer.startSubSpan("bar", SpanPurpose.LOCAL_ONLY); assertThat(MDC.get(Tracer.TRACE_ID_MDC_KEY)).isEqualTo(subspan.getTraceId()); assertThat(MDC.get(Tracer.SPAN_JSON_MDC_KEY)).isEqualTo(subspan.toJSON()); // when Deque<Span> spanStack = getSpanStackThreadLocal().get(); tracer.registerWithThread(spanStack); // then assertThat(getSpanStackThreadLocal().get()).isEqualTo(spanStack); assertThat(MDC.get(Tracer.TRACE_ID_MDC_KEY)).isEqualTo(subspan.getTraceId()); assertThat(MDC.get(Tracer.SPAN_JSON_MDC_KEY)).isEqualTo(subspan.toJSON()); }
MDC.setContextMap(mdcContextMapToLink); Tracer.getInstance().registerWithThread(spanStackToLink);
@Test public void registerWithThread_should_reset_everything_if_passed_empty_instance() { // given Tracer tracer = Tracer.getInstance(); tracer.startRequestWithRootSpan("foo"); Span subspan = tracer.startSubSpan("bar", SpanPurpose.LOCAL_ONLY); assertThat(MDC.get(Tracer.TRACE_ID_MDC_KEY)).isEqualTo(subspan.getTraceId()); assertThat(MDC.get(Tracer.SPAN_JSON_MDC_KEY)).isEqualTo(subspan.toJSON()); // when Deque<Span> emptyStack = new LinkedList<>(); tracer.registerWithThread(emptyStack); // then assertThat(getSpanStackThreadLocal().get()).isEqualTo(emptyStack); assertThat(MDC.get(Tracer.TRACE_ID_MDC_KEY)).isNull(); assertThat(MDC.get(Tracer.SPAN_JSON_MDC_KEY)).isNull(); }
@Test public void registerWithThread_should_reset_everything_if_passed_null() { // given Tracer tracer = Tracer.getInstance(); tracer.startRequestWithRootSpan("foo"); Span subspan = tracer.startSubSpan("bar", SpanPurpose.LOCAL_ONLY); assertThat(MDC.get(Tracer.TRACE_ID_MDC_KEY)).isEqualTo(subspan.getTraceId()); assertThat(MDC.get(Tracer.SPAN_JSON_MDC_KEY)).isEqualTo(subspan.toJSON()); // when tracer.registerWithThread(null); // then assertThat(getSpanStackThreadLocal().get()).isNull(); assertThat(MDC.get(Tracer.TRACE_ID_MDC_KEY)).isNull(); assertThat(MDC.get(Tracer.SPAN_JSON_MDC_KEY)).isNull(); }
tracer.registerWithThread(new LinkedList<Span>()); mock(Span.class), mock(Span.class), mock(Span.class) )); tracer.registerWithThread(nonEmptyStack);
@Test public void registerWithThread_should_override_existing_stuff() { // given Tracer tracer = Tracer.getInstance(); Span existingSpan = tracer.startRequestWithRootSpan("old"); Deque<Span> newSpanStack = new LinkedList<>(); Span parentSpan = Span.newBuilder("foo", SpanPurpose.LOCAL_ONLY).build(); Span subspan = Span.newBuilder("bar", SpanPurpose.LOCAL_ONLY).build(); newSpanStack.push(parentSpan); newSpanStack.push(subspan); assertThat(MDC.get(Tracer.TRACE_ID_MDC_KEY)).isEqualTo(existingSpan.getTraceId()); assertThat(MDC.get(Tracer.SPAN_JSON_MDC_KEY)).isEqualTo(existingSpan.toJSON()); // when tracer.registerWithThread(newSpanStack); // then assertThat(MDC.get(Tracer.TRACE_ID_MDC_KEY)).isEqualTo(subspan.getTraceId()); assertThat(MDC.get(Tracer.SPAN_JSON_MDC_KEY)).isEqualTo(subspan.toJSON()); Deque<Span> spanStack = getSpanStackThreadLocal().get(); assertThat(spanStack).isEqualTo(newSpanStack); }
Tracer.getInstance().registerWithThread(new ArrayDeque<>(Collections.singleton(spanMock))); assertThat(Tracer.getInstance().getCurrentSpan()).isEqualTo(spanMock);
@Test public void registerWithThread_should_work_as_advertised_if_existing_stack_is_empty() { // given getSpanStackThreadLocal().set(new LinkedList<Span>()); Tracer tracer = Tracer.getInstance(); Deque<Span> newSpanStack = new LinkedList<>(); Span parentSpan = Span.newBuilder("foo", SpanPurpose.LOCAL_ONLY).build(); Span subspan = Span.newBuilder("bar", SpanPurpose.LOCAL_ONLY).build(); newSpanStack.push(parentSpan); newSpanStack.push(subspan); assertThat(MDC.get(Tracer.TRACE_ID_MDC_KEY)).isNull(); assertThat(MDC.get(Tracer.SPAN_JSON_MDC_KEY)).isNull(); // when tracer.registerWithThread(newSpanStack); // then // our stack was registered, so subspan should be current assertThat(MDC.get(Tracer.TRACE_ID_MDC_KEY)).isEqualTo(subspan.getTraceId()); assertThat(MDC.get(Tracer.SPAN_JSON_MDC_KEY)).isEqualTo(subspan.toJSON()); assertThat(tracer.getCurrentSpan()).isEqualTo(subspan); // a *copy* of the stack we passed in should have been registered, and modifying the original stack should not affect Tracer's stack Deque<Span> spanStack = getSpanStackThreadLocal().get(); assertThat(Tracer.getInstance().containsSameSpansInSameOrder(spanStack, newSpanStack)).isTrue(); assertThat(spanStack).isNotSameAs(newSpanStack); newSpanStack.push(subspan.generateChildSpan("subsub", SpanPurpose.LOCAL_ONLY)); assertThat(newSpanStack).hasSize(3); assertThat(spanStack).hasSize(2); }
@Test public void registerWithThread_should_work_as_advertised() { // given Tracer tracer = Tracer.getInstance(); Deque<Span> newSpanStack = new LinkedList<>(); Span parentSpan = Span.newBuilder("foo", SpanPurpose.LOCAL_ONLY).build(); Span subspan = Span.newBuilder("bar", SpanPurpose.LOCAL_ONLY).build(); newSpanStack.push(parentSpan); newSpanStack.push(subspan); assertThat(MDC.get(Tracer.TRACE_ID_MDC_KEY)).isNull(); assertThat(MDC.get(Tracer.SPAN_JSON_MDC_KEY)).isNull(); // when tracer.registerWithThread(newSpanStack); // then // our stack was registered, so subspan should be current assertThat(MDC.get(Tracer.TRACE_ID_MDC_KEY)).isEqualTo(subspan.getTraceId()); assertThat(MDC.get(Tracer.SPAN_JSON_MDC_KEY)).isEqualTo(subspan.toJSON()); assertThat(tracer.getCurrentSpan()).isEqualTo(subspan); // a *copy* of the stack we passed in should have been registered, and modifying the original stack should not affect Tracer's stack Deque<Span> spanStack = getSpanStackThreadLocal().get(); assertThat(Tracer.getInstance().containsSameSpansInSameOrder(spanStack, newSpanStack)).isTrue(); assertThat(spanStack).isNotSameAs(newSpanStack); newSpanStack.push(subspan.generateChildSpan("subsub", SpanPurpose.LOCAL_ONLY)); assertThat(newSpanStack).hasSize(3); assertThat(spanStack).hasSize(2); }
MDC.setContextMap(mdcContextMapToLink); Tracer.getInstance().registerWithThread(distributedTraceStackToLink);
MDC.setContextMap(mdcContextMapToLink); Tracer.getInstance().registerWithThread(distributedTraceStackToLink);
MDC.setContextMap(mdcContextMap); Tracer.getInstance().registerWithThread(distributedTraceStack);
tracer.registerWithThread(reqAStack); tracer.registerWithThread(reqBStack);