/** * Calls {@link Span#complete()} on the given span. */ public static void completeSpan(Span span) { span.complete(); } }
/** * Calls {@link Span#complete()} to complete the span and logs it (but only if the span's {@link Span#isSampleable()} returns true). If the span is valid then it will * be logged to {@link #validSpanLogger}, and if it is invalid then it will be logged to {@link #invalidSpanLogger}. * * @param span The span to complete and log * @param containsIncorrectTimingInfo Pass in true if you know the given span contains incorrect timing information (e.g. a child sub-span that wasn't completed normally * when it was supposed to have been completed), pass in false if the span's timing info is good. This affects how the span is logged. */ protected void completeAndLogSpan(Span span, boolean containsIncorrectTimingInfo) { // Complete the span. if (span.isCompleted()) { classLogger.error( "WINGTIPS USAGE ERROR - An attempt was made to complete a span that was already completed. This call will be ignored. " + "wingtips_usage_error=true, already_completed_span=true, trace_id={}, span_id={}", span.getTraceId(), span.getSpanId(), new Exception("Stack trace for debugging purposes") ); return; } else span.complete(); // Log the span if it was sampleable. if (span.isSampleable()) { String infoTag = containsIncorrectTimingInfo ? "[INCORRECT_TIMING] " : ""; Logger loggerToUse = containsIncorrectTimingInfo ? invalidSpanLogger : validSpanLogger; loggerToUse.info("{}[DISTRIBUTED_TRACING] {}", infoTag, serializeSpanToDesiredStringRepresentation(span)); } // Notify listeners. notifySpanCompleted(span); }
@Test(expected = IllegalStateException.class) public void complete_should_throw_IllegalStateException_if_span_is_already_completed() { // given Span validSpan = Span.generateRootSpanForNewTrace(spanName, spanPurpose).build(); validSpan.complete(); assertThat(validSpan.isCompleted()).isTrue(); // expect validSpan.complete(); fail("Expected IllegalStateException but no exception was thrown"); }
@Test public void complete_method_should_complete_the_span_with_correct_duration() throws InterruptedException { for (int i = 0; i < 10; i++) { // given Span validSpan = Span.generateRootSpanForNewTrace(spanName, spanPurpose).build(); assertThat(validSpan.isCompleted()).isFalse(); // when Thread.sleep((long) (Math.random() * 10)); long beforeCompleteNanoTime = System.nanoTime(); validSpan.complete(); long afterCompleteNanoTime = System.nanoTime(); // then assertThat(validSpan.isCompleted()).isTrue(); long lowerBoundDuration = beforeCompleteNanoTime - validSpan.getSpanStartTimeNanos(); long upperBoundDuration = afterCompleteNanoTime - validSpan.getSpanStartTimeNanos(); assertThat(validSpan.getDurationNanos()).isBetween(lowerBoundDuration, upperBoundDuration); } }
@Test public void spanLifecycleListener_spanCompleted_is_not_called_when_request_span_was_completed_already() { // given SpanLifecycleListener listener1 = mock(SpanLifecycleListener.class); SpanLifecycleListener listener2 = mock(SpanLifecycleListener.class); Tracer tracer = Tracer.getInstance(); tracer.addSpanLifecycleListener(listener1); tracer.addSpanLifecycleListener(listener2); Span span = tracer.startRequestWithRootSpan("newspan"); span.complete(); verify(listener1).spanStarted(span); verify(listener1, times(0)).spanCompleted(span); verify(listener2).spanStarted(span); verify(listener2, times(0)).spanCompleted(span); // when tracer.completeRequestSpan(); // then verify(listener1, never()).spanCompleted(span); verify(listener2, never()).spanCompleted(span); }
@Test public void spanLifecycleListener_spanCompleted_is_not_called_if_subspan_was_already_completed() { // given SpanLifecycleListener listener1 = mock(SpanLifecycleListener.class); SpanLifecycleListener listener2 = mock(SpanLifecycleListener.class); Tracer tracer = Tracer.getInstance(); tracer.addSpanLifecycleListener(listener1); tracer.addSpanLifecycleListener(listener2); tracer.startRequestWithRootSpan("newspan"); Span subspan = tracer.startSubSpan("subspan", SpanPurpose.LOCAL_ONLY); subspan.complete(); verify(listener1).spanStarted(subspan); verify(listener1, times(0)).spanCompleted(subspan); verify(listener2).spanStarted(subspan); verify(listener2, times(0)).spanCompleted(subspan); // when tracer.completeSubSpan(); // then verify(listener1, never()).spanCompleted(subspan); verify(listener2, never()).spanCompleted(subspan); }
@Test public void getDuration_should_be_null_until_span_is_completed() { // given Span validSpan = Span.generateRootSpanForNewTrace(spanName, spanPurpose).build(); assertThat(validSpan.getDurationNanos()).isNull(); // when validSpan.complete(); // then assertThat(validSpan.getDurationNanos()).isNotNull(); }