Skip to content

Commit 2be9de2

Browse files
committed
feat(gax): verify T3/T4 span hierarchy and retry aggregation
1 parent 922962c commit 2be9de2

1 file changed

Lines changed: 95 additions & 0 deletions

File tree

‎sdk-platform-java/gax-java/gax/src/test/java/com/google/api/gax/tracing/OpenTelemetryTracingTracerIntegrationTest.java‎

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@
4444
import io.opentelemetry.sdk.trace.SdkTracerProvider;
4545
import io.opentelemetry.sdk.trace.data.SpanData;
4646
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
47+
import java.time.Duration;
4748
import java.util.List;
49+
import java.util.stream.Collectors;
4850
import org.junit.jupiter.api.AfterEach;
4951
import org.junit.jupiter.api.BeforeEach;
5052
import org.junit.jupiter.api.Test;
@@ -257,4 +259,97 @@ void testAttemptStarted_afterOperationCompleted_doesNotEmitNewSpan() {
257259
assertThat(finishedSpans).hasSize(1);
258260
assertThat(finishedSpans.get(0).getKind()).isEqualTo(SpanKind.INTERNAL);
259261
}
262+
263+
@Test
264+
void testRetrySucceeds_operationAggregatesSuccessAttributes() {
265+
ApiTracer apiTracer = tracingFactory.newTracer(BaseApiTracer.getInstance(), TRACER_CONTEXT);
266+
267+
// Attempt 0 fails with transient error
268+
apiTracer.attemptStarted(new Object(), 0);
269+
apiTracer.attemptFailedDuration(new RuntimeException("transient 503"), Duration.ofMillis(10));
270+
271+
// Attempt 1 succeeds
272+
apiTracer.attemptStarted(new Object(), 1);
273+
apiTracer.attemptSucceeded();
274+
apiTracer.operationSucceeded();
275+
276+
List<SpanData> finishedSpans = spanExporter.getFinishedSpanItems();
277+
assertThat(finishedSpans).hasSize(3); // attempt 0, attempt 1, operation
278+
279+
SpanData operationSpan =
280+
finishedSpans.stream()
281+
.filter(s -> s.getKind() == SpanKind.INTERNAL)
282+
.findFirst()
283+
.orElseThrow(() -> new AssertionError("Operation span not found"));
284+
285+
List<SpanData> attemptSpans =
286+
finishedSpans.stream()
287+
.filter(s -> s.getKind() == SpanKind.CLIENT)
288+
.collect(Collectors.toList());
289+
assertThat(attemptSpans).hasSize(2);
290+
291+
for (SpanData attempt : attemptSpans) {
292+
assertThat(attempt.getParentSpanId()).isEqualTo(operationSpan.getSpanContext().getSpanId());
293+
}
294+
295+
assertThat(operationSpan.getStatus().getStatusCode())
296+
.isEqualTo(io.opentelemetry.api.trace.StatusCode.UNSET);
297+
assertThat(
298+
operationSpan
299+
.getAttributes()
300+
.get(AttributeKey.stringKey(ObservabilityAttributes.RPC_RESPONSE_STATUS_ATTRIBUTE)))
301+
.isEqualTo("OK");
302+
assertThat(
303+
operationSpan
304+
.getAttributes()
305+
.get(AttributeKey.stringKey(ObservabilityAttributes.ERROR_TYPE_ATTRIBUTE)))
306+
.isNull();
307+
}
308+
309+
@Test
310+
void testRetriesExhausted_operationAggregatesFailureAttributes() {
311+
ApiTracer apiTracer = tracingFactory.newTracer(BaseApiTracer.getInstance(), TRACER_CONTEXT);
312+
313+
// Attempt 0 fails with transient error
314+
apiTracer.attemptStarted(new Object(), 0);
315+
apiTracer.attemptFailedDuration(new RuntimeException("transient 503"), Duration.ofMillis(10));
316+
317+
// Attempt 1 fails and exhausts retries
318+
apiTracer.attemptStarted(new Object(), 1);
319+
RuntimeException finalError = new RuntimeException("unavailable: retries exhausted");
320+
apiTracer.attemptFailedRetriesExhausted(finalError);
321+
apiTracer.operationFailed(finalError);
322+
323+
List<SpanData> finishedSpans = spanExporter.getFinishedSpanItems();
324+
assertThat(finishedSpans).hasSize(3); // attempt 0, attempt 1, operation
325+
326+
SpanData operationSpan =
327+
finishedSpans.stream()
328+
.filter(s -> s.getKind() == SpanKind.INTERNAL)
329+
.findFirst()
330+
.orElseThrow(() -> new AssertionError("Operation span not found"));
331+
332+
List<SpanData> attemptSpans =
333+
finishedSpans.stream()
334+
.filter(s -> s.getKind() == SpanKind.CLIENT)
335+
.collect(Collectors.toList());
336+
assertThat(attemptSpans).hasSize(2);
337+
338+
for (SpanData attempt : attemptSpans) {
339+
assertThat(attempt.getParentSpanId()).isEqualTo(operationSpan.getSpanContext().getSpanId());
340+
}
341+
342+
assertThat(operationSpan.getStatus().getStatusCode())
343+
.isEqualTo(io.opentelemetry.api.trace.StatusCode.ERROR);
344+
assertThat(
345+
operationSpan
346+
.getAttributes()
347+
.get(AttributeKey.stringKey(ObservabilityAttributes.STATUS_MESSAGE_ATTRIBUTE)))
348+
.isEqualTo("unavailable: retries exhausted");
349+
assertThat(
350+
operationSpan
351+
.getAttributes()
352+
.get(AttributeKey.stringKey(ObservabilityAttributes.ERROR_TYPE_ATTRIBUTE)))
353+
.isNotNull();
354+
}
260355
}

0 commit comments

Comments
 (0)