protected boolean shouldLinkAndUnlinkDistributedTraceInfoForMethod( HandlerMethodToExecute methodToExecute, boolean isDefaultMethodImpl, boolean forceEnableDTraceOnAllMethods, boolean debugHandlerMethodCalls, ChannelHandlerContext ctx, Object msgOrEvt, Throwable cause ) { return (!isDefaultMethodImpl && argsAreEligibleForLinkingAndUnlinkingDistributedTracingInfo(methodToExecute, ctx, msgOrEvt, cause) ) || forceEnableDTraceOnAllMethods || debugHandlerMethodCalls; }
public BaseInboundHandlerWithTracingAndMdcSupport() { Method[] methods = this.getClass().getMethods(); Map<String, Method> nameToMethodMap = Arrays.stream(methods) .filter(m -> m.getName().startsWith("do")) .collect(Collectors.toMap(Method::getName, m -> m)); isDefaultDoChannelRegisteredImpl = isDefaultMethodImpl("doChannelRegistered", nameToMethodMap); isDefaultDoChannelUnregisteredImpl = isDefaultMethodImpl("doChannelUnregistered", nameToMethodMap); isDefaultDoChannelActiveImpl = isDefaultMethodImpl("doChannelActive", nameToMethodMap); isDefaultDoChannelInactiveImpl = isDefaultMethodImpl("doChannelInactive", nameToMethodMap); isDefaultDoChannelReadImpl = isDefaultMethodImpl("doChannelRead", nameToMethodMap); isDefaultDoChannelReadCompleteImpl = isDefaultMethodImpl("doChannelReadComplete", nameToMethodMap); isDefaultDoUserEventTriggeredImpl = isDefaultMethodImpl("doUserEventTriggered", nameToMethodMap); isDefaultDoChannelWritabilityChangedImpl = isDefaultMethodImpl("doChannelWritabilityChanged", nameToMethodMap); isDefaultDoExceptionCaughtImpl = isDefaultMethodImpl("doExceptionCaught", nameToMethodMap); isDefaultDoHandlerAddedImpl = isDefaultMethodImpl("doHandlerAdded", nameToMethodMap); isDefaultDoHandlerRemovedImpl = isDefaultMethodImpl("doHandlerRemoved", nameToMethodMap); }
@Override public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { PipelineContinuationBehavior methodExecutionResponse; boolean shouldLinkAndUnlinkDTraceInfo = shouldLinkAndUnlinkDistributedTraceInfoForMethod( DO_CHANNEL_UNREGISTERED, isDefaultDoChannelUnregisteredImpl, forceEnableDTraceOnAllMethods, debugHandlerMethodCalls, ctx, null, null ); Pair<Deque<Span>, Map<String, String>> origThreadInfo = null; try { if (shouldLinkAndUnlinkDTraceInfo) origThreadInfo = linkTracingAndMdcToCurrentThread(ctx); if (debugHandlerMethodCalls) logger.debug("222222222222222 channelUnregistered for {}", this.getClass().getName()); methodExecutionResponse = doChannelUnregistered(ctx); } finally { if (shouldLinkAndUnlinkDTraceInfo) unlinkTracingAndMdcFromCurrentThread(ctx, origThreadInfo); } if (methodExecutionResponse == null || CONTINUE.equals(methodExecutionResponse)) super.channelUnregistered(ctx); }
@Override public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { PipelineContinuationBehavior methodExecutionResponse; boolean shouldLinkAndUnlinkDTraceInfo = shouldLinkAndUnlinkDistributedTraceInfoForMethod( DO_CHANNEL_WRITABILITY_CHANGED, isDefaultDoChannelWritabilityChangedImpl, forceEnableDTraceOnAllMethods, debugHandlerMethodCalls, ctx, null, null ); Pair<Deque<Span>, Map<String, String>> origThreadInfo = null; try { if (shouldLinkAndUnlinkDTraceInfo) origThreadInfo = linkTracingAndMdcToCurrentThread(ctx); if (debugHandlerMethodCalls) logger.debug("^^^^^^^^^^^^^^^ channelWritabilityChanged for {}", this.getClass().getName()); methodExecutionResponse = doChannelWritabilityChanged(ctx); } finally { if (shouldLinkAndUnlinkDTraceInfo) unlinkTracingAndMdcFromCurrentThread(ctx, origThreadInfo); } if (methodExecutionResponse == null || CONTINUE.equals(methodExecutionResponse)) super.channelWritabilityChanged(ctx); }
@Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { PipelineContinuationBehavior methodExecutionResponse; boolean shouldLinkAndUnlinkDTraceInfo = shouldLinkAndUnlinkDistributedTraceInfoForMethod( DO_HANDLER_ADDED, isDefaultDoHandlerAddedImpl, forceEnableDTraceOnAllMethods, debugHandlerMethodCalls, ctx, null, null ); Pair<Deque<Span>, Map<String, String>> origThreadInfo = null; try { if (shouldLinkAndUnlinkDTraceInfo) origThreadInfo = linkTracingAndMdcToCurrentThread(ctx); if (debugHandlerMethodCalls) logger.debug("(((((((((((((( handlerAdded for {}", this.getClass().getName()); methodExecutionResponse = doHandlerAdded(ctx); } finally { if (shouldLinkAndUnlinkDTraceInfo) unlinkTracingAndMdcFromCurrentThread(ctx, origThreadInfo); } if (methodExecutionResponse == null || CONTINUE.equals(methodExecutionResponse)) super.handlerAdded(ctx); }
@Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { PipelineContinuationBehavior methodExecutionResponse; boolean shouldLinkAndUnlinkDTraceInfo = shouldLinkAndUnlinkDistributedTraceInfoForMethod( DO_CHANNEL_INACTIVE, isDefaultDoChannelInactiveImpl, forceEnableDTraceOnAllMethods, debugHandlerMethodCalls, ctx, null, null ); Pair<Deque<Span>, Map<String, String>> origThreadInfo = null; try { if (shouldLinkAndUnlinkDTraceInfo) origThreadInfo = linkTracingAndMdcToCurrentThread(ctx); if (debugHandlerMethodCalls) logger.debug("444444444444444 channelInactive for {}", this.getClass().getName()); methodExecutionResponse = doChannelInactive(ctx); } finally { if (shouldLinkAndUnlinkDTraceInfo) unlinkTracingAndMdcFromCurrentThread(ctx, origThreadInfo); } if (methodExecutionResponse == null || CONTINUE.equals(methodExecutionResponse)) super.channelInactive(ctx); }
@Override public void channelActive(ChannelHandlerContext ctx) throws Exception { PipelineContinuationBehavior methodExecutionResponse; boolean shouldLinkAndUnlinkDTraceInfo = shouldLinkAndUnlinkDistributedTraceInfoForMethod( DO_CHANNEL_ACTIVE, isDefaultDoChannelActiveImpl, forceEnableDTraceOnAllMethods, debugHandlerMethodCalls, ctx, null, null ); Pair<Deque<Span>, Map<String, String>> origThreadInfo = null; try { if (shouldLinkAndUnlinkDTraceInfo) origThreadInfo = linkTracingAndMdcToCurrentThread(ctx); if (debugHandlerMethodCalls) logger.debug("333333333333333 channelActive for {}", this.getClass().getName()); methodExecutionResponse = doChannelActive(ctx); } finally { if (shouldLinkAndUnlinkDTraceInfo) unlinkTracingAndMdcFromCurrentThread(ctx, origThreadInfo); } if (methodExecutionResponse == null || CONTINUE.equals(methodExecutionResponse)) super.channelActive(ctx); }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { PipelineContinuationBehavior methodExecutionResponse; boolean shouldLinkAndUnlinkDTraceInfo = shouldLinkAndUnlinkDistributedTraceInfoForMethod( DO_CHANNEL_READ, isDefaultDoChannelReadImpl, forceEnableDTraceOnAllMethods, debugHandlerMethodCalls, ctx, msg, null ); Pair<Deque<Span>, Map<String, String>> origThreadInfo = null; try { if (shouldLinkAndUnlinkDTraceInfo) origThreadInfo = linkTracingAndMdcToCurrentThread(ctx); if (debugHandlerMethodCalls) logger.debug("############### channelRead for {}", this.getClass().getName()); methodExecutionResponse = doChannelRead(ctx, msg); } finally { if (shouldLinkAndUnlinkDTraceInfo) unlinkTracingAndMdcFromCurrentThread(ctx, origThreadInfo); } if (methodExecutionResponse == null || CONTINUE.equals(methodExecutionResponse)) super.channelRead(ctx, msg); }
@Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { PipelineContinuationBehavior methodExecutionResponse; boolean shouldLinkAndUnlinkDTraceInfo = shouldLinkAndUnlinkDistributedTraceInfoForMethod( DO_CHANNEL_READ_COMPLETE, isDefaultDoChannelReadCompleteImpl, forceEnableDTraceOnAllMethods, debugHandlerMethodCalls, ctx, null, null ); Pair<Deque<Span>, Map<String, String>> origThreadInfo = null; try { if (shouldLinkAndUnlinkDTraceInfo) origThreadInfo = linkTracingAndMdcToCurrentThread(ctx); if (debugHandlerMethodCalls) logger.debug("$$$$$$$$$$$$$$$$$ channelReadComplete for {}", this.getClass().getName()); methodExecutionResponse = doChannelReadComplete(ctx); } finally { if (shouldLinkAndUnlinkDTraceInfo) unlinkTracingAndMdcFromCurrentThread(ctx, origThreadInfo); } if (methodExecutionResponse == null || CONTINUE.equals(methodExecutionResponse)) super.channelReadComplete(ctx); }
@Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { PipelineContinuationBehavior methodExecutionResponse; boolean shouldLinkAndUnlinkDTraceInfo = shouldLinkAndUnlinkDistributedTraceInfoForMethod( DO_USER_EVENT_TRIGGERED, isDefaultDoUserEventTriggeredImpl, forceEnableDTraceOnAllMethods, debugHandlerMethodCalls, ctx, evt, null ); Pair<Deque<Span>, Map<String, String>> origThreadInfo = null; try { if (shouldLinkAndUnlinkDTraceInfo) origThreadInfo = linkTracingAndMdcToCurrentThread(ctx); if (debugHandlerMethodCalls) logger.debug("************** userEventTriggered for {}", this.getClass().getName()); methodExecutionResponse = doUserEventTriggered(ctx, evt); } finally { if (shouldLinkAndUnlinkDTraceInfo) unlinkTracingAndMdcFromCurrentThread(ctx, origThreadInfo); } if (methodExecutionResponse == null || CONTINUE.equals(methodExecutionResponse)) super.userEventTriggered(ctx, evt); }
@Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { PipelineContinuationBehavior methodExecutionResponse; boolean shouldLinkAndUnlinkDTraceInfo = shouldLinkAndUnlinkDistributedTraceInfoForMethod( DO_EXCEPTION_CAUGHT, isDefaultDoExceptionCaughtImpl, forceEnableDTraceOnAllMethods, debugHandlerMethodCalls, ctx, null, cause ); Pair<Deque<Span>, Map<String, String>> origThreadInfo = null; try { if (shouldLinkAndUnlinkDTraceInfo) origThreadInfo = linkTracingAndMdcToCurrentThread(ctx); if (debugHandlerMethodCalls) logger.debug("!!!!!!!!!!!!!!!!! exceptionCaught for {}", this.getClass().getName()); methodExecutionResponse = doExceptionCaught(ctx, cause); } finally { if (shouldLinkAndUnlinkDTraceInfo) unlinkTracingAndMdcFromCurrentThread(ctx, origThreadInfo); } if (methodExecutionResponse == null || CONTINUE.equals(methodExecutionResponse)) super.exceptionCaught(ctx, cause); }
@Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception { PipelineContinuationBehavior methodExecutionResponse; boolean shouldLinkAndUnlinkDTraceInfo = shouldLinkAndUnlinkDistributedTraceInfoForMethod( DO_CHANNEL_REGISTERED, isDefaultDoChannelRegisteredImpl, forceEnableDTraceOnAllMethods, debugHandlerMethodCalls, ctx, null, null ); Pair<Deque<Span>, Map<String, String>> origThreadInfo = null; try { if (shouldLinkAndUnlinkDTraceInfo) origThreadInfo = linkTracingAndMdcToCurrentThread(ctx); if (debugHandlerMethodCalls) logger.debug("11111111111111 channelRegistered for {}", this.getClass().getName()); methodExecutionResponse = doChannelRegistered(ctx); } finally { if (shouldLinkAndUnlinkDTraceInfo) unlinkTracingAndMdcFromCurrentThread(ctx, origThreadInfo); } if (methodExecutionResponse == null || CONTINUE.equals(methodExecutionResponse)) super.channelRegistered(ctx); }
@Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { PipelineContinuationBehavior methodExecutionResponse; boolean shouldLinkAndUnlinkDTraceInfo = shouldLinkAndUnlinkDistributedTraceInfoForMethod( DO_HANDLER_REMOVED, isDefaultDoHandlerRemovedImpl, forceEnableDTraceOnAllMethods, debugHandlerMethodCalls, ctx, null, null ); Pair<Deque<Span>, Map<String, String>> origThreadInfo = null; try { if (shouldLinkAndUnlinkDTraceInfo) origThreadInfo = linkTracingAndMdcToCurrentThread(ctx); if (debugHandlerMethodCalls) logger.debug("))))))))))))))))) handlerRemoved for {}", this.getClass().getName()); methodExecutionResponse = doHandlerRemoved(ctx); } finally { if (shouldLinkAndUnlinkDTraceInfo) unlinkTracingAndMdcFromCurrentThread(ctx, origThreadInfo); } if (methodExecutionResponse == null || CONTINUE.equals(methodExecutionResponse)) super.handlerRemoved(ctx); }
doReturn(argsEligibleForLinkUnlink).when(handlerSpy).argsAreEligibleForLinkingAndUnlinkingDistributedTracingInfo( eq(expectedHandlerMethodToExecute), eq(ctxMock), anyObject(), any(Throwable.class) ); assertThat(calledSuperMethod.heldObject, is(false)); return linkTracingAndMdcReturnVal; }).when(handlerSpy).linkTracingAndMdcToCurrentThread(ctxMock); assertThat(invocation.getArguments()[1], is(linkTracingAndMdcReturnVal)); return null; }).when(handlerSpy).unlinkTracingAndMdcFromCurrentThread(ctxMock, linkTracingAndMdcReturnVal); int numExpectedArgsEligibleMethodCalls = (argsEligibleMethodShouldHaveBeenCalled) ? 1 : 0; verify(handlerSpy, times(numExpectedArgsEligibleMethodCalls)).argsAreEligibleForLinkingAndUnlinkingDistributedTracingInfo( eq(expectedHandlerMethodToExecute), eq(ctxMock), anyObject(), any(Throwable.class) );
@Test public void linkTracingAndMdcToCurrentThread_should_clear_mdc_if_state_is_available_but_state_mdc_info_is_null() { // given MDC.put("foo", "bar"); Tracer.getInstance().startRequestWithRootSpan("blahtrace"); assertThat(MDC.getCopyOfContextMap().isEmpty(), is(false)); assertThat(Tracer.getInstance().getCurrentSpan(), notNullValue()); // when handler.linkTracingAndMdcToCurrentThread(ctxMock); // then assertThat(MDC.getCopyOfContextMap().isEmpty(), is(true)); assertThat(Tracer.getInstance().getCurrentSpanStackCopy(), nullValue()); }
@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(Tracer.TRACE_ID_MDC_KEY, origSpan.getTraceId()); origMdcInfo.put(Tracer.SPAN_JSON_MDC_KEY, origSpan.toJSON()); 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)); }
@Override public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { PipelineContinuationBehavior methodExecutionResponse; boolean shouldLinkAndUnlinkDTraceInfo = shouldLinkAndUnlinkDistributedTraceInfoForMethod( DO_CHANNEL_WRITABILITY_CHANGED, isDefaultDoChannelWritabilityChangedImpl, forceEnableDTraceOnAllMethods, debugHandlerMethodCalls, ctx, null, null ); Pair<Deque<Span>, Map<String, String>> origThreadInfo = null; try { if (shouldLinkAndUnlinkDTraceInfo) origThreadInfo = linkTracingAndMdcToCurrentThread(ctx); if (debugHandlerMethodCalls) logger.debug("^^^^^^^^^^^^^^^ channelWritabilityChanged for {}", this.getClass().getName()); methodExecutionResponse = doChannelWritabilityChanged(ctx); } finally { if (shouldLinkAndUnlinkDTraceInfo) unlinkTracingAndMdcFromCurrentThread(ctx, origThreadInfo); } if (methodExecutionResponse == null || CONTINUE.equals(methodExecutionResponse)) super.channelWritabilityChanged(ctx); }
@Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { PipelineContinuationBehavior methodExecutionResponse; boolean shouldLinkAndUnlinkDTraceInfo = shouldLinkAndUnlinkDistributedTraceInfoForMethod( DO_HANDLER_ADDED, isDefaultDoHandlerAddedImpl, forceEnableDTraceOnAllMethods, debugHandlerMethodCalls, ctx, null, null ); Pair<Deque<Span>, Map<String, String>> origThreadInfo = null; try { if (shouldLinkAndUnlinkDTraceInfo) origThreadInfo = linkTracingAndMdcToCurrentThread(ctx); if (debugHandlerMethodCalls) logger.debug("(((((((((((((( handlerAdded for {}", this.getClass().getName()); methodExecutionResponse = doHandlerAdded(ctx); } finally { if (shouldLinkAndUnlinkDTraceInfo) unlinkTracingAndMdcFromCurrentThread(ctx, origThreadInfo); } if (methodExecutionResponse == null || CONTINUE.equals(methodExecutionResponse)) super.handlerAdded(ctx); }
@Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { PipelineContinuationBehavior methodExecutionResponse; boolean shouldLinkAndUnlinkDTraceInfo = shouldLinkAndUnlinkDistributedTraceInfoForMethod( DO_CHANNEL_INACTIVE, isDefaultDoChannelInactiveImpl, forceEnableDTraceOnAllMethods, debugHandlerMethodCalls, ctx, null, null ); Pair<Deque<Span>, Map<String, String>> origThreadInfo = null; try { if (shouldLinkAndUnlinkDTraceInfo) origThreadInfo = linkTracingAndMdcToCurrentThread(ctx); if (debugHandlerMethodCalls) logger.debug("444444444444444 channelInactive for {}", this.getClass().getName()); methodExecutionResponse = doChannelInactive(ctx); } finally { if (shouldLinkAndUnlinkDTraceInfo) unlinkTracingAndMdcFromCurrentThread(ctx, origThreadInfo); } if (methodExecutionResponse == null || CONTINUE.equals(methodExecutionResponse)) super.channelInactive(ctx); }
@Override public void channelActive(ChannelHandlerContext ctx) throws Exception { PipelineContinuationBehavior methodExecutionResponse; boolean shouldLinkAndUnlinkDTraceInfo = shouldLinkAndUnlinkDistributedTraceInfoForMethod( DO_CHANNEL_ACTIVE, isDefaultDoChannelActiveImpl, forceEnableDTraceOnAllMethods, debugHandlerMethodCalls, ctx, null, null ); Pair<Deque<Span>, Map<String, String>> origThreadInfo = null; try { if (shouldLinkAndUnlinkDTraceInfo) origThreadInfo = linkTracingAndMdcToCurrentThread(ctx); if (debugHandlerMethodCalls) logger.debug("333333333333333 channelActive for {}", this.getClass().getName()); methodExecutionResponse = doChannelActive(ctx); } finally { if (shouldLinkAndUnlinkDTraceInfo) unlinkTracingAndMdcFromCurrentThread(ctx, origThreadInfo); } if (methodExecutionResponse == null || CONTINUE.equals(methodExecutionResponse)) super.channelActive(ctx); }