From 29240b12f800546c0629f74b3010dc94bdc7a1b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Fri, 10 Oct 2025 14:52:33 +0200 Subject: [PATCH 1/5] fix: do a quick check if the application runs on GCP The check whether the application runs on GCP did not use a timeout. This introduces a default 500ms timeout for that check. Fixes https://github.com/googleapis/java-spanner-jdbc/issues/2250 --- .../cloud/spanner/BuiltInMetricsProvider.java | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java index 76becf25c9..552c7f15a2 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java @@ -32,6 +32,7 @@ import com.google.cloud.opentelemetry.detection.AttributeKeys; import com.google.cloud.opentelemetry.detection.DetectedPlatform; import com.google.cloud.opentelemetry.detection.GCPPlatformDetector; +import com.google.common.base.Strings; import com.google.common.hash.HashFunction; import com.google.common.hash.Hashing; import io.grpc.ManagedChannelBuilder; @@ -43,11 +44,17 @@ import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; import io.opentelemetry.sdk.resources.Resource; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.lang.management.ManagementFactory; import java.lang.reflect.Method; +import java.net.HttpURLConnection; import java.net.InetAddress; +import java.net.URL; import java.net.UnknownHostException; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -79,7 +86,9 @@ OpenTelemetry getOrCreateOpenTelemetry( SpannerCloudMonitoringExporter.create( projectId, credentials, monitoringHost, universeDomain), sdkMeterProviderBuilder); - sdkMeterProviderBuilder.setResource(Resource.create(createResourceAttributes(projectId))); + String location = quickCheckIsRunningOnGcp() ? null : "global"; + sdkMeterProviderBuilder.setResource( + Resource.create(createResourceAttributes(projectId, location))); SdkMeterProvider sdkMeterProvider = sdkMeterProviderBuilder.build(); this.openTelemetry = OpenTelemetrySdk.builder().setMeterProvider(sdkMeterProvider).build(); Runtime.getRuntime().addShutdownHook(new Thread(sdkMeterProvider::close)); @@ -95,6 +104,36 @@ OpenTelemetry getOrCreateOpenTelemetry( } } + // TODO: Remove when + // https://github.com/GoogleCloudPlatform/opentelemetry-operations-java/issues/421 + // has been fixed. + static boolean quickCheckIsRunningOnGcp() { + int timeout = 500; + try { + timeout = + Integer.parseInt(System.getProperty("spanner.check_is_running_on_gcp_timeout", "500")); + } catch (NumberFormatException ignore) { + // ignore + } + try { + URL url = new URL("http://metadata.google.internal/computeMetadata/v1/project/project-id"); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setConnectTimeout(timeout); + connection.setRequestProperty("Metadata-Flavor", "Google"); + if (connection.getResponseCode() == 200 + && ("Google").equals(connection.getHeaderField("Metadata-Flavor"))) { + InputStream input = connection.getInputStream(); + try (BufferedReader reader = + new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8))) { + return !Strings.isNullOrEmpty(reader.readLine()); + } + } + } catch (IOException ignore) { + // ignore + } + return false; + } + void enableGrpcMetrics( InstantiatingGrpcChannelProvider.Builder channelProviderBuilder, String projectId, @@ -122,14 +161,14 @@ void enableGrpcMetrics( }); } - Attributes createResourceAttributes(String projectId) { + Attributes createResourceAttributes(String projectId, String location) { AttributesBuilder attributesBuilder = Attributes.builder() .put(PROJECT_ID_KEY.getKey(), projectId) .put(INSTANCE_CONFIG_ID_KEY.getKey(), "unknown") .put(CLIENT_HASH_KEY.getKey(), generateClientHash(getDefaultTaskValue())) .put(INSTANCE_ID_KEY.getKey(), "unknown") - .put(LOCATION_ID_KEY.getKey(), detectClientLocation()); + .put(LOCATION_ID_KEY.getKey(), location == null ? detectClientLocation() : location); return attributesBuilder.build(); } From 7194be6b8a7a80976f7e6f0d74065dc86783eb99 Mon Sep 17 00:00:00 2001 From: Surbhi Garg Date: Mon, 13 Oct 2025 12:32:50 +0530 Subject: [PATCH 2/5] make location static and fetch it only once --- .../cloud/spanner/BuiltInMetricsProvider.java | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java index 552c7f15a2..1b0b2ac7d5 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java @@ -70,6 +70,10 @@ final class BuiltInMetricsProvider { private static String taskId; + private static String location; + + private static final String default_location = "global"; + private OpenTelemetry openTelemetry; private BuiltInMetricsProvider() {} @@ -86,9 +90,7 @@ OpenTelemetry getOrCreateOpenTelemetry( SpannerCloudMonitoringExporter.create( projectId, credentials, monitoringHost, universeDomain), sdkMeterProviderBuilder); - String location = quickCheckIsRunningOnGcp() ? null : "global"; - sdkMeterProviderBuilder.setResource( - Resource.create(createResourceAttributes(projectId, location))); + sdkMeterProviderBuilder.setResource(Resource.create(createResourceAttributes(projectId))); SdkMeterProvider sdkMeterProvider = sdkMeterProviderBuilder.build(); this.openTelemetry = OpenTelemetrySdk.builder().setMeterProvider(sdkMeterProvider).build(); Runtime.getRuntime().addShutdownHook(new Thread(sdkMeterProvider::close)); @@ -161,14 +163,14 @@ void enableGrpcMetrics( }); } - Attributes createResourceAttributes(String projectId, String location) { + Attributes createResourceAttributes(String projectId) { AttributesBuilder attributesBuilder = Attributes.builder() .put(PROJECT_ID_KEY.getKey(), projectId) .put(INSTANCE_CONFIG_ID_KEY.getKey(), "unknown") .put(CLIENT_HASH_KEY.getKey(), generateClientHash(getDefaultTaskValue())) .put(INSTANCE_ID_KEY.getKey(), "unknown") - .put(LOCATION_ID_KEY.getKey(), location == null ? detectClientLocation() : location); + .put(LOCATION_ID_KEY.getKey(), detectClientLocation()); return attributesBuilder.build(); } @@ -210,14 +212,20 @@ static String generateClientHash(String clientUid) { } static String detectClientLocation() { - GCPPlatformDetector detector = GCPPlatformDetector.DEFAULT_INSTANCE; - DetectedPlatform detectedPlatform = detector.detectPlatform(); - // All platform except GKE uses "cloud_region" for region attribute. - String region = detectedPlatform.getAttributes().get("cloud_region"); - if (detectedPlatform.getSupportedPlatform() == GOOGLE_KUBERNETES_ENGINE) { - region = detectedPlatform.getAttributes().get(AttributeKeys.GKE_CLUSTER_LOCATION); + if (location == null) { + location = default_location; + if (quickCheckIsRunningOnGcp()) { + GCPPlatformDetector detector = GCPPlatformDetector.DEFAULT_INSTANCE; + DetectedPlatform detectedPlatform = detector.detectPlatform(); + // All platform except GKE uses "cloud_region" for region attribute. + String region = detectedPlatform.getAttributes().get("cloud_region"); + if (detectedPlatform.getSupportedPlatform() == GOOGLE_KUBERNETES_ENGINE) { + region = detectedPlatform.getAttributes().get(AttributeKeys.GKE_CLUSTER_LOCATION); + } + location = region == null ? location : region; + } } - return region == null ? "global" : region; + return location; } /** From 9729cbaa4234b7a3a21f010f39228e0d4f5b1b0d Mon Sep 17 00:00:00 2001 From: cloud-java-bot Date: Mon, 13 Oct 2025 07:08:44 +0000 Subject: [PATCH 3/5] chore: generate libraries at Mon Oct 13 07:06:03 UTC 2025 --- .github/workflows/update_generation_config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update_generation_config.yaml b/.github/workflows/update_generation_config.yaml index 59e39834dd..a7e14bb483 100644 --- a/.github/workflows/update_generation_config.yaml +++ b/.github/workflows/update_generation_config.yaml @@ -26,7 +26,7 @@ jobs: # the branch into which the pull request is merged base_branch: main steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v4 with: fetch-depth: 0 token: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }} From 09d5bd46a1fc44fb4a19ec9532de381d267ffe91 Mon Sep 17 00:00:00 2001 From: Surbhi Garg Date: Mon, 13 Oct 2025 12:49:55 +0530 Subject: [PATCH 4/5] changing the timeout to 5 sec --- .../java/com/google/cloud/spanner/BuiltInMetricsProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java index 1b0b2ac7d5..a6e1b0515f 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java @@ -110,7 +110,7 @@ OpenTelemetry getOrCreateOpenTelemetry( // https://github.com/GoogleCloudPlatform/opentelemetry-operations-java/issues/421 // has been fixed. static boolean quickCheckIsRunningOnGcp() { - int timeout = 500; + int timeout = 5000; try { timeout = Integer.parseInt(System.getProperty("spanner.check_is_running_on_gcp_timeout", "500")); From cd29121917c773e28fee1c6215cfb3f36c0761f3 Mon Sep 17 00:00:00 2001 From: Surbhi Garg Date: Mon, 13 Oct 2025 14:07:59 +0530 Subject: [PATCH 5/5] review comments --- .../java/com/google/cloud/spanner/BuiltInMetricsProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java index a6e1b0515f..f1c520e10f 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsProvider.java @@ -113,7 +113,7 @@ static boolean quickCheckIsRunningOnGcp() { int timeout = 5000; try { timeout = - Integer.parseInt(System.getProperty("spanner.check_is_running_on_gcp_timeout", "500")); + Integer.parseInt(System.getProperty("spanner.check_is_running_on_gcp_timeout", "5000")); } catch (NumberFormatException ignore) { // ignore }