diff --git a/changelog/@unreleased/pr-624.v2.yml b/changelog/@unreleased/pr-624.v2.yml new file mode 100644 index 000000000..8cf491d60 --- /dev/null +++ b/changelog/@unreleased/pr-624.v2.yml @@ -0,0 +1,6 @@ +type: improvement +improvement: + description: Add `Tracer.hasUnobservableTrace()` API to simplify tracing framework + implementations. + links: + - https://github.com/palantir/tracing-java/pull/624 diff --git a/tracing/src/main/java/com/palantir/tracing/Tracer.java b/tracing/src/main/java/com/palantir/tracing/Tracer.java index 2b33ff1d6..9688f2d63 100644 --- a/tracing/src/main/java/com/palantir/tracing/Tracer.java +++ b/tracing/src/main/java/com/palantir/tracing/Tracer.java @@ -627,6 +627,16 @@ public static boolean isTraceObservable() { return trace != null && trace.isObservable(); } + /** + * Returns true if there is an active trace which is not observable. This is equivalent to the result of + * {@code Tracer.hasTraceId() && !Tracer.isTraceObservable()}. + * This check is used frequently in hot paths to avoid unnecessary overhead in unsampled traces. + */ + public static boolean hasUnobservableTrace() { + Trace trace = currentTrace.get(); + return trace != null && !trace.isObservable(); + } + /** Returns an independent copy of this thread's {@link Trace}. */ static Optional copyTrace() { Trace trace = currentTrace.get(); diff --git a/tracing/src/test/java/com/palantir/tracing/TracerTest.java b/tracing/src/test/java/com/palantir/tracing/TracerTest.java index e24796ae8..e5ea8f617 100644 --- a/tracing/src/test/java/com/palantir/tracing/TracerTest.java +++ b/tracing/src/test/java/com/palantir/tracing/TracerTest.java @@ -157,11 +157,13 @@ public void testCountsSpansWhenTraceIsNotObservable() throws Exception { String traceId = Tracers.randomId(); assertThat(MDC.get(Tracers.TRACE_ID_KEY)).isNull(); assertThat(Tracer.hasTraceId()).isFalse(); + assertThat(Tracer.hasUnobservableTrace()).isFalse(); Tracer.setTrace(Trace.of(false, traceId, Optional.empty())); // Unsampled trace should still apply thread state assertThat(MDC.get(Tracers.TRACE_ID_KEY)).isEqualTo(traceId); assertThat(Tracer.hasTraceId()).isTrue(); assertThat(Tracer.getTraceId()).isEqualTo(traceId); + assertThat(Tracer.hasUnobservableTrace()).isTrue(); Tracer.fastStartSpan("foo"); Tracer.fastStartSpan("bar"); @@ -175,6 +177,7 @@ public void testCountsSpansWhenTraceIsNotObservable() throws Exception { Tracer.fastCompleteSpan(); assertThat(MDC.get(Tracers.TRACE_ID_KEY)).isNull(); assertThat(Tracer.hasTraceId()).isFalse(); + assertThat(Tracer.hasUnobservableTrace()).isFalse(); } @Test @@ -356,6 +359,36 @@ public void testHasTraceId() { assertThat(Tracer.hasTraceId()).isFalse(); } + @Test + public void testHasUnobservableTrace_observableTrace() { + Tracer.setSampler(AlwaysSampler.INSTANCE); + assertThat(Tracer.hasTraceId()).isFalse(); + assertThat(Tracer.hasUnobservableTrace()).isFalse(); + Tracer.fastStartSpan("test"); + try { + assertThat(Tracer.hasTraceId()).isTrue(); + assertThat(Tracer.hasUnobservableTrace()).isFalse(); + } finally { + Tracer.fastCompleteSpan(); + } + assertThat(Tracer.hasUnobservableTrace()).isFalse(); + } + + @Test + public void testHasUnobservableTrace_unobservableTrace() { + Tracer.setSampler(NeverSampler.INSTANCE); + assertThat(Tracer.hasTraceId()).isFalse(); + assertThat(Tracer.hasUnobservableTrace()).isFalse(); + Tracer.fastStartSpan("test"); + try { + assertThat(Tracer.hasTraceId()).isTrue(); + assertThat(Tracer.hasUnobservableTrace()).isTrue(); + } finally { + Tracer.fastCompleteSpan(); + } + assertThat(Tracer.hasUnobservableTrace()).isFalse(); + } + @Test public void testSimpleDetachedTrace() { assertThat(Tracer.hasTraceId()).isFalse();