From 6d54c9d07475d608f696269cd5f4c14793abe930 Mon Sep 17 00:00:00 2001 From: manu2 Date: Wed, 12 Mar 2025 09:19:16 +0000 Subject: [PATCH 01/16] Enable End to End tracing in Integration Test --- google-cloud-spanner/pom.xml | 22 +++- .../cloud/spanner/GceTestEnvConfig.java | 1 + .../cloud/spanner/IntegrationTestEnv.java | 2 + .../google/cloud/spanner/it/ITQueryTest.java | 120 +++++++++++++++++- 4 files changed, 141 insertions(+), 4 deletions(-) diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index a460cc33735..dc72a7f200e 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -17,8 +17,8 @@ google-cloud-spanner 0.31.1 com.google.cloud.spanner.GceTestEnvConfig - projects/gcloud-devel/instances/spanner-testing-east1 - gcloud-devel + projects/span-cloud-testing/instances/manu-demo1-mr-nam6 + span-cloud-testing projects/gcloud-devel/locations/us-east1/keyRings/cmek-test-key-ring/cryptoKeys/cmek-test-key @@ -455,6 +455,24 @@ opentelemetry-sdk-testing test + + com.google.cloud.opentelemetry + exporter-trace + 0.33.0 + test + + + + + + + + + + + + + diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GceTestEnvConfig.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GceTestEnvConfig.java index efb012ba8e2..589db4c9dc6 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GceTestEnvConfig.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GceTestEnvConfig.java @@ -58,6 +58,7 @@ public class GceTestEnvConfig implements TestEnvConfig { private final SpannerOptions options; public GceTestEnvConfig() { + System.setProperty(GCE_PROJECT_ID,"span-cloud-testing"); String projectId = System.getProperty(GCE_PROJECT_ID, ""); String serverUrl = System.getProperty(GCE_SERVER_URL, ""); String credentialsFile = System.getProperty(GCE_CREDENTIALS_FILE, ""); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java index 4593c04cc18..183b1412af3 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java @@ -110,6 +110,8 @@ protected void before() throws Throwable { SpannerOptions options = config.spannerOptions(); String instanceProperty = System.getProperty(TEST_INSTANCE_PROPERTY, ""); + instanceProperty = "projects/span-cloud-testing/instances/manu-demo1-mr-nam6"; + System.out.println("Instance Property Name " + instanceProperty); InstanceId instanceId; if (!instanceProperty.isEmpty() && !alwaysCreateNewInstance) { instanceId = InstanceId.of(instanceProperty); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java index 18044c452b5..29f4ee642c5 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java @@ -27,9 +27,12 @@ import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; +import com.google.api.gax.core.FixedCredentialsProvider; import com.google.cloud.ByteArray; import com.google.cloud.Date; import com.google.cloud.Timestamp; +import com.google.cloud.opentelemetry.trace.TraceConfiguration; +import com.google.cloud.opentelemetry.trace.TraceExporter; import com.google.cloud.spanner.Database; import com.google.cloud.spanner.DatabaseClient; import com.google.cloud.spanner.Dialect; @@ -40,6 +43,8 @@ import com.google.cloud.spanner.ReadContext.QueryAnalyzeMode; import com.google.cloud.spanner.ResultSet; import com.google.cloud.spanner.SpannerException; +import com.google.cloud.spanner.SpannerOptions; +import com.google.cloud.spanner.SpannerOptionsHelper; import com.google.cloud.spanner.Statement; import com.google.cloud.spanner.Struct; import com.google.cloud.spanner.TimestampBound; @@ -48,14 +53,33 @@ import com.google.cloud.spanner.Value; import com.google.cloud.spanner.connection.ConnectionOptions; import com.google.cloud.spanner.testing.EmulatorSpannerHelper; +import com.google.cloud.trace.v1.TraceServiceClient; +import com.google.cloud.trace.v1.TraceServiceClient.ListTracesPagedResponse; +import com.google.cloud.trace.v1.TraceServiceSettings; import com.google.common.base.Joiner; import com.google.common.collect.Iterables; +import com.google.devtools.cloudtrace.v1.ListTracesRequest; import com.google.spanner.v1.ResultSetStats; +// import io.opentelemetry.api.incubator.trace.ExtendedTracer; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.Scope; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import io.opentelemetry.sdk.trace.samplers.Sampler; +import java.io.IOException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.concurrent.ThreadLocalRandom; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -74,8 +98,18 @@ public class ITQueryTest { private static DatabaseClient googleStandardSQLClient; private static DatabaseClient postgreSQLClient; private String selectValueQuery; + private static OpenTelemetrySdk openTelemetry; + static { + SpannerOptionsHelper.resetActiveTracingFramework(); + SpannerOptions.enableOpenTelemetryMetrics(); + SpannerOptions.enableOpenTelemetryTraces(); + } @BeforeClass + public static void setUp(){ + setUpDatabase(); + setupOpenTelemetry(); + } public static void setUpDatabase() { // Empty database. Database googleStandardSQLDatabase = env.getTestHelper().createTestDatabase(); @@ -86,10 +120,47 @@ public static void setUpDatabase() { postgreSQLClient = env.getTestHelper().getDatabaseClient(postgreSQLDatabase); } } + public static void setupOpenTelemetry() { + GlobalOpenTelemetry.resetForTest(); // reset global context for test + assumeFalse("This test requires credentials", EmulatorSpannerHelper.isUsingEmulator()); + + SpannerOptions options = env.getTestHelper().getOptions(); + TraceConfiguration.Builder traceConfigurationBuilder = TraceConfiguration.builder(); + if (options.getCredentials() != null) { + traceConfigurationBuilder.setCredentials(options.getCredentials()); + } + SpanExporter traceExporter = TraceExporter.createWithConfiguration(traceConfigurationBuilder.setProjectId(options.getProjectId()).build()); + + String serviceName = + "java-spanner-jdbc-integration-tests-" + ThreadLocalRandom.current().nextInt(); + SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() + // Always sample in this test to ensure we know what we get. + .setSampler(Sampler.alwaysOn()) + .setResource(Resource.builder().put("service.name", serviceName).build()) + .addSpanProcessor(BatchSpanProcessor.builder(traceExporter).build()) + .build(); + openTelemetry = + OpenTelemetrySdk.builder() + .setTracerProvider(sdkTracerProvider) + .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) + .buildAndRegisterGlobal(); + SpannerOptions.enableOpenTelemetryTraces(); + options.toBuilder().setOpenTelemetry(openTelemetry).setEnableEndToEndTracing(true).build(); + // // TODO: Remove when the bug in OpenTelemetry that has SdkTracer implement ExtendedTracer, + // // which is only available in the incubator project. + // ExtendedTracer ignore = (ExtendedTracer) openTelemetry.getTracer("foo"); + } @AfterClass public static void teardown() { ConnectionOptions.closeSpanner(); + closeOpenTelemetry(); + } + + public static void closeOpenTelemetry() { + if (openTelemetry != null) { + openTelemetry.close(); + } } @Before @@ -121,10 +192,49 @@ private DatabaseClient getClient(Dialect dialect) { return googleStandardSQLClient; } + private void assertTrace() throws InterruptedException, IOException { + com.google.protobuf.Timestamp timestamp = Timestamp.now().toProto(); + TraceServiceSettings settings = + env.getTestHelper().getOptions().getCredentials() == null + ? TraceServiceSettings.newBuilder().build() + : TraceServiceSettings.newBuilder() + .setCredentialsProvider( + FixedCredentialsProvider.create( + env.getTestHelper().getOptions().getCredentials())) + .build(); + TraceServiceClient client = TraceServiceClient.create(settings); + // It can take a few seconds before the trace is visible. + Thread.sleep(5000L); + boolean foundTrace = false; + for (int attempts = 0; attempts < 2; attempts++) { + ListTracesPagedResponse response = + client.listTraces( + ListTracesRequest.newBuilder() + .setProjectId(env.getTestHelper().getInstanceId().getProject()) + .setFilter("span:arrayOfStruct") + // .setStartTime(timestamp) + .build()); + int size = Iterables.size(response.iterateAll()); + if (size != 0) { + assertEquals(1, size); + foundTrace = true; + break; + } else { + Thread.sleep(5000L); + } + } + assertTrue(foundTrace); + } @Test - public void simple() { + public void simple() throws IOException, InterruptedException { + Tracer tracer = openTelemetry.getTracer(ITQueryTest.class.getName()); + Span span = tracer.spanBuilder("simple").startSpan(); + Scope scope = span.makeCurrent(); Struct row = execute(Statement.of("SELECT 1"), Type.int64()); assertThat(row.getLong(0)).isEqualTo(1); + scope.close(); + span.end(); + assertTrace(); } @Test @@ -143,7 +253,10 @@ public void badQuery() { } @Test - public void arrayOfStruct() { + public void arrayOfStruct() throws IOException, InterruptedException { + Tracer tracer = openTelemetry.getTracer(ITQueryTest.class.getName()); + Span span = tracer.spanBuilder("arrayOfStruct").startSpan(); + Scope scope = span.makeCurrent(); assumeFalse("structs are not supported on POSTGRESQL", dialect.dialect == Dialect.POSTGRESQL); Type structType = Type.struct(StructField.of("C1", Type.string()), StructField.of("C2", Type.int64())); @@ -154,6 +267,8 @@ public void arrayOfStruct() { + "FROM (SELECT 'a' AS C1, 1 AS C2 UNION ALL SELECT 'b' AS C1, 2 AS C2) " + "ORDER BY C1 ASC)"), Type.array(structType)); + scope.close(); + span.end(); assertThat(row.isNull(0)).isFalse(); List value = row.getStructList(0); assertThat(value.size()).isEqualTo(2); @@ -178,6 +293,7 @@ public void arrayOfStruct() { Struct.newBuilder().set("C1").to("b").set("C2").to(2).build())) .build(); assertThat(row).isEqualTo(expectedRow); + assertTrace(); } @Test From a0806eef30c9b07b08c22d5d46d54f0b6a6abe10 Mon Sep 17 00:00:00 2001 From: manu2 Date: Tue, 18 Mar 2025 07:33:22 +0000 Subject: [PATCH 02/16] Integration test for End to End tracing --- .../cloud/spanner/IntegrationTestEnv.java | 58 ++++++- .../spanner/it/ITEndToEndTracingTest.java | 144 ++++++++++++++++++ .../google/cloud/spanner/it/ITQueryTest.java | 120 +-------------- 3 files changed, 197 insertions(+), 125 deletions(-) create mode 100644 google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java index 183b1412af3..034eb0b06d0 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java @@ -22,14 +22,26 @@ import com.google.api.client.util.ExponentialBackOff; import com.google.api.gax.longrunning.OperationFuture; import com.google.cloud.Timestamp; +import com.google.cloud.opentelemetry.trace.TraceConfiguration; +import com.google.cloud.opentelemetry.trace.TraceExporter; import com.google.cloud.spanner.DatabaseInfo.DatabaseField; import com.google.cloud.spanner.testing.EmulatorSpannerHelper; import com.google.cloud.spanner.testing.RemoteSpannerHelper; import com.google.common.collect.Iterators; import com.google.spanner.admin.instance.v1.CreateInstanceMetadata; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import io.opentelemetry.sdk.trace.samplers.Sampler; import java.util.Objects; import java.util.Random; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; @@ -45,7 +57,9 @@ */ public class IntegrationTestEnv extends ExternalResource { - /** Names a property that provides the class name of the {@link TestEnvConfig} to use. */ + /** + * Names a property that provides the class name of the {@link TestEnvConfig} to use. + */ public static final String TEST_ENV_CONFIG_CLASS_NAME = "spanner.testenv.config.class"; public static final String CONFIG_CLASS = System.getProperty(TEST_ENV_CONFIG_CLASS_NAME, null); @@ -107,11 +121,10 @@ protected void before() throws Throwable { assumeFalse(alwaysCreateNewInstance && isCloudDevel()); this.config.setUp(); - - SpannerOptions options = config.spannerOptions(); + // OpenTelemetry with End to End tracing enabled for all integration test env. The grpc stub and connections are created during env set up using SpannerOptions and are reused for executing statements. + SpannerOptions options = spannerOptionsWithEndToEndTracing(); String instanceProperty = System.getProperty(TEST_INSTANCE_PROPERTY, ""); instanceProperty = "projects/span-cloud-testing/instances/manu-demo1-mr-nam6"; - System.out.println("Instance Property Name " + instanceProperty); InstanceId instanceId; if (!instanceProperty.isEmpty() && !alwaysCreateNewInstance) { instanceId = InstanceId.of(instanceProperty); @@ -135,6 +148,37 @@ protected void before() throws Throwable { } } + public SpannerOptions spannerOptionsWithEndToEndTracing() { + GlobalOpenTelemetry.resetForTest(); // reset global context for test + assumeFalse("This test requires credentials", EmulatorSpannerHelper.isUsingEmulator()); + + SpannerOptions options = config.spannerOptions(); + TraceConfiguration.Builder traceConfigurationBuilder = TraceConfiguration.builder(); + if (options.getCredentials() != null) { + traceConfigurationBuilder.setCredentials(options.getCredentials()); + } + SpanExporter traceExporter = TraceExporter.createWithConfiguration( + traceConfigurationBuilder.setProjectId(options.getProjectId()).build()); + + String serviceName = + "java-spanner-jdbc-integration-tests-" + ThreadLocalRandom.current().nextInt(); + SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() + // Always sample in this test to ensure we know what we get. + .setSampler(Sampler.alwaysOn()) + .setResource(Resource.builder().put("service.name", serviceName).build()) + .addSpanProcessor(BatchSpanProcessor.builder(traceExporter).build()) + .build(); + OpenTelemetrySdk openTelemetry = + OpenTelemetrySdk.builder() + .setTracerProvider(sdkTracerProvider) + .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) + .buildAndRegisterGlobal(); + SpannerOptions.enableOpenTelemetryTraces(); + return options.toBuilder().setOpenTelemetry(openTelemetry).setEnableEndToEndTracing(true) + .build(); + } + + RemoteSpannerHelper createTestHelper(SpannerOptions options, InstanceId instanceId) throws Throwable { return RemoteSpannerHelper.create(options, instanceId); @@ -220,9 +264,9 @@ static boolean isRetryableResourceExhaustedException(SpannerException exception) return false; } return exception - .getMessage() - .contains( - "Quota exceeded for quota metric 'Instance create requests' and limit 'Instance create requests per minute'") + .getMessage() + .contains( + "Quota exceeded for quota metric 'Instance create requests' and limit 'Instance create requests per minute'") || exception.getMessage().matches(".*cannot add \\d+ nodes in region.*"); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java new file mode 100644 index 00000000000..9ef4ea71d17 --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java @@ -0,0 +1,144 @@ +package com.google.cloud.spanner.it; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertTrue; + +import com.google.api.gax.core.FixedCredentialsProvider; +import com.google.api.gax.rpc.ApiException; +import com.google.api.gax.rpc.ResourceExhaustedException; +import com.google.api.gax.rpc.StatusCode; +import com.google.cloud.spanner.Database; +import com.google.cloud.spanner.DatabaseClient; +import com.google.cloud.spanner.IntegrationTestEnv; +import com.google.cloud.spanner.ParallelIntegrationTest; +import com.google.cloud.spanner.ResultSet; +import com.google.cloud.spanner.SpannerOptions; +import com.google.cloud.spanner.SpannerOptionsHelper; +import com.google.cloud.spanner.Statement; +import com.google.cloud.spanner.Struct; +import com.google.cloud.spanner.Type; +import com.google.cloud.spanner.Type.StructField; +import com.google.cloud.spanner.connection.ConnectionOptions; +import com.google.cloud.trace.v1.TraceServiceClient; +import com.google.cloud.trace.v1.TraceServiceSettings; +import com.google.devtools.cloudtrace.v1.Trace; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Scope; +import java.io.IOException; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Integration tests for End to End Tracing. + */ +@Category(ParallelIntegrationTest.class) +@RunWith(JUnit4.class) +public class ITEndToEndTracingTest { + + @ClassRule + public static IntegrationTestEnv env = new IntegrationTestEnv(); + private static DatabaseClient googleStandardSQLClient; + private String selectValueQuery; + + static { + SpannerOptionsHelper.resetActiveTracingFramework(); + SpannerOptions.enableOpenTelemetryMetrics(); + SpannerOptions.enableOpenTelemetryTraces(); + } + + @BeforeClass + public static void setUp() { + setUpDatabase(); + } + + public static void setUpDatabase() { + // Empty database. + Database googleStandardSQLDatabase = env.getTestHelper().createTestDatabase(); + googleStandardSQLClient = env.getTestHelper().getDatabaseClient(googleStandardSQLDatabase); + } + + @Before + public void initSelectValueQuery() { + selectValueQuery = "SELECT @p1 + @p1 "; + } + + @AfterClass + public static void teardown() { + ConnectionOptions.closeSpanner(); + } + + private void assertTrace(String spanName, String traceid) + throws IOException, InterruptedException { + TraceServiceSettings settings = + env.getTestHelper().getOptions().getCredentials() == null + ? TraceServiceSettings.newBuilder().build() + : TraceServiceSettings.newBuilder() + .setCredentialsProvider( + FixedCredentialsProvider.create( + env.getTestHelper().getOptions().getCredentials())) + .build(); + try (TraceServiceClient client = TraceServiceClient.create(settings)) { + // It can take a few seconds before the trace is visible. + Thread.sleep(5000L); + boolean foundTrace = false; + for (int attempts = 0; attempts < 2; attempts++) { + try { + Trace clientTrace = client.getTrace(env.getTestHelper().getInstanceId().getProject(), + traceid); + // Assert Spanner Frontend Trace is present + assertTrue(clientTrace.getSpansList().stream().anyMatch( + span -> "CloudSpannerOperation.ExecuteStreamingQuery".equals(span.getName()))); + foundTrace = true; + break; + } catch (ApiException apiException) { + assertThat(apiException.getStatusCode().getCode()).isEqualTo(StatusCode.Code.NOT_FOUND); + Thread.sleep(5000L); + } + } + assertTrue(foundTrace); + } catch (ResourceExhaustedException resourceExhaustedException) { + if (resourceExhaustedException + .getMessage() + .contains("Quota exceeded for quota metric 'Read requests (free)'")) { + // Ignore and allow the test to succeed. + System.out.println("RESOURCE_EXHAUSTED error ignored"); + } else { + throw resourceExhaustedException; + } + } + } + + private Struct executeWithRowResultType(Statement statement, Type expectedRowType) { + ResultSet resultSet = + statement.executeQuery(googleStandardSQLClient.singleUse()); + assertThat(resultSet.next()).isTrue(); + assertThat(resultSet.getType()).isEqualTo(expectedRowType); + Struct row = resultSet.getCurrentRowAsStruct(); + assertThat(resultSet.next()).isFalse(); + return row; + } + + @Test + public void simpleSelect() throws IOException, InterruptedException { + Tracer tracer = GlobalOpenTelemetry.getTracer(ITEndToEndTracingTest.class.getName()); + String spanName = "simpleSelect"; + Span span = tracer.spanBuilder(spanName).startSpan(); + Scope scope = span.makeCurrent(); + Type rowType = Type.struct(StructField.of("", Type.int64())); + Struct row = executeWithRowResultType( + Statement.newBuilder(selectValueQuery).bind("p1").to(1234).build(), rowType); + assertThat(row.isNull(0)).isFalse(); + assertThat(row.getLong(0)).isEqualTo(2468); + scope.close(); + span.end(); + assertTrace(spanName, span.getSpanContext().getTraceId()); + } +} diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java index 29f4ee642c5..18044c452b5 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java @@ -27,12 +27,9 @@ import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; -import com.google.api.gax.core.FixedCredentialsProvider; import com.google.cloud.ByteArray; import com.google.cloud.Date; import com.google.cloud.Timestamp; -import com.google.cloud.opentelemetry.trace.TraceConfiguration; -import com.google.cloud.opentelemetry.trace.TraceExporter; import com.google.cloud.spanner.Database; import com.google.cloud.spanner.DatabaseClient; import com.google.cloud.spanner.Dialect; @@ -43,8 +40,6 @@ import com.google.cloud.spanner.ReadContext.QueryAnalyzeMode; import com.google.cloud.spanner.ResultSet; import com.google.cloud.spanner.SpannerException; -import com.google.cloud.spanner.SpannerOptions; -import com.google.cloud.spanner.SpannerOptionsHelper; import com.google.cloud.spanner.Statement; import com.google.cloud.spanner.Struct; import com.google.cloud.spanner.TimestampBound; @@ -53,33 +48,14 @@ import com.google.cloud.spanner.Value; import com.google.cloud.spanner.connection.ConnectionOptions; import com.google.cloud.spanner.testing.EmulatorSpannerHelper; -import com.google.cloud.trace.v1.TraceServiceClient; -import com.google.cloud.trace.v1.TraceServiceClient.ListTracesPagedResponse; -import com.google.cloud.trace.v1.TraceServiceSettings; import com.google.common.base.Joiner; import com.google.common.collect.Iterables; -import com.google.devtools.cloudtrace.v1.ListTracesRequest; import com.google.spanner.v1.ResultSetStats; -// import io.opentelemetry.api.incubator.trace.ExtendedTracer; -import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.Tracer; -import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; -import io.opentelemetry.context.Scope; -import io.opentelemetry.context.propagation.ContextPropagators; -import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.resources.Resource; -import io.opentelemetry.sdk.trace.SdkTracerProvider; -import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; -import io.opentelemetry.sdk.trace.export.SpanExporter; -import io.opentelemetry.sdk.trace.samplers.Sampler; -import java.io.IOException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.concurrent.ThreadLocalRandom; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -98,18 +74,8 @@ public class ITQueryTest { private static DatabaseClient googleStandardSQLClient; private static DatabaseClient postgreSQLClient; private String selectValueQuery; - private static OpenTelemetrySdk openTelemetry; - static { - SpannerOptionsHelper.resetActiveTracingFramework(); - SpannerOptions.enableOpenTelemetryMetrics(); - SpannerOptions.enableOpenTelemetryTraces(); - } @BeforeClass - public static void setUp(){ - setUpDatabase(); - setupOpenTelemetry(); - } public static void setUpDatabase() { // Empty database. Database googleStandardSQLDatabase = env.getTestHelper().createTestDatabase(); @@ -120,47 +86,10 @@ public static void setUpDatabase() { postgreSQLClient = env.getTestHelper().getDatabaseClient(postgreSQLDatabase); } } - public static void setupOpenTelemetry() { - GlobalOpenTelemetry.resetForTest(); // reset global context for test - assumeFalse("This test requires credentials", EmulatorSpannerHelper.isUsingEmulator()); - - SpannerOptions options = env.getTestHelper().getOptions(); - TraceConfiguration.Builder traceConfigurationBuilder = TraceConfiguration.builder(); - if (options.getCredentials() != null) { - traceConfigurationBuilder.setCredentials(options.getCredentials()); - } - SpanExporter traceExporter = TraceExporter.createWithConfiguration(traceConfigurationBuilder.setProjectId(options.getProjectId()).build()); - - String serviceName = - "java-spanner-jdbc-integration-tests-" + ThreadLocalRandom.current().nextInt(); - SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() - // Always sample in this test to ensure we know what we get. - .setSampler(Sampler.alwaysOn()) - .setResource(Resource.builder().put("service.name", serviceName).build()) - .addSpanProcessor(BatchSpanProcessor.builder(traceExporter).build()) - .build(); - openTelemetry = - OpenTelemetrySdk.builder() - .setTracerProvider(sdkTracerProvider) - .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) - .buildAndRegisterGlobal(); - SpannerOptions.enableOpenTelemetryTraces(); - options.toBuilder().setOpenTelemetry(openTelemetry).setEnableEndToEndTracing(true).build(); - // // TODO: Remove when the bug in OpenTelemetry that has SdkTracer implement ExtendedTracer, - // // which is only available in the incubator project. - // ExtendedTracer ignore = (ExtendedTracer) openTelemetry.getTracer("foo"); - } @AfterClass public static void teardown() { ConnectionOptions.closeSpanner(); - closeOpenTelemetry(); - } - - public static void closeOpenTelemetry() { - if (openTelemetry != null) { - openTelemetry.close(); - } } @Before @@ -192,49 +121,10 @@ private DatabaseClient getClient(Dialect dialect) { return googleStandardSQLClient; } - private void assertTrace() throws InterruptedException, IOException { - com.google.protobuf.Timestamp timestamp = Timestamp.now().toProto(); - TraceServiceSettings settings = - env.getTestHelper().getOptions().getCredentials() == null - ? TraceServiceSettings.newBuilder().build() - : TraceServiceSettings.newBuilder() - .setCredentialsProvider( - FixedCredentialsProvider.create( - env.getTestHelper().getOptions().getCredentials())) - .build(); - TraceServiceClient client = TraceServiceClient.create(settings); - // It can take a few seconds before the trace is visible. - Thread.sleep(5000L); - boolean foundTrace = false; - for (int attempts = 0; attempts < 2; attempts++) { - ListTracesPagedResponse response = - client.listTraces( - ListTracesRequest.newBuilder() - .setProjectId(env.getTestHelper().getInstanceId().getProject()) - .setFilter("span:arrayOfStruct") - // .setStartTime(timestamp) - .build()); - int size = Iterables.size(response.iterateAll()); - if (size != 0) { - assertEquals(1, size); - foundTrace = true; - break; - } else { - Thread.sleep(5000L); - } - } - assertTrue(foundTrace); - } @Test - public void simple() throws IOException, InterruptedException { - Tracer tracer = openTelemetry.getTracer(ITQueryTest.class.getName()); - Span span = tracer.spanBuilder("simple").startSpan(); - Scope scope = span.makeCurrent(); + public void simple() { Struct row = execute(Statement.of("SELECT 1"), Type.int64()); assertThat(row.getLong(0)).isEqualTo(1); - scope.close(); - span.end(); - assertTrace(); } @Test @@ -253,10 +143,7 @@ public void badQuery() { } @Test - public void arrayOfStruct() throws IOException, InterruptedException { - Tracer tracer = openTelemetry.getTracer(ITQueryTest.class.getName()); - Span span = tracer.spanBuilder("arrayOfStruct").startSpan(); - Scope scope = span.makeCurrent(); + public void arrayOfStruct() { assumeFalse("structs are not supported on POSTGRESQL", dialect.dialect == Dialect.POSTGRESQL); Type structType = Type.struct(StructField.of("C1", Type.string()), StructField.of("C2", Type.int64())); @@ -267,8 +154,6 @@ public void arrayOfStruct() throws IOException, InterruptedException { + "FROM (SELECT 'a' AS C1, 1 AS C2 UNION ALL SELECT 'b' AS C1, 2 AS C2) " + "ORDER BY C1 ASC)"), Type.array(structType)); - scope.close(); - span.end(); assertThat(row.isNull(0)).isFalse(); List value = row.getStructList(0); assertThat(value.size()).isEqualTo(2); @@ -293,7 +178,6 @@ public void arrayOfStruct() throws IOException, InterruptedException { Struct.newBuilder().set("C1").to("b").set("C2").to(2).build())) .build(); assertThat(row).isEqualTo(expectedRow); - assertTrace(); } @Test From 00a173510323d0e9a9db5a7e7317ab0697829127 Mon Sep 17 00:00:00 2001 From: manu2 Date: Tue, 18 Mar 2025 08:41:43 +0000 Subject: [PATCH 03/16] Integration test for End to End tracing --- google-cloud-spanner/pom.xml | 16 ++-------------- .../google/cloud/spanner/IntegrationTestEnv.java | 5 +++-- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index dc72a7f200e..746c48defc6 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -17,8 +17,8 @@ google-cloud-spanner 0.31.1 com.google.cloud.spanner.GceTestEnvConfig - projects/span-cloud-testing/instances/manu-demo1-mr-nam6 - span-cloud-testing + projects/gcloud-devel/instances/spanner-testing-east1 + gcloud-devel projects/gcloud-devel/locations/us-east1/keyRings/cmek-test-key-ring/cryptoKeys/cmek-test-key @@ -461,18 +461,6 @@ 0.33.0 test - - - - - - - - - - - - diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java index 034eb0b06d0..1e87493e122 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java @@ -121,10 +121,11 @@ protected void before() throws Throwable { assumeFalse(alwaysCreateNewInstance && isCloudDevel()); this.config.setUp(); - // OpenTelemetry with End to End tracing enabled for all integration test env. The grpc stub and connections are created during env set up using SpannerOptions and are reused for executing statements. + // OpenTelemetry set up for enabling End to End tracing for all integration test env. + // The grpc stub and connections are created during test env set up using SpannerOptions and are + // reused for executing statements. SpannerOptions options = spannerOptionsWithEndToEndTracing(); String instanceProperty = System.getProperty(TEST_INSTANCE_PROPERTY, ""); - instanceProperty = "projects/span-cloud-testing/instances/manu-demo1-mr-nam6"; InstanceId instanceId; if (!instanceProperty.isEmpty() && !alwaysCreateNewInstance) { instanceId = InstanceId.of(instanceProperty); From 680ce7fa13a2a1414c30820797c1160cecd56e7d Mon Sep 17 00:00:00 2001 From: manu2 Date: Tue, 18 Mar 2025 08:44:21 +0000 Subject: [PATCH 04/16] Integration test for End to End tracing --- .../src/test/java/com/google/cloud/spanner/GceTestEnvConfig.java | 1 - 1 file changed, 1 deletion(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GceTestEnvConfig.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GceTestEnvConfig.java index 589db4c9dc6..efb012ba8e2 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GceTestEnvConfig.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GceTestEnvConfig.java @@ -58,7 +58,6 @@ public class GceTestEnvConfig implements TestEnvConfig { private final SpannerOptions options; public GceTestEnvConfig() { - System.setProperty(GCE_PROJECT_ID,"span-cloud-testing"); String projectId = System.getProperty(GCE_PROJECT_ID, ""); String serverUrl = System.getProperty(GCE_SERVER_URL, ""); String credentialsFile = System.getProperty(GCE_CREDENTIALS_FILE, ""); From 11baac33c70add7a714d2cf040afe16c32403c81 Mon Sep 17 00:00:00 2001 From: manu2 Date: Tue, 18 Mar 2025 09:03:06 +0000 Subject: [PATCH 05/16] Integration test for End to End tracing --- .../cloud/spanner/IntegrationTestEnv.java | 2 +- .../spanner/it/ITEndToEndTracingTest.java | 50 ++++++++++++------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java index 1e87493e122..082d67357e0 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java @@ -122,7 +122,7 @@ protected void before() throws Throwable { this.config.setUp(); // OpenTelemetry set up for enabling End to End tracing for all integration test env. - // The grpc stub and connections are created during test env set up using SpannerOptions and are + // The gRPC stub and connections are created during test env set up using SpannerOptions and are // reused for executing statements. SpannerOptions options = spannerOptionsWithEndToEndTracing(); String instanceProperty = System.getProperty(TEST_INSTANCE_PROPERTY, ""); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java index 9ef4ea71d17..9a915b31eb6 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.google.cloud.spanner.it; import static com.google.common.truth.Truth.assertThat; @@ -46,7 +62,6 @@ public class ITEndToEndTracingTest { @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); private static DatabaseClient googleStandardSQLClient; - private String selectValueQuery; static { SpannerOptionsHelper.resetActiveTracingFramework(); @@ -54,6 +69,8 @@ public class ITEndToEndTracingTest { SpannerOptions.enableOpenTelemetryTraces(); } + private String selectValueQuery; + @BeforeClass public static void setUp() { setUpDatabase(); @@ -65,26 +82,23 @@ public static void setUpDatabase() { googleStandardSQLClient = env.getTestHelper().getDatabaseClient(googleStandardSQLDatabase); } - @Before - public void initSelectValueQuery() { - selectValueQuery = "SELECT @p1 + @p1 "; - } - @AfterClass public static void teardown() { ConnectionOptions.closeSpanner(); } + @Before + public void initSelectValueQuery() { + selectValueQuery = "SELECT @p1 + @p1 "; + } + private void assertTrace(String spanName, String traceid) throws IOException, InterruptedException { - TraceServiceSettings settings = - env.getTestHelper().getOptions().getCredentials() == null - ? TraceServiceSettings.newBuilder().build() - : TraceServiceSettings.newBuilder() - .setCredentialsProvider( - FixedCredentialsProvider.create( - env.getTestHelper().getOptions().getCredentials())) - .build(); + TraceServiceSettings settings = env.getTestHelper().getOptions().getCredentials() == null + ? TraceServiceSettings.newBuilder().build() : TraceServiceSettings.newBuilder() + .setCredentialsProvider( + FixedCredentialsProvider.create(env.getTestHelper().getOptions().getCredentials())) + .build(); try (TraceServiceClient client = TraceServiceClient.create(settings)) { // It can take a few seconds before the trace is visible. Thread.sleep(5000L); @@ -105,8 +119,7 @@ private void assertTrace(String spanName, String traceid) } assertTrue(foundTrace); } catch (ResourceExhaustedException resourceExhaustedException) { - if (resourceExhaustedException - .getMessage() + if (resourceExhaustedException.getMessage() .contains("Quota exceeded for quota metric 'Read requests (free)'")) { // Ignore and allow the test to succeed. System.out.println("RESOURCE_EXHAUSTED error ignored"); @@ -117,8 +130,7 @@ private void assertTrace(String spanName, String traceid) } private Struct executeWithRowResultType(Statement statement, Type expectedRowType) { - ResultSet resultSet = - statement.executeQuery(googleStandardSQLClient.singleUse()); + ResultSet resultSet = statement.executeQuery(googleStandardSQLClient.singleUse()); assertThat(resultSet.next()).isTrue(); assertThat(resultSet.getType()).isEqualTo(expectedRowType); Struct row = resultSet.getCurrentRowAsStruct(); @@ -141,4 +153,4 @@ public void simpleSelect() throws IOException, InterruptedException { span.end(); assertTrace(spanName, span.getSpanContext().getTraceId()); } -} +} \ No newline at end of file From 8f12e88a4f01c5423c8a78529f8461d77bf79340 Mon Sep 17 00:00:00 2001 From: manu2 Date: Tue, 18 Mar 2025 09:55:04 +0000 Subject: [PATCH 06/16] Fix errors in Integration test for End to End tracing --- google-cloud-spanner/pom.xml | 12 +++++ .../cloud/spanner/IntegrationTestEnv.java | 34 ++++++------- .../spanner/it/ITEndToEndTracingTest.java | 48 ++++++++++--------- 3 files changed, 56 insertions(+), 38 deletions(-) diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index 2c169542df1..f15d137fdef 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -461,6 +461,18 @@ 0.33.0 test + + com.google.cloud + google-cloud-trace + 2.51.0 + test + + + com.google.cloud + google-cloud-trace + 2.51.0 + test + diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java index 082d67357e0..11fb36fd635 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java @@ -57,9 +57,7 @@ */ public class IntegrationTestEnv extends ExternalResource { - /** - * Names a property that provides the class name of the {@link TestEnvConfig} to use. - */ + /** Names a property that provides the class name of the {@link TestEnvConfig} to use. */ public static final String TEST_ENV_CONFIG_CLASS_NAME = "spanner.testenv.config.class"; public static final String CONFIG_CLASS = System.getProperty(TEST_ENV_CONFIG_CLASS_NAME, null); @@ -158,28 +156,32 @@ public SpannerOptions spannerOptionsWithEndToEndTracing() { if (options.getCredentials() != null) { traceConfigurationBuilder.setCredentials(options.getCredentials()); } - SpanExporter traceExporter = TraceExporter.createWithConfiguration( - traceConfigurationBuilder.setProjectId(options.getProjectId()).build()); + SpanExporter traceExporter = + TraceExporter.createWithConfiguration( + traceConfigurationBuilder.setProjectId(options.getProjectId()).build()); String serviceName = "java-spanner-jdbc-integration-tests-" + ThreadLocalRandom.current().nextInt(); - SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() - // Always sample in this test to ensure we know what we get. - .setSampler(Sampler.alwaysOn()) - .setResource(Resource.builder().put("service.name", serviceName).build()) - .addSpanProcessor(BatchSpanProcessor.builder(traceExporter).build()) - .build(); + SdkTracerProvider sdkTracerProvider = + SdkTracerProvider.builder() + // Always sample in this test to ensure we know what we get. + .setSampler(Sampler.alwaysOn()) + .setResource(Resource.builder().put("service.name", serviceName).build()) + .addSpanProcessor(BatchSpanProcessor.builder(traceExporter).build()) + .build(); OpenTelemetrySdk openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) .buildAndRegisterGlobal(); SpannerOptions.enableOpenTelemetryTraces(); - return options.toBuilder().setOpenTelemetry(openTelemetry).setEnableEndToEndTracing(true) + return options + .toBuilder() + .setOpenTelemetry(openTelemetry) + .setEnableEndToEndTracing(true) .build(); } - RemoteSpannerHelper createTestHelper(SpannerOptions options, InstanceId instanceId) throws Throwable { return RemoteSpannerHelper.create(options, instanceId); @@ -265,9 +267,9 @@ static boolean isRetryableResourceExhaustedException(SpannerException exception) return false; } return exception - .getMessage() - .contains( - "Quota exceeded for quota metric 'Instance create requests' and limit 'Instance create requests per minute'") + .getMessage() + .contains( + "Quota exceeded for quota metric 'Instance create requests' and limit 'Instance create requests per minute'") || exception.getMessage().matches(".*cannot add \\d+ nodes in region.*"); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java index 9a915b31eb6..2415e88d161 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java @@ -52,15 +52,12 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -/** - * Integration tests for End to End Tracing. - */ +/** Integration tests for End to End Tracing. */ @Category(ParallelIntegrationTest.class) @RunWith(JUnit4.class) public class ITEndToEndTracingTest { - @ClassRule - public static IntegrationTestEnv env = new IntegrationTestEnv(); + @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); private static DatabaseClient googleStandardSQLClient; static { @@ -92,24 +89,30 @@ public void initSelectValueQuery() { selectValueQuery = "SELECT @p1 + @p1 "; } - private void assertTrace(String spanName, String traceid) + private void assertTrace(String traceId) throws IOException, InterruptedException { - TraceServiceSettings settings = env.getTestHelper().getOptions().getCredentials() == null - ? TraceServiceSettings.newBuilder().build() : TraceServiceSettings.newBuilder() - .setCredentialsProvider( - FixedCredentialsProvider.create(env.getTestHelper().getOptions().getCredentials())) - .build(); + TraceServiceSettings settings = + env.getTestHelper().getOptions().getCredentials() == null + ? TraceServiceSettings.newBuilder().build() + : TraceServiceSettings.newBuilder() + .setCredentialsProvider( + FixedCredentialsProvider.create( + env.getTestHelper().getOptions().getCredentials())) + .build(); try (TraceServiceClient client = TraceServiceClient.create(settings)) { // It can take a few seconds before the trace is visible. Thread.sleep(5000L); boolean foundTrace = false; for (int attempts = 0; attempts < 2; attempts++) { try { - Trace clientTrace = client.getTrace(env.getTestHelper().getInstanceId().getProject(), - traceid); + Trace clientTrace = + client.getTrace(env.getTestHelper().getInstanceId().getProject(), traceId); // Assert Spanner Frontend Trace is present - assertTrue(clientTrace.getSpansList().stream().anyMatch( - span -> "CloudSpannerOperation.ExecuteStreamingQuery".equals(span.getName()))); + assertTrue( + clientTrace.getSpansList().stream() + .anyMatch( + span -> + "CloudSpannerOperation.ExecuteStreamingQuery".equals(span.getName()))); foundTrace = true; break; } catch (ApiException apiException) { @@ -119,7 +122,8 @@ private void assertTrace(String spanName, String traceid) } assertTrue(foundTrace); } catch (ResourceExhaustedException resourceExhaustedException) { - if (resourceExhaustedException.getMessage() + if (resourceExhaustedException + .getMessage() .contains("Quota exceeded for quota metric 'Read requests (free)'")) { // Ignore and allow the test to succeed. System.out.println("RESOURCE_EXHAUSTED error ignored"); @@ -141,16 +145,16 @@ private Struct executeWithRowResultType(Statement statement, Type expectedRowTyp @Test public void simpleSelect() throws IOException, InterruptedException { Tracer tracer = GlobalOpenTelemetry.getTracer(ITEndToEndTracingTest.class.getName()); - String spanName = "simpleSelect"; - Span span = tracer.spanBuilder(spanName).startSpan(); + Span span = tracer.spanBuilder("simpleSelect").startSpan(); Scope scope = span.makeCurrent(); Type rowType = Type.struct(StructField.of("", Type.int64())); - Struct row = executeWithRowResultType( - Statement.newBuilder(selectValueQuery).bind("p1").to(1234).build(), rowType); + Struct row = + executeWithRowResultType( + Statement.newBuilder(selectValueQuery).bind("p1").to(1234).build(), rowType); assertThat(row.isNull(0)).isFalse(); assertThat(row.getLong(0)).isEqualTo(2468); scope.close(); span.end(); - assertTrace(spanName, span.getSpanContext().getTraceId()); + assertTrace(span.getSpanContext().getTraceId()); } -} \ No newline at end of file +} From 8bc559d218e710dcf441fa2f635f30b5bd485cb0 Mon Sep 17 00:00:00 2001 From: manu2 Date: Tue, 18 Mar 2025 10:06:55 +0000 Subject: [PATCH 07/16] Fix errors in Integration test for End to End tracing --- google-cloud-spanner/pom.xml | 4 ++-- .../com/google/cloud/spanner/it/ITEndToEndTracingTest.java | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index f15d137fdef..cc3d9e20a4a 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -468,8 +468,8 @@ test - com.google.cloud - google-cloud-trace + com.google.api.grpc + proto-google-cloud-trace-v1 2.51.0 test diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java index 2415e88d161..2a5b95191c7 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java @@ -89,8 +89,7 @@ public void initSelectValueQuery() { selectValueQuery = "SELECT @p1 + @p1 "; } - private void assertTrace(String traceId) - throws IOException, InterruptedException { + private void assertTrace(String traceId) throws IOException, InterruptedException { TraceServiceSettings settings = env.getTestHelper().getOptions().getCredentials() == null ? TraceServiceSettings.newBuilder().build() From 9f81dbb6938714a497a2cbac70863eeb79aa73ee Mon Sep 17 00:00:00 2001 From: manu2 Date: Tue, 18 Mar 2025 19:11:07 +0000 Subject: [PATCH 08/16] Add TestEnvOptions to enable End to End tracing for the new Integration Test only. --- .../cloud/spanner/IntegrationTestEnv.java | 30 +++++++++++++++---- .../spanner/it/ITEndToEndTracingTest.java | 8 +++-- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java index 11fb36fd635..f0bbb6330cd 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java @@ -38,6 +38,8 @@ import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; import io.opentelemetry.sdk.trace.export.SpanExporter; import io.opentelemetry.sdk.trace.samplers.Sampler; +import java.util.Collection; +import java.util.Collections; import java.util.Objects; import java.util.Random; import java.util.concurrent.ExecutionException; @@ -79,10 +81,22 @@ public class IntegrationTestEnv extends ExternalResource { private final boolean alwaysCreateNewInstance; private RemoteSpannerHelper testHelper; + private Collection testEnvOptions = Collections.emptyList(); + + public enum TestEnvOptions { + USE_END_TO_END_TRACING; + // TODO : Move alwaysCreateNewInstance to TestEnvOptions + } + public IntegrationTestEnv() { this(false); } + public IntegrationTestEnv(Collection testEnvOptions) { + this(false); + this.testEnvOptions = testEnvOptions; + } + public IntegrationTestEnv(final boolean alwaysCreateNewInstance) { this.alwaysCreateNewInstance = alwaysCreateNewInstance; } @@ -119,10 +133,15 @@ protected void before() throws Throwable { assumeFalse(alwaysCreateNewInstance && isCloudDevel()); this.config.setUp(); - // OpenTelemetry set up for enabling End to End tracing for all integration test env. - // The gRPC stub and connections are created during test env set up using SpannerOptions and are - // reused for executing statements. - SpannerOptions options = spannerOptionsWithEndToEndTracing(); + SpannerOptions options = config.spannerOptions(); + if (testEnvOptions.stream() + .anyMatch(testEnvOption -> TestEnvOptions.USE_END_TO_END_TRACING.equals(testEnvOption))) { + // OpenTelemetry set up for enabling End to End tracing for all integration test env. + // The gRPC stub and connections are created during test env set up using SpannerOptions and + // are + // reused for executing statements. + options = spannerOptionsWithEndToEndTracing(options); + } String instanceProperty = System.getProperty(TEST_INSTANCE_PROPERTY, ""); InstanceId instanceId; if (!instanceProperty.isEmpty() && !alwaysCreateNewInstance) { @@ -147,11 +166,10 @@ protected void before() throws Throwable { } } - public SpannerOptions spannerOptionsWithEndToEndTracing() { + public SpannerOptions spannerOptionsWithEndToEndTracing(SpannerOptions options) { GlobalOpenTelemetry.resetForTest(); // reset global context for test assumeFalse("This test requires credentials", EmulatorSpannerHelper.isUsingEmulator()); - SpannerOptions options = config.spannerOptions(); TraceConfiguration.Builder traceConfigurationBuilder = TraceConfiguration.builder(); if (options.getCredentials() != null) { traceConfigurationBuilder.setCredentials(options.getCredentials()); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java index 2a5b95191c7..f56f1c8a97b 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java @@ -26,6 +26,7 @@ import com.google.cloud.spanner.Database; import com.google.cloud.spanner.DatabaseClient; import com.google.cloud.spanner.IntegrationTestEnv; +import com.google.cloud.spanner.IntegrationTestEnv.TestEnvOptions; import com.google.cloud.spanner.ParallelIntegrationTest; import com.google.cloud.spanner.ResultSet; import com.google.cloud.spanner.SpannerOptions; @@ -43,6 +44,8 @@ import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Scope; import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -56,8 +59,9 @@ @Category(ParallelIntegrationTest.class) @RunWith(JUnit4.class) public class ITEndToEndTracingTest { - - @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); + public static Collection testEnvOptions = + Arrays.asList(TestEnvOptions.USE_END_TO_END_TRACING); + @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(testEnvOptions); private static DatabaseClient googleStandardSQLClient; static { From 19eee1c83463fbf964b5f107df7b61d177a904ec Mon Sep 17 00:00:00 2001 From: manu2 Date: Tue, 18 Mar 2025 19:57:29 +0000 Subject: [PATCH 09/16] Fix ITEndToEndTracingTest error on direct path build --- .../java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java index f56f1c8a97b..0790f56cc32 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java @@ -22,7 +22,6 @@ import com.google.api.gax.core.FixedCredentialsProvider; import com.google.api.gax.rpc.ApiException; import com.google.api.gax.rpc.ResourceExhaustedException; -import com.google.api.gax.rpc.StatusCode; import com.google.cloud.spanner.Database; import com.google.cloud.spanner.DatabaseClient; import com.google.cloud.spanner.IntegrationTestEnv; @@ -119,7 +118,6 @@ private void assertTrace(String traceId) throws IOException, InterruptedExceptio foundTrace = true; break; } catch (ApiException apiException) { - assertThat(apiException.getStatusCode().getCode()).isEqualTo(StatusCode.Code.NOT_FOUND); Thread.sleep(5000L); } } From 646a6b952332aa4c0efdcc9470c0a93abec8f494 Mon Sep 17 00:00:00 2001 From: manu2 Date: Wed, 19 Mar 2025 04:50:59 +0000 Subject: [PATCH 10/16] Skip ITEndToEndTracingTest on permission denied error for error in direct path build --- .../com/google/cloud/spanner/it/ITEndToEndTracingTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java index 0790f56cc32..bbad14ade09 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java @@ -18,10 +18,12 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import com.google.api.gax.core.FixedCredentialsProvider; import com.google.api.gax.rpc.ApiException; import com.google.api.gax.rpc.ResourceExhaustedException; +import com.google.api.gax.rpc.StatusCode; import com.google.cloud.spanner.Database; import com.google.cloud.spanner.DatabaseClient; import com.google.cloud.spanner.IntegrationTestEnv; @@ -118,6 +120,9 @@ private void assertTrace(String traceId) throws IOException, InterruptedExceptio foundTrace = true; break; } catch (ApiException apiException) { + assumeTrue( + apiException.getStatusCode() != null + && StatusCode.Code.NOT_FOUND.equals(apiException.getStatusCode().getCode())); Thread.sleep(5000L); } } From d752823afd030be704b9774061b31432ff6aaa21 Mon Sep 17 00:00:00 2001 From: manu2 Date: Fri, 21 Mar 2025 09:53:12 +0000 Subject: [PATCH 11/16] Assert server side span name --- .../com/google/cloud/spanner/it/ITEndToEndTracingTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java index bbad14ade09..9e1d423c072 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java @@ -67,7 +67,6 @@ public class ITEndToEndTracingTest { static { SpannerOptionsHelper.resetActiveTracingFramework(); - SpannerOptions.enableOpenTelemetryMetrics(); SpannerOptions.enableOpenTelemetryTraces(); } @@ -116,7 +115,7 @@ private void assertTrace(String traceId) throws IOException, InterruptedExceptio clientTrace.getSpansList().stream() .anyMatch( span -> - "CloudSpannerOperation.ExecuteStreamingQuery".equals(span.getName()))); + "Spanner.ExecuteStreamingSql".equals(span.getName()))); foundTrace = true; break; } catch (ApiException apiException) { From 74b901dedbacf1bda152d6d3614ebf3d708ec5a5 Mon Sep 17 00:00:00 2001 From: manu2 Date: Tue, 25 Mar 2025 09:23:17 +0000 Subject: [PATCH 12/16] Increase delay before trace fetch. --- .../java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java index 9e1d423c072..fd0fab8f4d2 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java @@ -104,7 +104,7 @@ private void assertTrace(String traceId) throws IOException, InterruptedExceptio .build(); try (TraceServiceClient client = TraceServiceClient.create(settings)) { // It can take a few seconds before the trace is visible. - Thread.sleep(5000L); + Thread.sleep(15000); boolean foundTrace = false; for (int attempts = 0; attempts < 2; attempts++) { try { From 9c1cd081e32e372d64d9cf568dc83fa3bb6d9e45 Mon Sep 17 00:00:00 2001 From: manu2 Date: Tue, 25 Mar 2025 13:30:17 +0000 Subject: [PATCH 13/16] Remove update to GlobalTelemetry. Use opentelemetrysdk created in test. --- .../cloud/spanner/IntegrationTestEnv.java | 7 ++--- .../spanner/it/ITEndToEndTracingTest.java | 26 +++++++------------ 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java index f0bbb6330cd..b7cdcd3d476 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/IntegrationTestEnv.java @@ -29,7 +29,6 @@ import com.google.cloud.spanner.testing.RemoteSpannerHelper; import com.google.common.collect.Iterators; import com.google.spanner.admin.instance.v1.CreateInstanceMetadata; -import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.sdk.OpenTelemetrySdk; @@ -167,7 +166,6 @@ protected void before() throws Throwable { } public SpannerOptions spannerOptionsWithEndToEndTracing(SpannerOptions options) { - GlobalOpenTelemetry.resetForTest(); // reset global context for test assumeFalse("This test requires credentials", EmulatorSpannerHelper.isUsingEmulator()); TraceConfiguration.Builder traceConfigurationBuilder = TraceConfiguration.builder(); @@ -178,8 +176,7 @@ public SpannerOptions spannerOptionsWithEndToEndTracing(SpannerOptions options) TraceExporter.createWithConfiguration( traceConfigurationBuilder.setProjectId(options.getProjectId()).build()); - String serviceName = - "java-spanner-jdbc-integration-tests-" + ThreadLocalRandom.current().nextInt(); + String serviceName = "java-spanner-integration-tests-" + ThreadLocalRandom.current().nextInt(); SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() // Always sample in this test to ensure we know what we get. @@ -191,7 +188,7 @@ public SpannerOptions spannerOptionsWithEndToEndTracing(SpannerOptions options) OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) - .buildAndRegisterGlobal(); + .build(); SpannerOptions.enableOpenTelemetryTraces(); return options .toBuilder() diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java index fd0fab8f4d2..eb238505a62 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java @@ -40,7 +40,6 @@ import com.google.cloud.trace.v1.TraceServiceClient; import com.google.cloud.trace.v1.TraceServiceSettings; import com.google.devtools.cloudtrace.v1.Trace; -import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Scope; @@ -48,7 +47,6 @@ import java.util.Arrays; import java.util.Collection; import org.junit.AfterClass; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; @@ -70,7 +68,7 @@ public class ITEndToEndTracingTest { SpannerOptions.enableOpenTelemetryTraces(); } - private String selectValueQuery; + private static String selectValueQuery = "SELECT @p1 + @p1"; @BeforeClass public static void setUp() { @@ -88,11 +86,6 @@ public static void teardown() { ConnectionOptions.closeSpanner(); } - @Before - public void initSelectValueQuery() { - selectValueQuery = "SELECT @p1 + @p1 "; - } - private void assertTrace(String traceId) throws IOException, InterruptedException { TraceServiceSettings settings = env.getTestHelper().getOptions().getCredentials() == null @@ -104,18 +97,15 @@ private void assertTrace(String traceId) throws IOException, InterruptedExceptio .build(); try (TraceServiceClient client = TraceServiceClient.create(settings)) { // It can take a few seconds before the trace is visible. - Thread.sleep(15000); + Thread.sleep(10000); boolean foundTrace = false; for (int attempts = 0; attempts < 2; attempts++) { try { - Trace clientTrace = - client.getTrace(env.getTestHelper().getInstanceId().getProject(), traceId); + Trace trace = client.getTrace(env.getTestHelper().getInstanceId().getProject(), traceId); // Assert Spanner Frontend Trace is present assertTrue( - clientTrace.getSpansList().stream() - .anyMatch( - span -> - "Spanner.ExecuteStreamingSql".equals(span.getName()))); + trace.getSpansList().stream() + .anyMatch(span -> "Spanner.ExecuteStreamingSql".equals(span.getName()))); foundTrace = true; break; } catch (ApiException apiException) { @@ -149,7 +139,11 @@ private Struct executeWithRowResultType(Statement statement, Type expectedRowTyp @Test public void simpleSelect() throws IOException, InterruptedException { - Tracer tracer = GlobalOpenTelemetry.getTracer(ITEndToEndTracingTest.class.getName()); + Tracer tracer = + env.getTestHelper() + .getOptions() + .getOpenTelemetry() + .getTracer(ITEndToEndTracingTest.class.getName()); Span span = tracer.spanBuilder("simpleSelect").startSpan(); Scope scope = span.makeCurrent(); Type rowType = Type.struct(StructField.of("", Type.int64())); From eb25e677bd9ce7dbb88e50e21324ea0821dcd8ef Mon Sep 17 00:00:00 2001 From: manu2 Date: Thu, 27 Mar 2025 09:21:14 +0000 Subject: [PATCH 14/16] Update retry logic for trace retrieval. (cherry picked from commit f47f01a834c80fadf754ed1ceee5179c1bd00deb) --- .../spanner/it/ITEndToEndTracingTest.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java index eb238505a62..6c63a114022 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITEndToEndTracingTest.java @@ -39,13 +39,14 @@ import com.google.cloud.spanner.connection.ConnectionOptions; import com.google.cloud.trace.v1.TraceServiceClient; import com.google.cloud.trace.v1.TraceServiceSettings; -import com.google.devtools.cloudtrace.v1.Trace; +import com.google.common.base.Stopwatch; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Scope; import java.io.IOException; import java.util.Arrays; import java.util.Collection; +import java.util.concurrent.TimeUnit; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.ClassRule; @@ -96,23 +97,21 @@ private void assertTrace(String traceId) throws IOException, InterruptedExceptio env.getTestHelper().getOptions().getCredentials())) .build(); try (TraceServiceClient client = TraceServiceClient.create(settings)) { - // It can take a few seconds before the trace is visible. - Thread.sleep(10000); boolean foundTrace = false; - for (int attempts = 0; attempts < 2; attempts++) { + Stopwatch metricsPollingStopwatch = Stopwatch.createStarted(); + while (!foundTrace && metricsPollingStopwatch.elapsed(TimeUnit.SECONDS) < 30) { + // Try every 5 seconds + Thread.sleep(5000); try { - Trace trace = client.getTrace(env.getTestHelper().getInstanceId().getProject(), traceId); - // Assert Spanner Frontend Trace is present - assertTrue( - trace.getSpansList().stream() - .anyMatch(span -> "Spanner.ExecuteStreamingSql".equals(span.getName()))); - foundTrace = true; - break; + foundTrace = + client.getTrace(env.getTestHelper().getInstanceId().getProject(), traceId) + .getSpansList().stream() + .anyMatch(span -> "Spanner.ExecuteStreamingSql".equals(span.getName())); } catch (ApiException apiException) { assumeTrue( apiException.getStatusCode() != null && StatusCode.Code.NOT_FOUND.equals(apiException.getStatusCode().getCode())); - Thread.sleep(5000L); + System.out.println("Trace NOT_FOUND error ignored"); } } assertTrue(foundTrace); From 66856a8ac9c7b75205cab852c13c0a9efe330cd5 Mon Sep 17 00:00:00 2001 From: manu2 Date: Fri, 28 Mar 2025 07:44:42 +0000 Subject: [PATCH 15/16] Remove version number from opentelemetry exporter-trace dependency --- google-cloud-spanner/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index 4d217bcc0e8..2dc54d627bc 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -458,7 +458,6 @@ com.google.cloud.opentelemetry exporter-trace - 0.33.0 test From e7f31099dfff231500b517cbe3729e9631944dc2 Mon Sep 17 00:00:00 2001 From: manu2 Date: Fri, 28 Mar 2025 10:12:40 +0000 Subject: [PATCH 16/16] Revert "Remove version number from opentelemetry exporter-trace dependency" This reverts commit 66856a8ac9c7b75205cab852c13c0a9efe330cd5. --- google-cloud-spanner/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index 2dc54d627bc..4d217bcc0e8 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -458,6 +458,7 @@ com.google.cloud.opentelemetry exporter-trace + 0.33.0 test