Skip to content

Commit bd813da

Browse files
dsd987bulldozer-bot[bot]
authored andcommitted
Restore trace state back to cleared when wrapWithNewTrace is called with no trace state. (#52)
Previously, when `Tracers::wrapWithNewTrace` was called with no trace state, the trace state would incorrectly be restored to a new trace rather than the cleared state. Now, the trace state will be appropriately returned to the cleared state.
1 parent 37719b4 commit bd813da

File tree

4 files changed

+78
-9
lines changed

4 files changed

+78
-9
lines changed

tracing/src/main/java/com/palantir/tracing/Tracer.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,13 @@ public static String getTraceId() {
270270
return Preconditions.checkNotNull(currentTrace.get(), "There is no root span").getTraceId();
271271
}
272272

273+
/** Clears the current trace id and returns it if present. */
274+
static Optional<Trace> getAndClearTraceIfPresent() {
275+
Optional<Trace> trace = Optional.ofNullable(currentTrace.get());
276+
clearCurrentTrace();
277+
return trace;
278+
}
279+
273280
/** Clears the current trace id and returns (a copy of) it. */
274281
public static Trace getAndClearTrace() {
275282
Trace trace = getOrCreateCurrentTrace();

tracing/src/main/java/com/palantir/tracing/Tracers.java

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -145,16 +145,15 @@ protected <T> Callable<T> wrapTask(Callable<T> callable) {
145145
public static <V> Callable<V> wrapWithNewTrace(Callable<V> delegate) {
146146
return () -> {
147147
// clear the existing trace and keep it around for restoration when we're done
148-
Trace originalTrace = Tracer.getAndClearTrace();
148+
Optional<Trace> originalTrace = Tracer.getAndClearTraceIfPresent();
149149

150150
try {
151151
Tracer.initTrace(Optional.empty(), Tracers.randomId());
152152
Tracer.startSpan(ROOT_SPAN_OPERATION);
153153
return delegate.call();
154154
} finally {
155155
Tracer.fastCompleteSpan();
156-
// restore the trace
157-
Tracer.setTrace(originalTrace);
156+
restoreTrace(originalTrace);
158157
}
159158
};
160159
}
@@ -165,16 +164,15 @@ public static <V> Callable<V> wrapWithNewTrace(Callable<V> delegate) {
165164
public static Runnable wrapWithNewTrace(Runnable delegate) {
166165
return () -> {
167166
// clear the existing trace and keep it around for restoration when we're done
168-
Trace originalTrace = Tracer.getAndClearTrace();
167+
Optional<Trace> originalTrace = Tracer.getAndClearTraceIfPresent();
169168

170169
try {
171170
Tracer.initTrace(Optional.empty(), Tracers.randomId());
172171
Tracer.startSpan(ROOT_SPAN_OPERATION);
173172
delegate.run();
174173
} finally {
175174
Tracer.fastCompleteSpan();
176-
// restore the trace
177-
Tracer.setTrace(originalTrace);
175+
restoreTrace(originalTrace);
178176
}
179177
};
180178
}
@@ -188,20 +186,32 @@ public static Runnable wrapWithNewTrace(Runnable delegate) {
188186
public static Runnable wrapWithAlternateTraceId(String traceId, Runnable delegate) {
189187
return () -> {
190188
// clear the existing trace and keep it around for restoration when we're done
191-
Trace originalTrace = Tracer.getAndClearTrace();
189+
Optional<Trace> originalTrace = Tracer.getAndClearTraceIfPresent();
192190

193191
try {
194192
Tracer.initTrace(Optional.empty(), traceId);
195193
Tracer.startSpan(ROOT_SPAN_OPERATION);
196194
delegate.run();
197195
} finally {
198196
Tracer.fastCompleteSpan();
199-
// restore the trace
200-
Tracer.setTrace(originalTrace);
197+
restoreTrace(originalTrace);
201198
}
202199
};
203200
}
204201

202+
/**
203+
* Restores or clears trace state based on provided {@link Trace}. Used to cleanup trace state for
204+
* {@link #wrapWithNewTrace} calls.
205+
*/
206+
private static void restoreTrace(Optional<Trace> trace) {
207+
if (trace.isPresent()) {
208+
Tracer.setTrace(trace.get());
209+
} else {
210+
// Ignoring returned value, used to clear trace only
211+
Tracer.getAndClearTraceIfPresent();
212+
}
213+
}
214+
205215
/**
206216
* Wraps a given callable such that its execution operates with the {@link Trace thread-local Trace} of the thread
207217
* that constructs the {@link TracingAwareCallable} instance rather than the thread that executes the callable.

tracing/src/test/java/com/palantir/tracing/TracerTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,19 @@ public void testFastCompleteSpanWithMetadata() {
251251
assertThat(spanCaptor.getValue().getMetadata()).isEqualTo(metadata);
252252
}
253253

254+
@Test
255+
public void testGetAndClearTraceIfPresent() {
256+
Trace trace = new Trace(true, "newTraceId");
257+
Tracer.setTrace(trace);
258+
259+
Optional<Trace> nonEmptyTrace = Tracer.getAndClearTraceIfPresent();
260+
assertThat(nonEmptyTrace).hasValue(trace);
261+
assertThat(Tracer.hasTraceId()).isFalse();
262+
263+
Optional<Trace> emptyTrace = Tracer.getAndClearTraceIfPresent();
264+
assertThat(emptyTrace).isEmpty();
265+
}
266+
254267
@Test
255268
public void testClearAndGetTraceClearsMdc() {
256269
Tracer.startSpan("test");

tracing/src/test/java/com/palantir/tracing/TracersTest.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@
2424
import java.util.Collections;
2525
import java.util.HashSet;
2626
import java.util.List;
27+
import java.util.Optional;
2728
import java.util.Set;
2829
import java.util.concurrent.Callable;
2930
import java.util.concurrent.ExecutorService;
3031
import java.util.concurrent.Executors;
3132
import java.util.concurrent.ScheduledExecutorService;
3233
import java.util.concurrent.TimeUnit;
3334
import java.util.concurrent.atomic.AtomicReference;
35+
import org.junit.After;
3436
import org.junit.Before;
3537
import org.junit.Test;
3638
import org.mockito.MockitoAnnotations;
@@ -42,6 +44,15 @@ public final class TracersTest {
4244
public void before() {
4345
MockitoAnnotations.initMocks(this);
4446
MDC.clear();
47+
48+
// Initialize a new trace for each test
49+
Tracer.initTrace(Optional.empty(), "defaultTraceId");
50+
}
51+
52+
@After
53+
public void after() {
54+
// Clear out the old trace from each test
55+
Tracer.getAndClearTraceIfPresent();
4556
}
4657

4758
@Test
@@ -243,6 +254,14 @@ public void testWrapCallableWithNewTrace_traceStateRestoredWhenThrows() throws E
243254
assertThat(Tracer.getTraceId()).isEqualTo(traceIdBeforeConstruction);
244255
}
245256

257+
@Test
258+
public void testWrapCallableWithNewTrace_traceStateRestoredToCleared() throws Exception {
259+
// Clear out the default initialized trace
260+
Tracer.getAndClearTraceIfPresent();
261+
Tracers.wrapWithNewTrace(() -> null).call();
262+
assertThat(Tracer.hasTraceId()).isFalse();
263+
}
264+
246265
@Test
247266
public void testWrapRunnableWithNewTrace_traceStateInsideRunnableIsIsolated() throws Exception {
248267
String traceIdBeforeConstruction = Tracer.getTraceId();
@@ -306,6 +325,16 @@ public void testWrapRunnableWithNewTrace_traceStateRestoredWhenThrows() throws E
306325
assertThat(Tracer.getTraceId()).isEqualTo(traceIdBeforeConstruction);
307326
}
308327

328+
@Test
329+
public void testWrapRunnableWithNewTrace_traceStateRestoredToCleared() {
330+
// Clear out the default initialized trace
331+
Tracer.getAndClearTraceIfPresent();
332+
Tracers.wrapWithNewTrace(() -> {
333+
// no-op
334+
}).run();
335+
assertThat(Tracer.hasTraceId()).isFalse();
336+
}
337+
309338
@Test
310339
public void testWrapRunnableWithAlternateTraceId_traceStateInsideRunnableUsesGivenTraceId() {
311340
String traceIdBeforeConstruction = Tracer.getTraceId();
@@ -358,6 +387,16 @@ public void testWrapRunnableWithAlternateTraceId_traceStateRestoredWhenThrows()
358387
assertThat(Tracer.getTraceId()).isEqualTo(traceIdBeforeConstruction);
359388
}
360389

390+
@Test
391+
public void testWrapRunnableWithAlternateTraceId_traceStateRestoredToCleared() {
392+
// Clear out the default initialized trace
393+
Tracer.getAndClearTraceIfPresent();
394+
Tracers.wrapWithAlternateTraceId("someTraceId", () -> {
395+
// no-op
396+
}).run();
397+
assertThat(Tracer.hasTraceId()).isFalse();
398+
}
399+
361400
@Test
362401
public void testTraceIdGeneration() throws Exception {
363402
assertThat(Tracers.randomId()).hasSize(16); // fails with p=1/16 if generated string is not padded

0 commit comments

Comments
 (0)