diff --git a/java-bigtable/google-cloud-bigtable/pom.xml b/java-bigtable/google-cloud-bigtable/pom.xml index aeea17b40db0..17e1db391fa2 100644 --- a/java-bigtable/google-cloud-bigtable/pom.xml +++ b/java-bigtable/google-cloud-bigtable/pom.xml @@ -247,10 +247,6 @@ io.opentelemetry opentelemetry-sdk-common - - com.google.cloud.opentelemetry - detector-resources-support - io.opentelemetry opentelemetry-sdk-testing @@ -264,6 +260,14 @@ com.google.api.grpc proto-google-cloud-monitoring-v3 + + io.opentelemetry.contrib + opentelemetry-gcp-resources + + + io.opentelemetry + opentelemetry-sdk-extension-autoconfigure-spi + diff --git a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/csm/attributes/EnvInfo.java b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/csm/attributes/EnvInfo.java index e45ea2607f5b..f36b37e78221 100644 --- a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/csm/attributes/EnvInfo.java +++ b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/csm/attributes/EnvInfo.java @@ -17,19 +17,15 @@ package com.google.cloud.bigtable.data.v2.internal.csm.attributes; import com.google.auto.value.AutoValue; -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.Function; import com.google.common.base.Splitter; import com.google.common.base.Supplier; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.contrib.gcp.resource.GCPResourceProvider; import java.lang.management.ManagementFactory; import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.UUID; import java.util.concurrent.atomic.AtomicLong; @@ -47,11 +43,6 @@ public abstract class EnvInfo { private static final Logger logger = Logger.getLogger(EnvInfo.class.getName()); - private static final Map SUPPORTED_PLATFORM_MAP = - ImmutableMap.of( - GCPPlatformDetector.SupportedPlatform.GOOGLE_COMPUTE_ENGINE, "gcp_compute_engine", - GCPPlatformDetector.SupportedPlatform.GOOGLE_KUBERNETES_ENGINE, "gcp_kubernetes_engine"); - private static final AtomicLong uidSuffix = new AtomicLong(0); public abstract String getUid(); @@ -110,7 +101,7 @@ private static String computeUid() { public static EnvInfo detect() { return detect( - GCPPlatformDetector.DEFAULT_INSTANCE.detectPlatform(), + new GCPResourceProvider().getAttributes(), System::getenv, () -> { try { @@ -123,11 +114,11 @@ public static EnvInfo detect() { @Nullable static EnvInfo detect( - DetectedPlatform detectedPlatform, + Attributes detectedAttributes, Function envGetter, Supplier hostnameSupplier) { @Nullable - String cloud_platform = SUPPORTED_PLATFORM_MAP.get(detectedPlatform.getSupportedPlatform()); + String cloud_platform = detectedAttributes.get(AttributeKey.stringKey("cloud.platform")); if (cloud_platform == null) { return EnvInfo.builder() .setPlatform("unknown") @@ -138,32 +129,33 @@ static EnvInfo detect( .build(); } - Map attrs = detectedPlatform.getAttributes(); - ImmutableList locationKeys = - ImmutableList.of( - AttributeKeys.GCE_CLOUD_REGION, - AttributeKeys.GCE_AVAILABILITY_ZONE, - AttributeKeys.GKE_LOCATION_TYPE_REGION, - AttributeKeys.GKE_CLUSTER_LOCATION); - - String region = - locationKeys.stream().map(attrs::get).filter(Objects::nonNull).findFirst().orElse("global"); + // All platform except GKE uses "cloud.region" for region attribute. + // GKE could either use "cloud.region" or "cloud.availability_zone" for region attribute. + String region = detectedAttributes.get(AttributeKey.stringKey("cloud.region")); + String gkeZonalClusterLocation = + detectedAttributes.get(AttributeKey.stringKey("cloud.availability_zone")); + if (region == null && gkeZonalClusterLocation != null) { + region = gkeZonalClusterLocation; + } + region = region == null ? "global" : region; // Deal with possibility of a zone. Zones are of the form us-east1-c, but we want a region // which, which is us-east1. region = Splitter.on('-').splitToStream(region).limit(2).collect(Collectors.joining("-")); - String hostname = attrs.get(AttributeKeys.GCE_INSTANCE_NAME); + String hostname = detectedAttributes.get(AttributeKey.stringKey("host.name")); + // TODO: add support for cloud run & gae by looking at SERVERLESS_COMPUTE_NAME & GAE_MODULE_NAME if (hostname == null) { hostname = detectHostname(envGetter, hostnameSupplier); } - String hostId = Optional.ofNullable(attrs.get(AttributeKeys.GCE_INSTANCE_ID)).orElse(""); + String hostId = + Optional.ofNullable(detectedAttributes.get(AttributeKey.stringKey("host.id"))).orElse(""); return builder() .setPlatform(cloud_platform) - .setProject(detectedPlatform.getProjectId()) + .setProject(detectedAttributes.get(AttributeKey.stringKey("cloud.account.id"))) .setRegion(region) .setHostId(hostId) .setHostName(hostname) diff --git a/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/internal/csm/attributes/EnvInfoTest.java b/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/internal/csm/attributes/EnvInfoTest.java index 4c81aeb09396..3b3b874d3392 100644 --- a/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/internal/csm/attributes/EnvInfoTest.java +++ b/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/internal/csm/attributes/EnvInfoTest.java @@ -17,34 +17,24 @@ package com.google.cloud.bigtable.data.v2.internal.csm.attributes; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.when; -import com.google.cloud.opentelemetry.detection.DetectedPlatform; -import com.google.cloud.opentelemetry.detection.GCPPlatformDetector.SupportedPlatform; import com.google.common.base.Function; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableMap; +import io.opentelemetry.api.common.Attributes; import java.util.Map; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -@ExtendWith(MockitoExtension.class) class EnvInfoTest { private static final Supplier NULL_HOST = () -> null; @SuppressWarnings("UnnecessaryLambda") private static final Function NULL_ENV = (ignored) -> null; - @Mock private DetectedPlatform detectedPlatform; - @Test void testUid() { - when(detectedPlatform.getSupportedPlatform()).thenReturn(SupportedPlatform.UNKNOWN_PLATFORM); - - EnvInfo info1 = EnvInfo.detect(detectedPlatform, NULL_ENV, NULL_HOST); - EnvInfo info2 = EnvInfo.detect(detectedPlatform, NULL_ENV, NULL_HOST); + EnvInfo info1 = EnvInfo.detect(Attributes.empty(), NULL_ENV, NULL_HOST); + EnvInfo info2 = EnvInfo.detect(Attributes.empty(), NULL_ENV, NULL_HOST); assertThat(info1.getUid()).isNotEmpty(); assertThat(info2.getUid()).isNotEmpty(); @@ -53,8 +43,7 @@ void testUid() { @Test void testUnknown() { - when(detectedPlatform.getSupportedPlatform()).thenReturn(SupportedPlatform.UNKNOWN_PLATFORM); - EnvInfo envInfo = EnvInfo.detect(detectedPlatform, NULL_ENV, NULL_HOST); + EnvInfo envInfo = EnvInfo.detect(Attributes.empty(), NULL_ENV, NULL_HOST); assertThat(envInfo.getHostName()).isEmpty(); assertThat(envInfo.getHostId()).isEmpty(); assertThat(envInfo.getPlatform()).isEqualTo("unknown"); @@ -63,19 +52,16 @@ void testUnknown() { @Test void testGce() { - when(detectedPlatform.getSupportedPlatform()) - .thenReturn(SupportedPlatform.GOOGLE_COMPUTE_ENGINE); - when(detectedPlatform.getProjectId()).thenReturn("my-project"); - when(detectedPlatform.getAttributes()) - .thenReturn( - ImmutableMap.of( - "machine_type", "n2-standard-8", - "availability_zone", "us-central1-c", - "instance_id", "1234567890", - "instance_name", "my-vm-name", - "cloud_region", "us-central1", - "instance_hostname", "my-vm-name.us-central1-c.c.my-project.google.com.internal")); - EnvInfo envInfo = EnvInfo.detect(detectedPlatform, NULL_ENV, NULL_HOST); + Attributes attributes = + Attributes.builder() + .put("cloud.platform", "gcp_compute_engine") + .put("cloud.account.id", "my-project") + .put("cloud.region", "us-central1") + .put("cloud.availability_zone", "us-central1-c") + .put("host.id", "1234567890") + .put("host.name", "my-vm-name") + .build(); + EnvInfo envInfo = EnvInfo.detect(attributes, NULL_ENV, NULL_HOST); assertThat(envInfo.getPlatform()).isEqualTo("gcp_compute_engine"); assertThat(envInfo.getProject()).isEqualTo("my-project"); assertThat(envInfo.getRegion()).isEqualTo("us-central1"); @@ -84,20 +70,37 @@ void testGce() { } @Test - void testGke() { - when(detectedPlatform.getSupportedPlatform()) - .thenReturn(SupportedPlatform.GOOGLE_KUBERNETES_ENGINE); - when(detectedPlatform.getProjectId()).thenReturn("my-project"); - when(detectedPlatform.getAttributes()) - .thenReturn( - ImmutableMap.of( - "gke_cluster_name", "my-cluster", - "gke_cluster_location", "us-central1", - "gke_cluster_location_type", "country-region", - "instance_id", "1234567890")); + void testGkeRegionalCluster() { + Attributes attributes = + Attributes.builder() + .put("cloud.platform", "gcp_kubernetes_engine") + .put("cloud.account.id", "my-project") + .put("cloud.region", "us-central1") + .put("host.id", "1234567890") + .build(); + Map env = ImmutableMap.of("HOSTNAME", "my-hostname"); + + EnvInfo envInfo = EnvInfo.detect(attributes, env::get, NULL_HOST); + assertThat(envInfo.getPlatform()).isEqualTo("gcp_kubernetes_engine"); + assertThat(envInfo.getProject()).isEqualTo("my-project"); + assertThat(envInfo.getRegion()).isEqualTo("us-central1"); + assertThat(envInfo.getHostId()).isEqualTo("1234567890"); + assertThat(envInfo.getHostName()).isEqualTo("my-hostname"); + } + + @Test + void testGkeZonalCluster() { + // Zonal GKE clusters report their location via cloud.availability_zone instead of cloud.region. + Attributes attributes = + Attributes.builder() + .put("cloud.platform", "gcp_kubernetes_engine") + .put("cloud.account.id", "my-project") + .put("cloud.availability_zone", "us-central1-c") + .put("host.id", "1234567890") + .build(); Map env = ImmutableMap.of("HOSTNAME", "my-hostname"); - EnvInfo envInfo = EnvInfo.detect(detectedPlatform, env::get, NULL_HOST); + EnvInfo envInfo = EnvInfo.detect(attributes, env::get, NULL_HOST); assertThat(envInfo.getPlatform()).isEqualTo("gcp_kubernetes_engine"); assertThat(envInfo.getProject()).isEqualTo("my-project"); assertThat(envInfo.getRegion()).isEqualTo("us-central1"); @@ -106,18 +109,15 @@ void testGke() { } @Test - void testGkeHostanmeFallback() { - when(detectedPlatform.getSupportedPlatform()) - .thenReturn(SupportedPlatform.GOOGLE_KUBERNETES_ENGINE); - when(detectedPlatform.getProjectId()).thenReturn("my-project"); - when(detectedPlatform.getAttributes()) - .thenReturn( - ImmutableMap.of( - "gke_cluster_name", "my-cluster", - "gke_cluster_location", "us-central1", - "gke_cluster_location_type", "country-region", - "instance_id", "1234567890")); - EnvInfo envInfo = EnvInfo.detect(detectedPlatform, NULL_ENV, () -> "my-hostname"); + void testGkeHostnameFallback() { + Attributes attributes = + Attributes.builder() + .put("cloud.platform", "gcp_kubernetes_engine") + .put("cloud.account.id", "my-project") + .put("cloud.region", "us-central1") + .put("host.id", "1234567890") + .build(); + EnvInfo envInfo = EnvInfo.detect(attributes, NULL_ENV, () -> "my-hostname"); assertThat(envInfo.getPlatform()).isEqualTo("gcp_kubernetes_engine"); assertThat(envInfo.getProject()).isEqualTo("my-project"); assertThat(envInfo.getRegion()).isEqualTo("us-central1"); diff --git a/java-bigtable/pom.xml b/java-bigtable/pom.xml index bc0bb829a4ef..21241da704fc 100644 --- a/java-bigtable/pom.xml +++ b/java-bigtable/pom.xml @@ -292,6 +292,7 @@ maven-dependency-plugin true + io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi