diff --git a/sdk-platform-java/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelTracing.java b/sdk-platform-java/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelTracing.java index 5825003cf0f7..36223ba35797 100644 --- a/sdk-platform-java/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelTracing.java +++ b/sdk-platform-java/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelTracing.java @@ -51,6 +51,8 @@ import com.google.showcase.v1beta1.EchoRequest; import com.google.showcase.v1beta1.EchoResponse; import com.google.showcase.v1beta1.EchoSettings; +import com.google.showcase.v1beta1.GetUserRequest; +import com.google.showcase.v1beta1.IdentityClient; import com.google.showcase.v1beta1.it.util.TestClientInitializer; import com.google.showcase.v1beta1.stub.EchoStub; import com.google.showcase.v1beta1.stub.EchoStubSettings; @@ -89,6 +91,39 @@ class ITOtelTracing { private static final String SHOWCASE_ARTIFACT = "com.google.cloud:gapic-showcase"; private static final String SHOWCASE_USER_URL = "http://localhost:7469/v1beta1/echo:echo"; + // Attribute Keys + private static final AttributeKey RPC_SYSTEM_KEY = + AttributeKey.stringKey(ObservabilityAttributes.RPC_SYSTEM_NAME_ATTRIBUTE); + private static final AttributeKey RPC_RESPONSE_STATUS_KEY = + AttributeKey.stringKey(ObservabilityAttributes.RPC_RESPONSE_STATUS_ATTRIBUTE); + private static final AttributeKey HTTP_RESPONSE_STATUS_KEY = + AttributeKey.longKey(ObservabilityAttributes.HTTP_RESPONSE_STATUS_ATTRIBUTE); + private static final AttributeKey REPO_KEY = + AttributeKey.stringKey(ObservabilityAttributes.REPO_ATTRIBUTE); + private static final AttributeKey ARTIFACT_KEY = + AttributeKey.stringKey(ObservabilityAttributes.ARTIFACT_ATTRIBUTE); + private static final AttributeKey ERROR_TYPE_KEY = + AttributeKey.stringKey(ObservabilityAttributes.ERROR_TYPE_ATTRIBUTE); + private static final AttributeKey EXCEPTION_TYPE_KEY = + AttributeKey.stringKey(ObservabilityAttributes.EXCEPTION_TYPE_ATTRIBUTE); + private static final AttributeKey STATUS_MESSAGE_KEY = + AttributeKey.stringKey(ObservabilityAttributes.STATUS_MESSAGE_ATTRIBUTE); + private static final AttributeKey DESTINATION_RESOURCE_ID_KEY = + AttributeKey.stringKey(ObservabilityAttributes.DESTINATION_RESOURCE_ID_ATTRIBUTE); + + // Expected Values + private static final String VALUE_GRPC = "grpc"; + private static final String VALUE_HTTP = "http"; + private static final String VALUE_OK = "OK"; + private static final String VALUE_TEST_USER = "users/test-user"; + private static final String VALUE_UNAVAILABLE = "UNAVAILABLE"; + private static final String VALUE_UNAVAILABLE_EXCEPTION = "UnavailableException"; + private static final String VALUE_SERVICE_UNAVAILABLE = "Service Unavailable"; + private static final String SPAN_NAME_ECHO_GRPC = "google.showcase.v1beta1.Echo/Echo"; + private static final String SPAN_NAME_ECHO_HTTP = "POST v1beta1/echo:echo"; + private static final String SPAN_NAME_GET_USER_GRPC = "google.showcase.v1beta1.Identity/GetUser"; + private static final String SPAN_NAME_GET_USER_HTTP = "GET v1beta1/{name=users/*}"; + private InMemorySpanExporter spanExporter; private OpenTelemetrySdk openTelemetrySdk; @@ -129,7 +164,7 @@ void testTracing_successfulEcho_grpc() throws Exception { SpanData attemptSpan = spans.stream() - .filter(span -> span.getName().equals("google.showcase.v1beta1.Echo/Echo")) + .filter(span -> span.getName().equals(SPAN_NAME_ECHO_GRPC)) .findFirst() .orElseThrow(() -> new AssertionError("Incorrect span name")); assertThat(attemptSpan.getKind()).isEqualTo(SpanKind.CLIENT); @@ -143,21 +178,11 @@ void testTracing_successfulEcho_grpc() throws Exception { .getAttributes() .get(AttributeKey.longKey(ObservabilityAttributes.SERVER_PORT_ATTRIBUTE))) .isEqualTo(SHOWCASE_SERVER_PORT); - assertThat( - attemptSpan - .getAttributes() - .get(AttributeKey.stringKey(ObservabilityAttributes.REPO_ATTRIBUTE))) - .isEqualTo(SHOWCASE_REPO); - assertThat( - attemptSpan - .getAttributes() - .get(AttributeKey.stringKey(ObservabilityAttributes.ARTIFACT_ATTRIBUTE))) - .isEqualTo(SHOWCASE_ARTIFACT); - assertThat( - attemptSpan - .getAttributes() - .get(AttributeKey.stringKey(ObservabilityAttributes.RPC_SYSTEM_NAME_ATTRIBUTE))) - .isEqualTo("grpc"); + assertThat(attemptSpan.getAttributes().get(RPC_SYSTEM_KEY)).isEqualTo(VALUE_GRPC); + assertThat(attemptSpan.getAttributes().get(RPC_RESPONSE_STATUS_KEY)).isEqualTo(VALUE_OK); + assertThat(attemptSpan.getAttributes().get(REPO_KEY)).isEqualTo(SHOWCASE_REPO); + assertThat(attemptSpan.getAttributes().get(ARTIFACT_KEY)).isEqualTo(SHOWCASE_ARTIFACT); + assertThat( attemptSpan .getAttributes() @@ -209,7 +234,7 @@ void testTracing_successfulEcho_httpjson() throws Exception { SpanData attemptSpan = spans.stream() - .filter(span -> span.getName().equals("POST v1beta1/echo:echo")) + .filter(span -> span.getName().equals(SPAN_NAME_ECHO_HTTP)) .findFirst() .orElseThrow( () -> new AssertionError("Attempt span 'POST v1beta1/echo:echo' not found")); @@ -224,16 +249,10 @@ void testTracing_successfulEcho_httpjson() throws Exception { .getAttributes() .get(AttributeKey.longKey(ObservabilityAttributes.SERVER_PORT_ATTRIBUTE))) .isEqualTo(SHOWCASE_SERVER_PORT); - assertThat( - attemptSpan - .getAttributes() - .get(AttributeKey.stringKey(ObservabilityAttributes.REPO_ATTRIBUTE))) - .isEqualTo(SHOWCASE_REPO); - assertThat( - attemptSpan - .getAttributes() - .get(AttributeKey.stringKey(ObservabilityAttributes.ARTIFACT_ATTRIBUTE))) - .isEqualTo(SHOWCASE_ARTIFACT); + assertThat(attemptSpan.getAttributes().get(RPC_SYSTEM_KEY)).isEqualTo(VALUE_HTTP); + assertThat(attemptSpan.getAttributes().get(HTTP_RESPONSE_STATUS_KEY)).isEqualTo(200L); + assertThat(attemptSpan.getAttributes().get(REPO_KEY)).isEqualTo(SHOWCASE_REPO); + assertThat(attemptSpan.getAttributes().get(ARTIFACT_KEY)).isEqualTo(SHOWCASE_ARTIFACT); assertThat( attemptSpan .getAttributes() @@ -293,6 +312,60 @@ private long computeExpectedHttpJsonResponseSize(Message message) return jsonPayload.getBytes(StandardCharsets.UTF_8).length; } + @Test + void testTracing_successfulIdentityGetUser_grpc() throws Exception { + SpanTracerFactory tracingFactory = new SpanTracerFactory(openTelemetrySdk); + + try (IdentityClient client = + TestClientInitializer.createGrpcIdentityClientOpentelemetry(tracingFactory)) { + + try { + client.getUser(GetUserRequest.newBuilder().setName("users/test-user").build()); + } catch (Exception e) { + // Ignored, the showcase server may not have this user, but trace is still + // generated. + } + + List spans = spanExporter.getFinishedSpanItems(); + assertThat(spans).isNotEmpty(); + + SpanData attemptSpan = + spans.stream() + .filter(span -> span.getName().equals(SPAN_NAME_GET_USER_GRPC)) + .findFirst() + .orElseThrow(() -> new AssertionError("Incorrect span name")); + assertThat(attemptSpan.getAttributes().get(DESTINATION_RESOURCE_ID_KEY)) + .isEqualTo(VALUE_TEST_USER); + } + } + + @Test + void testTracing_successfulIdentityGetUser_httpjson() throws Exception { + SpanTracerFactory tracingFactory = new SpanTracerFactory(openTelemetrySdk); + + try (IdentityClient client = + TestClientInitializer.createHttpJsonIdentityClientOpentelemetry(tracingFactory)) { + + try { + client.getUser(GetUserRequest.newBuilder().setName("users/test-user").build()); + } catch (Exception e) { + // Ignored, the showcase server may not have this user, but trace is still + // generated. + } + + List spans = spanExporter.getFinishedSpanItems(); + assertThat(spans).isNotEmpty(); + + SpanData attemptSpan = + spans.stream() + .filter(span -> span.getName().equals(SPAN_NAME_GET_USER_HTTP)) + .findFirst() + .orElseThrow(() -> new AssertionError("Incorrect span name")); + assertThat(attemptSpan.getAttributes().get(DESTINATION_RESOURCE_ID_KEY)) + .isEqualTo(VALUE_TEST_USER); + } + } + @Test void testTracing_retry_grpc() throws Exception { final int attempts = 5; @@ -443,7 +516,7 @@ void testTracing_retry_httpjson() throws Exception { assertThat(resendCounts).containsExactlyElementsIn(expectedCounts).inOrder(); } - private void verifyErrorTypeAttribute(String expectedErrorType) { + private SpanData getErrorSpan() { List spans = spanExporter.getFinishedSpanItems(); assertThat(spans).isNotEmpty(); @@ -458,16 +531,11 @@ private void verifyErrorTypeAttribute(String expectedErrorType) { != null) .findFirst() .orElseThrow(() -> new AssertionError("Span with error.type not found")); - - assertThat( - errorSpan - .getAttributes() - .get(AttributeKey.stringKey(ObservabilityAttributes.ERROR_TYPE_ATTRIBUTE))) - .isEqualTo(expectedErrorType); + return errorSpan; } @Test - void testTracing_failedEcho_grpc_recordsErrorType() throws Exception { + void testTracing_failedEcho_grpc_recordsErrorAttributes() throws Exception { SpanTracerFactory tracingFactory = new SpanTracerFactory(openTelemetrySdk); ClientInterceptor interceptor = @@ -509,53 +577,17 @@ public void sendMessage(ReqT message) {} EchoRequest echoRequest = EchoRequest.newBuilder().build(); assertThrows(UnavailableException.class, () -> client.echo(echoRequest)); - verifyErrorTypeAttribute("UNAVAILABLE"); + SpanData errorSpan = getErrorSpan(); + assertThat(errorSpan.getAttributes().get(ERROR_TYPE_KEY)).isEqualTo(VALUE_UNAVAILABLE); + assertThat(errorSpan.getAttributes().get(EXCEPTION_TYPE_KEY)) + .isEqualTo("com.google.api.gax.rpc.UnavailableException"); + assertThat(errorSpan.getAttributes().get(STATUS_MESSAGE_KEY)) + .isEqualTo("io.grpc.StatusRuntimeException: UNAVAILABLE"); } } @Test - void testTracing_statusCodes_grpc() throws Exception { - SpanTracerFactory tracingFactory = new SpanTracerFactory(openTelemetrySdk); - EchoRequest errorRequest = - EchoRequest.newBuilder() - .setError( - Status.newBuilder().setCode(StatusCode.Code.INVALID_ARGUMENT.ordinal()).build()) - .build(); - EchoRequest successRequest = EchoRequest.newBuilder().setContent("tracing-test").build(); - - try (EchoClient grpcClient = - TestClientInitializer.createGrpcEchoClientOpentelemetry(tracingFactory)) { - - grpcClient.echo(successRequest); - assertThrows( - com.google.api.gax.rpc.InvalidArgumentException.class, - () -> grpcClient.echo(errorRequest)); - - List spans = spanExporter.getFinishedSpanItems(); - assertThat(spans).hasSize(2); - - SpanData grpcSuccessSpan = spans.get(0); - assertThat( - grpcSuccessSpan - .getAttributes() - .get( - AttributeKey.stringKey( - ObservabilityAttributes.RPC_RESPONSE_STATUS_ATTRIBUTE))) - .isEqualTo("OK"); - - SpanData grpcErrorSpan = spans.get(1); - assertThat( - grpcErrorSpan - .getAttributes() - .get( - AttributeKey.stringKey( - ObservabilityAttributes.RPC_RESPONSE_STATUS_ATTRIBUTE))) - .isEqualTo("INVALID_ARGUMENT"); - } - } - - @Test - void testTracing_failedEcho_httpjson_recordsErrorType() throws Exception { + void testTracing_failedEcho_httpjson_recordsErrorAttributes() throws Exception { SpanTracerFactory tracingFactory = new SpanTracerFactory(openTelemetrySdk); HttpTransport mockTransport = @@ -645,10 +677,57 @@ public String getHeaderValue(int index) { EchoRequest echoRequest = EchoRequest.newBuilder().build(); assertThrows(UnavailableException.class, () -> client.echo(echoRequest)); - verifyErrorTypeAttribute("503"); + SpanData errorSpan = getErrorSpan(); + assertThat(errorSpan.getAttributes().get(ERROR_TYPE_KEY)).isEqualTo("503"); + assertThat(errorSpan.getAttributes().get(EXCEPTION_TYPE_KEY)) + .isEqualTo("com.google.api.gax.rpc.UnavailableException"); + assertThat(errorSpan.getAttributes().get(STATUS_MESSAGE_KEY)) + .isEqualTo(VALUE_SERVICE_UNAVAILABLE); } } + @Test + void testTracing_statusCodes_grpc() throws Exception { + SpanTracerFactory tracingFactory = new SpanTracerFactory(openTelemetrySdk); + EchoRequest errorRequest = + EchoRequest.newBuilder() + .setError( + Status.newBuilder().setCode(StatusCode.Code.INVALID_ARGUMENT.ordinal()).build()) + .build(); + EchoRequest successRequest = EchoRequest.newBuilder().setContent("tracing-test").build(); + + try (EchoClient grpcClient = + TestClientInitializer.createGrpcEchoClientOpentelemetry(tracingFactory)) { + + grpcClient.echo(successRequest); + assertThrows( + com.google.api.gax.rpc.InvalidArgumentException.class, + () -> grpcClient.echo(errorRequest)); + + List spans = spanExporter.getFinishedSpanItems(); + assertThat(spans).hasSize(2); + + SpanData grpcSuccessSpan = spans.get(0); + assertThat( + grpcSuccessSpan + .getAttributes() + .get( + AttributeKey.stringKey( + ObservabilityAttributes.RPC_RESPONSE_STATUS_ATTRIBUTE))) + .isEqualTo("OK"); + + SpanData grpcErrorSpan = spans.get(1); + assertThat( + grpcErrorSpan + .getAttributes() + .get( + AttributeKey.stringKey( + ObservabilityAttributes.RPC_RESPONSE_STATUS_ATTRIBUTE))) + .isEqualTo("INVALID_ARGUMENT"); + } + } + + @Test void testTracing_statusCodes_httpjson() throws Exception { SpanTracerFactory tracingFactory = new SpanTracerFactory(openTelemetrySdk); EchoRequest errorRequest =