WingtipsSpringWebfluxWebFilter implements WebFilter, Ordered { @SafeVarargs protected static void finalizeAndCompleteOverallRequestSpanAttachedToCurrentThread( @NotNull ServerWebExchange exchange, @Nullable Throwable error, @NotNull HttpTagAndSpanNamingStrategy<ServerWebExchange, ServerHttpResponse> tagAndNamingStrategy, @NotNull HttpTagAndSpanNamingAdapter<ServerWebExchange, ServerHttpResponse> tagAndNamingAdapter, Pair<String, String>... extraCustomTags ) { Span span = Tracer.getInstance().getCurrentSpan(); if (span == null) { return; } if (span.isCompleted()) { return; } try { if (extraCustomTags != null) { for (Pair<String, String> tag : extraCustomTags) { span.putTag(tag.getKey(), tag.getValue()); } } tagAndNamingStrategy.handleResponseTaggingAndFinalSpanName( span, exchange, exchange.getResponse(), error, tagAndNamingAdapter ); } finally { Tracer.getInstance().completeRequestSpan(); } } WingtipsSpringWebfluxWebFilter();  WingtipsSpringWebfluxWebFilter(Builder builder); static Builder newBuilder(); @Override @NotNull Mono<Void> filter(@NotNull ServerWebExchange exchange, @NotNull WebFilterChain chain); @Override int getOrder(); void setOrder(int order);  }
@UseDataProvider("extraCustomTagsScenarioDataProvider") @Test public void finalizeAndCompleteOverallRequestSpanAttachedToCurrentThread_works_as_expected_happy_path( ExtraCustomTagsScenario scenario ) { Span rootSpan = Tracer.getInstance().startRequestWithRootSpan("fooRootSpan"); Throwable error = mock(Throwable.class); WingtipsSpringWebfluxWebFilter.finalizeAndCompleteOverallRequestSpanAttachedToCurrentThread( exchange, error, tagAndNamingStrategy, tagAndNamingAdapterMock, scenario.extraCustomTags ); assertThat(strategyResponseTaggingAndFinalSpanNameMethodCalled.get()).isTrue(); strategyResponseTaggingArgs.get().verifyArgs( rootSpan, exchange, responseMock, error, tagAndNamingAdapterMock ); if (scenario.extraCustomTags != null) { for (Pair<String, String> expectedTag : scenario.extraCustomTags) { assertThat(rootSpan.getTags().get(expectedTag.getKey())).isEqualTo(expectedTag.getValue()); } } assertThat(rootSpan.isCompleted()).isTrue(); assertThat(spanRecorder.completedSpans).isEqualTo(singletonList(rootSpan)); assertThat(Tracer.getInstance().getCurrentSpan()).isNull(); }
@Test public void finalizeAndCompleteOverallRequestSpanAttachedToCurrentThread_does_nothing_if_called_when_current_thread_span_is_null() { assertThat(Tracer.getInstance().getCurrentSpan()).isNull(); WingtipsSpringWebfluxWebFilter.finalizeAndCompleteOverallRequestSpanAttachedToCurrentThread( exchange, mock(Throwable.class), tagAndNamingStrategy, tagAndNamingAdapterMock, Pair.of("foo", "bar") ); assertThat(strategyResponseTaggingAndFinalSpanNameMethodCalled.get()).isFalse(); assertThat(spanRecorder.completedSpans).isEmpty(); }
@Test public void finalizeAndCompleteOverallRequestSpanAttachedToCurrentThread_does_nothing_if_called_when_current_thread_span_is_already_completed() { Span spanMock = mock(Span.class); Tracer.getInstance().registerWithThread(new ArrayDeque<>(singleton(spanMock))); reset(spanMock); doReturn(true).when(spanMock).isCompleted(); assertThat(Tracer.getInstance().getCurrentSpan()).isSameAs(spanMock); WingtipsSpringWebfluxWebFilter.finalizeAndCompleteOverallRequestSpanAttachedToCurrentThread( exchange, mock(Throwable.class), tagAndNamingStrategy, tagAndNamingAdapterMock, Pair.of("foo", "bar") ); assertThat(strategyResponseTaggingAndFinalSpanNameMethodCalled.get()).isFalse(); assertThat(spanRecorder.completedSpans).isEmpty(); verify(spanMock).isCompleted(); verifyNoMoreInteractions(spanMock); }
@Test public void finalizeAndCompleteOverallRequestSpanAttachedToCurrentThread_completes_span_even_if_highly_improbable_exception_occurs() { Span rootSpan = Tracer.getInstance().startRequestWithRootSpan("fooRootSpan"); RuntimeException improbableException = new RuntimeException("Intentional test exception"); @SuppressWarnings("unchecked") Pair<String, String> explodingTag = mock(Pair.class); doThrow(improbableException).when(explodingTag).getKey(); Throwable ex = catchThrowable( () -> WingtipsSpringWebfluxWebFilter.finalizeAndCompleteOverallRequestSpanAttachedToCurrentThread( exchange, mock(Throwable.class), tagAndNamingStrategy, tagAndNamingAdapterMock, explodingTag ) ); assertThat(ex).isSameAs(improbableException); assertThat(rootSpan.isCompleted()).isTrue(); assertThat(spanRecorder.completedSpans).isEqualTo(singletonList(rootSpan)); assertThat(Tracer.getInstance().getCurrentSpan()).isNull(); }