use of com.nike.wingtips.Span in project riposte by Nike-Inc.
the class AsyncCompletionHandlerWithTracingAndMdcSupportTest method constructor_sets_values_with_subspan_when_subtracing_is_on.
@DataProvider(value = { "NULL", "EMPTY", "HAS_EXISTING_SPAN" }, splitBy = "\\|")
@Test
public void constructor_sets_values_with_subspan_when_subtracing_is_on(ExistingSpanStackState existingSpanStackState) {
// given
CompletableFuture cfResponse = mock(CompletableFuture.class);
AsyncResponseHandler responseHandlerFunc = mock(AsyncResponseHandler.class);
RequestBuilderWrapper rbwMock = mock(RequestBuilderWrapper.class);
Optional<CircuitBreaker<Response>> circuitBreaker = Optional.of(mock(CircuitBreaker.class));
Span initialSpan = null;
switch(existingSpanStackState) {
case NULL:
case // intentional fall-through
EMPTY:
resetTracingAndMdc();
break;
case HAS_EXISTING_SPAN:
initialSpan = Tracer.getInstance().startRequestWithRootSpan("overallReqSpan");
break;
default:
throw new IllegalArgumentException("Unhandled state: " + existingSpanStackState.name());
}
Deque<Span> spanStack = (existingSpanStackState == EMPTY) ? new LinkedList<>() : Tracer.getInstance().getCurrentSpanStackCopy();
Map<String, String> mdcInfo = (existingSpanStackState == EMPTY) ? new HashMap<>() : MDC.getCopyOfContextMap();
resetTracingAndMdc();
Deque<Span> spanStackBeforeCall = Tracer.getInstance().getCurrentSpanStackCopy();
Map<String, String> mdcInfoBeforeCall = MDC.getCopyOfContextMap();
// when
AsyncCompletionHandlerWithTracingAndMdcSupport instance = new AsyncCompletionHandlerWithTracingAndMdcSupport(cfResponse, responseHandlerFunc, true, rbwMock, circuitBreaker, spanStack, mdcInfo, tagAndNamingStrategy);
// then
assertThat(instance.completableFutureResponse).isSameAs(cfResponse);
assertThat(instance.responseHandlerFunction).isSameAs(responseHandlerFunc);
assertThat(instance.performSubSpanAroundDownstreamCalls).isEqualTo(true);
assertThat(instance.circuitBreakerManualTask).isSameAs(circuitBreaker);
int initialSpanStackSize = (spanStack == null) ? 0 : spanStack.size();
assertThat(instance.distributedTraceStackToUse).hasSize(initialSpanStackSize + 1);
Span subspan = (Span) instance.distributedTraceStackToUse.peek();
assertThat(instance.mdcContextToUse.get(SpanFieldForLoggerMdc.TRACE_ID.mdcKey)).isEqualTo(subspan.getTraceId());
if (existingSpanStackState == ExistingSpanStackState.NULL || existingSpanStackState == EMPTY) {
assertThat(instance.distributedTraceStackToUse).hasSize(1);
} else {
assertThat(instance.distributedTraceStackToUse.peekLast()).isEqualTo(initialSpan);
assertThat(subspan).isNotEqualTo(initialSpan);
assertThat(subspan.getTraceId()).isEqualTo(initialSpan.getTraceId());
assertThat(subspan.getParentSpanId()).isEqualTo(initialSpan.getSpanId());
assertThat(subspan.getSpanName()).isEqualTo(instance.getSubspanSpanName(rbwMock, tagAndNamingStrategy));
}
assertThat(Tracer.getInstance().getCurrentSpanStackCopy()).isEqualTo(spanStackBeforeCall);
assertThat(MDC.getCopyOfContextMap()).isEqualTo(mdcInfoBeforeCall);
}
use of com.nike.wingtips.Span in project riposte by Nike-Inc.
the class AsyncCompletionHandlerWithTracingAndMdcSupport method onCompleted.
@Override
public Response onCompleted(Response response) {
Pair<Deque<Span>, Map<String, String>> originalThreadInfo = null;
try {
// Link up the distributed tracing and MDC information to the current thread
originalThreadInfo = linkTracingAndMdcToCurrentThread(distributedTraceStackToUse, mdcContextToUse);
// Notify the circuit breaker of an event.
try {
circuitBreakerManualTask.ifPresent(cb -> cb.handleEvent(response));
} catch (Throwable t) {
logger.error("Circuit breaker threw an exception during handleEvent. This should never happen and means the " + "CircuitBreaker is malfunctioning. Ignoring exception.", t);
}
// If a subspan was started for the downstream call, it should now be completed
if (performSubSpanAroundDownstreamCalls) {
Span spanAroundCall = Tracer.getInstance().getCurrentSpan();
// Handle the final span naming and response tagging.
tagAndNamingStrategy.handleResponseTaggingAndFinalSpanName(spanAroundCall, rbwCopyWithHttpMethodAndUrlOnly, response, null);
// The Span.close() method will do the right thing whether or not this is an overall request span or
// subspan.
spanAroundCall.close();
}
// and we should not do any more processing here.
if (completableFutureResponse.isDone())
return response;
// completableFutureResponse with.
try {
O responseInfo = responseHandlerFunction.handleResponse(response);
completableFutureResponse.complete(responseInfo);
} catch (Throwable throwable) {
// responseHandlerFunction threw an error. Complete completableFutureResponse exceptionally.
completableFutureResponse.completeExceptionally(throwable);
}
return response;
} finally {
AsyncNettyHelper.unlinkTracingAndMdcFromCurrentThread(originalThreadInfo);
}
}
use of com.nike.wingtips.Span in project riposte by Nike-Inc.
the class AsyncHttpClientHelper method executeAsyncHttpRequest.
/**
* Executes the given request asynchronously, handling the response with the given responseHandlerFunction, and
* returns a {@link CompletableFuture} that represents the result of executing the
* responseHandlerFunction on the downstream response. Any error anywhere along the way will cause the returned
* future to be completed with {@link CompletableFuture#completeExceptionally(Throwable)}.
* <p/>
* <b>Distributed Tracing and MDC for the downstream call:</b> The given {@code distributedTraceStackForCall} and
* {@code mdcContextForCall} arguments are used to setup distributed trace and MDC info for the downstream call so
* that the callback will be performed with that data attached to whatever thread the callback is done on.
*/
public <O> CompletableFuture<O> executeAsyncHttpRequest(RequestBuilderWrapper requestBuilderWrapper, AsyncResponseHandler<O> responseHandlerFunction, Deque<Span> distributedTraceStackForCall, Map<String, String> mdcContextForCall) {
CompletableFuture<O> completableFutureResponse = new CompletableFuture<>();
try {
Optional<ManualModeTask<Response>> circuitBreakerManualTask = getCircuitBreaker(requestBuilderWrapper).map(CircuitBreaker::newManualModeTask);
// If we have a circuit breaker, give it a chance to throw an exception if the circuit is open/tripped
circuitBreakerManualTask.ifPresent(ManualModeTask::throwExceptionIfCircuitBreakerIsOpen);
// Setup the async completion handler for the call.
AsyncCompletionHandlerWithTracingAndMdcSupport<O> asyncCompletionHandler = new AsyncCompletionHandlerWithTracingAndMdcSupport<>(completableFutureResponse, responseHandlerFunction, performSubSpanAroundDownstreamCalls, requestBuilderWrapper, circuitBreakerManualTask, distributedTraceStackForCall, mdcContextForCall, spanNamingAndTaggingStrategy);
// Add distributed trace headers to the downstream call if we have a span.
Span spanForCall = asyncCompletionHandler.getSpanForCall();
if (spanForCall != null) {
HttpRequestTracingUtils.propagateTracingHeaders((headerKey, headerValue) -> {
if (headerValue != null) {
requestBuilderWrapper.requestBuilder.setHeader(headerKey, headerValue);
}
}, spanForCall);
}
// Add span tags if we're doing a subspan around the call.
if (performSubSpanAroundDownstreamCalls && spanForCall != null) {
spanNamingAndTaggingStrategy.handleRequestTagging(spanForCall, requestBuilderWrapper);
}
// Execute the downstream call. The completableFutureResponse will be completed or completed exceptionally
// depending on the result of the call.
requestBuilderWrapper.requestBuilder.execute(asyncCompletionHandler);
} catch (Throwable t) {
// normal when the circuit breaker associated with this request has been tripped.
if (!(t instanceof CircuitBreakerOpenException)) {
logger.error("An error occurred while trying to set up an async HTTP call for method {} and URL {}. " + "The CompletableFuture will be instantly failed with this error", requestBuilderWrapper.httpMethod, requestBuilderWrapper.url, t);
}
completableFutureResponse.completeExceptionally(t);
}
return completableFutureResponse;
}
use of com.nike.wingtips.Span in project riposte by Nike-Inc.
the class BaseInboundHandlerWithTracingAndMdcSupportTest method unlinkTracingAndMdcFromCurrentThread_should_populate_state_and_reset_tracing_and_mdc_to_originalThreadInfo_if_state_is_not_null.
@Test
public void unlinkTracingAndMdcFromCurrentThread_should_populate_state_and_reset_tracing_and_mdc_to_originalThreadInfo_if_state_is_not_null() {
// given
// Orig thread info
Deque<Span> origTraceStack = new LinkedList<>();
Span origSpan = Span.newBuilder(UUID.randomUUID().toString(), LOCAL_ONLY).withTraceId(UUID.randomUUID().toString()).build();
origTraceStack.add(origSpan);
Map<String, String> origMdcInfo = new HashMap<>();
origMdcInfo.put(UUID.randomUUID().toString(), UUID.randomUUID().toString());
origMdcInfo.put(SpanFieldForLoggerMdc.TRACE_ID.mdcKey, origSpan.getTraceId());
Pair<Deque<Span>, Map<String, String>> origThreadInfo = Pair.of(origTraceStack, origMdcInfo);
// "Current" state
MDC.put("foo", "bar");
Tracer.getInstance().startRequestWithRootSpan(UUID.randomUUID().toString());
Deque<Span> currentTraceStackBeforeUnlinkCall = Tracer.getInstance().getCurrentSpanStackCopy();
Map<String, String> currentMdcInfoBeforeUnlinkCall = MDC.getCopyOfContextMap();
// Verify we've set up our "given" section correctly
assertThat(MDC.getCopyOfContextMap(), is(currentMdcInfoBeforeUnlinkCall));
assertThat(MDC.get("foo"), is("bar"));
assertThat(Tracer.getInstance().getCurrentSpanStackCopy(), is(currentTraceStackBeforeUnlinkCall));
assertThat(state.getLoggerMdcContextMap(), nullValue());
assertThat(state.getDistributedTraceStack(), nullValue());
assertThat(origMdcInfo, not(currentMdcInfoBeforeUnlinkCall));
assertThat(origTraceStack, not(currentTraceStackBeforeUnlinkCall));
// when
handler.unlinkTracingAndMdcFromCurrentThread(ctxMock, origThreadInfo);
// then
// The state should have the expected values from the time when the unlink method was called
assertThat(state.getLoggerMdcContextMap(), is(currentMdcInfoBeforeUnlinkCall));
assertThat(state.getDistributedTraceStack(), is(currentTraceStackBeforeUnlinkCall));
// The "current" thread state after the unlink call should match the original thread info
assertThat(MDC.getCopyOfContextMap(), is(origMdcInfo));
assertThat(Tracer.getInstance().getCurrentSpanStackCopy(), is(origTraceStack));
}
use of com.nike.wingtips.Span in project riposte by Nike-Inc.
the class BaseInboundHandlerWithTracingAndMdcSupportTest method unlinkTracingAndMdcFromCurrentThread_should_reset_tracing_and_mdc_to_originalThreadInfo_if_state_is_null.
@Test
public void unlinkTracingAndMdcFromCurrentThread_should_reset_tracing_and_mdc_to_originalThreadInfo_if_state_is_null() {
// given
doReturn(null).when(stateAttributeMock).get();
MDC.put("foo", "bar");
Tracer.getInstance().startRequestWithRootSpan("blahtrace");
assertThat(MDC.getCopyOfContextMap().isEmpty(), is(false));
assertThat(Tracer.getInstance().getCurrentSpan(), notNullValue());
Deque<Span> origTraceStack = new LinkedList<>();
Span origSpan = Span.newBuilder(UUID.randomUUID().toString(), LOCAL_ONLY).withTraceId(UUID.randomUUID().toString()).build();
origTraceStack.add(origSpan);
Map<String, String> origMdcInfo = new HashMap<>();
origMdcInfo.put(UUID.randomUUID().toString(), UUID.randomUUID().toString());
origMdcInfo.put(SpanFieldForLoggerMdc.TRACE_ID.mdcKey, origSpan.getTraceId());
Pair<Deque<Span>, Map<String, String>> origThreadInfo = Pair.of(origTraceStack, origMdcInfo);
// when
handler.unlinkTracingAndMdcFromCurrentThread(ctxMock, origThreadInfo);
// then
assertThat(MDC.getCopyOfContextMap(), is(origMdcInfo));
assertThat(Tracer.getInstance().getCurrentSpanStackCopy(), is(origTraceStack));
}
Aggregations