Skip to content

Commit 74f46d4

Browse files
pkoenig10bulldozer-bot[bot]
authored andcommitted
[improvement] Add methods to set span operation when wrapping with a new trace (#59)
## Before this PR When calling any of the `wrapWithNewTrace` methods, the operation of the initial span would be set to "root". This makes it difficult to determine the origin of traces if `wrapWithNewTrace` is used in more than one place. ## After this PR `Tracers` now provides variants of the `wrapWithNewTrace` methods that allow callers to explicitly set the initial span operation. Follow up to #49.
1 parent 2597bae commit 74f46d4

File tree

2 files changed

+129
-30
lines changed

2 files changed

+129
-30
lines changed

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

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.palantir.tracing;
1818

19+
import com.google.errorprone.annotations.CompileTimeConstant;
1920
import java.util.Optional;
2021
import java.util.concurrent.Callable;
2122
import java.util.concurrent.ExecutorService;
@@ -104,52 +105,75 @@ public static Runnable wrap(Runnable delegate) {
104105
return new TracingAwareRunnable(delegate);
105106
}
106107

108+
/**
109+
* Like {@link #wrapWithNewTrace(String, ExecutorService)}, but with a default initial span operation.
110+
*/
111+
public static ExecutorService wrapWithNewTrace(ExecutorService executorService) {
112+
return wrapWithNewTrace(ROOT_SPAN_OPERATION, executorService);
113+
}
114+
107115
/**
108116
* Wraps the provided executor service to make submitted tasks traceable with a fresh {@link Trace trace}
109-
* for each execution, see {@link #wrapWithNewTrace(ExecutorService)}. This method should not be used to
117+
* for each execution, see {@link #wrapWithNewTrace(String, ExecutorService)}. This method should not be used to
110118
* wrap a ScheduledExecutorService that has already been {@link #wrap(ExecutorService) wrapped}. If this is
111119
* done, a new trace will be generated for each execution, effectively bypassing the intent of the previous
112-
* wrapping.
120+
* wrapping. The given {@link String operation} is used to create the initial span.
113121
*/
114-
public static ExecutorService wrapWithNewTrace(ExecutorService executorService) {
122+
public static ExecutorService wrapWithNewTrace(@CompileTimeConstant String operation,
123+
ExecutorService executorService) {
115124
return new WrappingExecutorService(executorService) {
116125
@Override
117126
protected <T> Callable<T> wrapTask(Callable<T> callable) {
118-
return wrapWithNewTrace(callable);
127+
return wrapWithNewTrace(operation, callable);
119128
}
120129
};
121130
}
122131

123132
/**
124-
* Wraps the provided scheduled executor service to make submitted tasks traceable with a fresh {@link Trace trace}
125-
* for each execution, see {@link #wrapWithNewTrace(ScheduledExecutorService)}. This method should not be used to
126-
* wrap a ScheduledExecutorService that has already been {@link #wrap(ScheduledExecutorService) wrapped}. If this is
127-
* done, a new trace will be generated for each execution, effectively bypassing the intent of the previous
128-
* wrapping.
133+
* Like {@link #wrapWithNewTrace(String, ScheduledExecutorService)}, but with a default initial span operation.
129134
*/
130135
public static ScheduledExecutorService wrapWithNewTrace(ScheduledExecutorService executorService) {
136+
return wrapWithNewTrace(ROOT_SPAN_OPERATION, executorService);
137+
}
138+
139+
/**
140+
* Wraps the provided scheduled executor service to make submitted tasks traceable with a fresh {@link Trace trace}
141+
* for each execution, see {@link #wrapWithNewTrace(String, ScheduledExecutorService)}. This method should not be
142+
* used to wrap a ScheduledExecutorService that has already been {@link #wrap(ScheduledExecutorService) wrapped}.
143+
* If this is done, a new trace will be generated for each execution, effectively bypassing the intent of the
144+
* previous wrapping. The given {@link String operation} is used to create the initial span.
145+
*/
146+
public static ScheduledExecutorService wrapWithNewTrace(@CompileTimeConstant String operation,
147+
ScheduledExecutorService executorService) {
131148
return new WrappingScheduledExecutorService(executorService) {
132149
@Override
133150
protected <T> Callable<T> wrapTask(Callable<T> callable) {
134-
return wrapWithNewTrace(callable);
151+
return wrapWithNewTrace(operation, callable);
135152
}
136153
};
137154
}
138155

156+
/**
157+
* Like {@link #wrapWithNewTrace(String, Callable)}, but with a default initial span operation.
158+
*/
159+
public static <V> Callable<V> wrapWithNewTrace(Callable<V> delegate) {
160+
return wrapWithNewTrace(ROOT_SPAN_OPERATION, delegate);
161+
}
162+
139163
/**
140164
* Wraps the given {@link Callable} such that it creates a fresh {@link Trace tracing state} for its execution.
141165
* That is, the trace during its {@link Callable#call() execution} is entirely separate from the trace at
142166
* construction or any trace already set on the thread used to execute the callable. Each execution of the callable
143-
* will have a fresh trace.
167+
* will have a fresh trace. The given {@link String operation} is used to create the initial span.
144168
*/
145-
public static <V> Callable<V> wrapWithNewTrace(Callable<V> delegate) {
169+
public static <V> Callable<V> wrapWithNewTrace(@CompileTimeConstant String operation, Callable<V> delegate) {
146170
return () -> {
147171
// clear the existing trace and keep it around for restoration when we're done
148172
Optional<Trace> originalTrace = Tracer.getAndClearTraceIfPresent();
149173

150174
try {
151175
Tracer.initTrace(Optional.empty(), Tracers.randomId());
152-
Tracer.startSpan(ROOT_SPAN_OPERATION);
176+
Tracer.startSpan(operation);
153177
return delegate.call();
154178
} finally {
155179
Tracer.fastCompleteSpan();
@@ -159,16 +183,23 @@ public static <V> Callable<V> wrapWithNewTrace(Callable<V> delegate) {
159183
}
160184

161185
/**
162-
* Like {@link #wrapWithNewTrace(Callable)}, but for Runnables.
186+
* Like {@link #wrapWithAlternateTraceId(String, Runnable)}, but with a default initial span operation.
163187
*/
164188
public static Runnable wrapWithNewTrace(Runnable delegate) {
189+
return wrapWithNewTrace(ROOT_SPAN_OPERATION, delegate);
190+
}
191+
192+
/**
193+
* Like {@link #wrapWithNewTrace(String, Callable)}, but for Runnables.
194+
*/
195+
public static Runnable wrapWithNewTrace(@CompileTimeConstant String operation, Runnable delegate) {
165196
return () -> {
166197
// clear the existing trace and keep it around for restoration when we're done
167198
Optional<Trace> originalTrace = Tracer.getAndClearTraceIfPresent();
168199

169200
try {
170201
Tracer.initTrace(Optional.empty(), Tracers.randomId());
171-
Tracer.startSpan(ROOT_SPAN_OPERATION);
202+
Tracer.startSpan(operation);
172203
delegate.run();
173204
} finally {
174205
Tracer.fastCompleteSpan();
@@ -177,20 +208,29 @@ public static Runnable wrapWithNewTrace(Runnable delegate) {
177208
};
178209
}
179210

211+
/**
212+
* Like {@link #wrapWithAlternateTraceId(String, String, Runnable)}, but with a default initial span operation.
213+
*/
214+
public static Runnable wrapWithAlternateTraceId(String traceId, Runnable delegate) {
215+
return wrapWithAlternateTraceId(traceId, ROOT_SPAN_OPERATION, delegate);
216+
}
217+
180218
/**
181219
* Wraps the given {@link Runnable} such that it creates a fresh {@link Trace tracing state with the given traceId}
182220
* for its execution. That is, the trace during its {@link Runnable#run() execution} will use the traceId provided
183221
* instead of any trace already set on the thread used to execute the runnable. Each execution of the runnable
184-
* will use a new {@link Trace tracing state} with the same given traceId.
222+
* will use a new {@link Trace tracing state} with the same given traceId. The given {@link String operation} is
223+
* used to create the initial span.
185224
*/
186-
public static Runnable wrapWithAlternateTraceId(String traceId, Runnable delegate) {
225+
public static Runnable wrapWithAlternateTraceId(String traceId, @CompileTimeConstant String operation, Runnable
226+
delegate) {
187227
return () -> {
188228
// clear the existing trace and keep it around for restoration when we're done
189229
Optional<Trace> originalTrace = Tracer.getAndClearTraceIfPresent();
190230

191231
try {
192232
Tracer.initTrace(Optional.empty(), traceId);
193-
Tracer.startSpan(ROOT_SPAN_OPERATION);
233+
Tracer.startSpan(operation);
194234
delegate.run();
195235
} finally {
196236
Tracer.fastCompleteSpan();

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

Lines changed: 71 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,10 @@ public void testScheduledExecutorServiceWrapsCallables() throws Exception {
9696
@Test
9797
public void testScheduledExecutorServiceWrapsCallablesWithNewTraces() throws Exception {
9898
ScheduledExecutorService wrappedService =
99-
Tracers.wrapWithNewTrace(Executors.newSingleThreadScheduledExecutor());
99+
Tracers.wrapWithNewTrace("operationToUse", Executors.newSingleThreadScheduledExecutor());
100100

101-
Callable<Void> callable = newTraceExpectingCallable();
102-
Runnable runnable = newTraceExpectingRunnable();
101+
Callable<Void> callable = newTraceExpectingCallable("operationToUse");
102+
Runnable runnable = newTraceExpectingRunnable("operationToUse");
103103

104104
// Empty trace
105105
wrappedService.schedule(callable, 0, TimeUnit.SECONDS).get();
@@ -122,10 +122,10 @@ public void testScheduledExecutorServiceWrapsCallablesWithNewTraces() throws Exc
122122
@Test
123123
public void testExecutorServiceWrapsCallablesWithNewTraces() throws Exception {
124124
ExecutorService wrappedService =
125-
Tracers.wrapWithNewTrace(Executors.newSingleThreadExecutor());
125+
Tracers.wrapWithNewTrace("operationToUse", Executors.newSingleThreadExecutor());
126126

127-
Callable<Void> callable = newTraceExpectingCallable();
128-
Runnable runnable = newTraceExpectingRunnable();
127+
Callable<Void> callable = newTraceExpectingCallable("operationToUse");
128+
Runnable runnable = newTraceExpectingRunnable("operationToUse");
129129

130130
// Empty trace
131131
wrappedService.submit(callable).get();
@@ -241,6 +241,22 @@ public void testWrapCallableWithNewTrace_traceStateInsideCallableHasSpan() throw
241241
assertThat(span.getParentSpanId()).isEmpty();
242242
}
243243

244+
@Test
245+
public void testWrapCallableWithNewTrace_traceStateInsideCallableHasGivenSpan() throws Exception {
246+
Callable<List<OpenSpan>> wrappedCallable = Tracers.wrapWithNewTrace("someOperation", () -> {
247+
return getCurrentFullTrace();
248+
});
249+
250+
List<OpenSpan> spans = wrappedCallable.call();
251+
252+
assertThat(spans).hasSize(1);
253+
254+
OpenSpan span = spans.get(0);
255+
256+
assertThat(span.getOperation()).isEqualTo("someOperation");
257+
assertThat(span.getParentSpanId()).isEmpty();
258+
}
259+
244260
@Test
245261
public void testWrapCallableWithNewTrace_traceStateRestoredWhenThrows() throws Exception {
246262
String traceIdBeforeConstruction = Tracer.getTraceId();
@@ -312,7 +328,25 @@ public void testWrapRunnableWithNewTrace_traceStateInsideRunnableHasSpan() throw
312328
}
313329

314330
@Test
315-
public void testWrapRunnableWithNewTrace_traceStateRestoredWhenThrows() throws Exception {
331+
public void testWrapRunnableWithNewTrace_traceStateInsideRunnableHasGivenSpan() throws Exception {
332+
List<List<OpenSpan>> spans = Lists.newArrayList();
333+
334+
Runnable wrappedRunnable = Tracers.wrapWithNewTrace("someOperation", () -> {
335+
spans.add(getCurrentFullTrace());
336+
});
337+
338+
wrappedRunnable.run();
339+
340+
assertThat(spans.get(0)).hasSize(1);
341+
342+
OpenSpan span = spans.get(0).get(0);
343+
344+
assertThat(span.getOperation()).isEqualTo("someOperation");
345+
assertThat(span.getParentSpanId()).isEmpty();
346+
}
347+
348+
@Test
349+
public void testWrapRunnableWithNewTrace_traceStateRestoredWhenThrows() {
316350
String traceIdBeforeConstruction = Tracer.getTraceId();
317351

318352
Runnable rawRunnable = () -> {
@@ -357,7 +391,7 @@ public void testWrapRunnableWithAlternateTraceId_traceStateInsideRunnableUsesGiv
357391
}
358392

359393
@Test
360-
public void testWrapRunnableWithAlternateTraceId_traceStateInsideRunnableHasSpan() throws Exception {
394+
public void testWrapRunnableWithAlternateTraceId_traceStateInsideRunnableHasSpan() {
361395
List<List<OpenSpan>> spans = Lists.newArrayList();
362396

363397
String traceIdToUse = "someTraceId";
@@ -375,6 +409,25 @@ public void testWrapRunnableWithAlternateTraceId_traceStateInsideRunnableHasSpan
375409
assertThat(span.getParentSpanId()).isEmpty();
376410
}
377411

412+
@Test
413+
public void testWrapRunnableWithAlternateTraceId_traceStateInsideRunnableHasGivenSpan() {
414+
List<List<OpenSpan>> spans = Lists.newArrayList();
415+
416+
String traceIdToUse = "someTraceId";
417+
Runnable wrappedRunnable = Tracers.wrapWithAlternateTraceId(traceIdToUse, "someOperation", () -> {
418+
spans.add(getCurrentFullTrace());
419+
});
420+
421+
wrappedRunnable.run();
422+
423+
assertThat(spans.get(0)).hasSize(1);
424+
425+
OpenSpan span = spans.get(0).get(0);
426+
427+
assertThat(span.getOperation()).isEqualTo("someOperation");
428+
assertThat(span.getParentSpanId()).isEmpty();
429+
}
430+
378431
@Test
379432
public void testWrapRunnableWithAlternateTraceId_traceStateRestoredWhenThrows() {
380433
String traceIdBeforeConstruction = Tracer.getTraceId();
@@ -406,36 +459,42 @@ public void testTraceIdGeneration() throws Exception {
406459
assertThat(Tracers.longToPaddedHex(123456789L)).isEqualTo("00000000075bcd15");
407460
}
408461

409-
private static Callable<Void> newTraceExpectingCallable() {
462+
private static Callable<Void> newTraceExpectingCallable(String expectedOperation) {
410463
final Set<String> seenTraceIds = new HashSet<>();
411464
seenTraceIds.add(Tracer.getTraceId());
412465

413466
return new Callable<Void>() {
414467
@Override
415468
public Void call() throws Exception {
416469
String newTraceId = Tracer.getTraceId();
470+
List<OpenSpan> spans = getCurrentFullTrace();
417471

418472
assertThat(MDC.get(Tracers.TRACE_ID_KEY)).isEqualTo(newTraceId);
419473
assertThat(seenTraceIds).doesNotContain(newTraceId);
420-
assertThat(getCurrentFullTrace()).hasSize(1);
474+
assertThat(spans).hasSize(1);
475+
assertThat(spans.get(0).getOperation()).isEqualTo(expectedOperation);
476+
assertThat(spans.get(0).getParentSpanId()).isEmpty();
421477
seenTraceIds.add(newTraceId);
422478
return null;
423479
}
424480
};
425481
}
426482

427-
private static Runnable newTraceExpectingRunnable() {
483+
private static Runnable newTraceExpectingRunnable(String expectedOperation) {
428484
final Set<String> seenTraceIds = new HashSet<>();
429485
seenTraceIds.add(Tracer.getTraceId());
430486

431487
return new Runnable() {
432488
@Override
433489
public void run() {
434490
String newTraceId = Tracer.getTraceId();
491+
List<OpenSpan> spans = getCurrentFullTrace();
435492

436493
assertThat(MDC.get(Tracers.TRACE_ID_KEY)).isEqualTo(newTraceId);
437494
assertThat(seenTraceIds).doesNotContain(newTraceId);
438-
assertThat(getCurrentFullTrace()).hasSize(1);
495+
assertThat(spans).hasSize(1);
496+
assertThat(spans.get(0).getOperation()).isEqualTo(expectedOperation);
497+
assertThat(spans.get(0).getParentSpanId()).isEmpty();
439498
seenTraceIds.add(newTraceId);
440499
}
441500
};

0 commit comments

Comments
 (0)