From eefad12e4c44c384927ff042382ccb5538896de9 Mon Sep 17 00:00:00 2001 From: Pranav Sharma Date: Wed, 3 Jan 2024 22:29:24 +0000 Subject: [PATCH] Refactor platform detection to enhance testing --- .../detectors/AttributeKeys.java | 45 +++++ .../detectors/CloudLocationUtil.java | 15 -- .../detectors/DetectedPlatform.java | 10 + .../detectors/EnvironmentVariables.java | 15 -- .../opentelemetry/detectors/GAEDetector.java | 61 ------ .../opentelemetry/detectors/GCEDetector.java | 57 ------ .../detectors/GCPMetadataConfig.java | 15 -- .../detectors/GCPPlatformDetector.java | 80 ++++---- .../opentelemetry/detectors/GKEDetector.java | 100 ---------- .../detectors/GoogleAppEngine.java | 62 ++++++ .../detectors/GoogleCloudFunction.java | 8 + .../detectors/GoogleCloudRun.java | 23 +++ .../detectors/GoogleComputeEngine.java | 55 ++++++ .../detectors/GoogleKubernetesEngine.java | 79 ++++++++ .../detectors/GoogleServerlessCompute.java | 54 ++++++ .../detectors/ServerlessComputeDetector.java | 60 ------ .../detectors/UnknownPlatform.java | 20 ++ .../detectors/GCPResourceProvider.java | 183 ++++++++++-------- .../detectors/GCPResourceProviderTest.java | 71 +++++++ 19 files changed, 577 insertions(+), 436 deletions(-) create mode 100644 detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/AttributeKeys.java create mode 100644 detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/DetectedPlatform.java delete mode 100644 detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GAEDetector.java delete mode 100644 detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GCEDetector.java delete mode 100644 detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GKEDetector.java create mode 100644 detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleAppEngine.java create mode 100644 detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleCloudFunction.java create mode 100644 detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleCloudRun.java create mode 100644 detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleComputeEngine.java create mode 100644 detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleKubernetesEngine.java create mode 100644 detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleServerlessCompute.java delete mode 100644 detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/ServerlessComputeDetector.java create mode 100644 detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/UnknownPlatform.java diff --git a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/AttributeKeys.java b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/AttributeKeys.java new file mode 100644 index 00000000..ca0fd0b7 --- /dev/null +++ b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/AttributeKeys.java @@ -0,0 +1,45 @@ +package com.google.cloud.opentelemetry.detectors; + +public final class AttributeKeys { + // GCE Attributes + public static final String GCE_PROJECT_ID = AttributeKeys.PROJECT_ID; + public static final String GCE_AVAILABILITY_ZONE = AttributeKeys.AVAILABILITY_ZONE; + public static final String GCE_CLOUD_REGION = AttributeKeys.CLOUD_REGION; + public static final String GCE_INSTANCE_ID = AttributeKeys.INSTANCE_ID; + public static final String GCE_INSTANCE_NAME = AttributeKeys.INSTANCE_NAME; + public static final String GCE_MACHINE_TYPE = AttributeKeys.MACHINE_TYPE; + + // GKE Attributes + public static final String GKE_POD_NAME = "gke_pod_name"; + public static final String GKE_NAMESPACE = "gke_namespace"; + public static final String GKE_CONTAINER_NAME = "gke_container_name"; + public static final String GKE_CLUSTER_NAME = "gke_cluster_name"; + public static final String GKE_CLUSTER_LOCATION_TYPE = "gke_cluster_location_type"; + public static final String GKE_CLUSTER_LOCATION = "gke_cluster_location"; + public static final String GKE_HOST_ID = AttributeKeys.INSTANCE_ID; + + // GKE Location Constants + public static final String GKE_LOCATION_TYPE_ZONE = "ZONE"; + public static final String GKE_LOCATION_TYPE_REGION = "REGION"; + + // GAE Attributes + public static final String GAE_MODULE_NAME = "gae_module_name"; + public static final String GAE_APP_VERSION = "gae_app_version"; + public static final String GAE_INSTANCE_ID = AttributeKeys.INSTANCE_ID; + public static final String GAE_AVAILABILITY_ZONE = AttributeKeys.AVAILABILITY_ZONE; + public static final String GAE_CLOUD_REGION = AttributeKeys.CLOUD_REGION; + + // Google Serverless Compute Attributes + public static final String SERVERLESS_COMPUTE_NAME = "serverless_compute_name"; + public static final String SERVERLESS_COMPUTE_REVISION = "serverless_compute_revision"; + public static final String SERVERLESS_COMPUTE_AVAILABILITY_ZONE = AttributeKeys.AVAILABILITY_ZONE; + public static final String SERVERLESS_COMPUTE_CLOUD_REGION = AttributeKeys.CLOUD_REGION; + public static final String SERVERLESS_COMPUTE_INSTANCE_ID = AttributeKeys.INSTANCE_ID; + + static final String PROJECT_ID = "project_id"; + static final String AVAILABILITY_ZONE = "availability_zone"; + static final String CLOUD_REGION = "cloud_region"; + static final String INSTANCE_ID = "instance_id"; + static final String INSTANCE_NAME = "instance_name"; + static final String MACHINE_TYPE = "machine_type"; +} diff --git a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/CloudLocationUtil.java b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/CloudLocationUtil.java index 6e7e6e74..28d3b058 100644 --- a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/CloudLocationUtil.java +++ b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/CloudLocationUtil.java @@ -1,18 +1,3 @@ -/* - * Copyright 2023 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.opentelemetry.detectors; import java.util.Optional; diff --git a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/DetectedPlatform.java b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/DetectedPlatform.java new file mode 100644 index 00000000..f370caab --- /dev/null +++ b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/DetectedPlatform.java @@ -0,0 +1,10 @@ +package com.google.cloud.opentelemetry.detectors; + +import java.util.Map; +import java.util.Optional; + +public interface DetectedPlatform { + GCPPlatformDetector.SupportedPlatform getSupportedPlatform(); + + Map> getAttributes(); +} diff --git a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/EnvironmentVariables.java b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/EnvironmentVariables.java index 64004ed1..95dce3d4 100644 --- a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/EnvironmentVariables.java +++ b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/EnvironmentVariables.java @@ -1,18 +1,3 @@ -/* - * Copyright 2023 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.opentelemetry.detectors; /** diff --git a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GAEDetector.java b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GAEDetector.java deleted file mode 100644 index 7e468208..00000000 --- a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GAEDetector.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2023 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.opentelemetry.detectors; - -import java.util.Optional; - -public final class GAEDetector { - public static final GAEDetector DEFAULT_INSTANCE = new GAEDetector(); - - private final EnvironmentVariables environmentVariables; - private final GCPMetadataConfig metadataConfig; - - GAEDetector() { - this.environmentVariables = EnvironmentVariables.DEFAULT_INSTANCE; - this.metadataConfig = GCPMetadataConfig.DEFAULT_INSTANCE; - } - - // for testing only - GAEDetector(EnvironmentVariables environmentVariables, GCPMetadataConfig metadataConfig) { - this.environmentVariables = environmentVariables; - this.metadataConfig = metadataConfig; - } - - public Optional getAppModuleName() { - return Optional.ofNullable(this.environmentVariables.get("GAE_SERVICE")); - } - - public Optional getAppVersion() { - return Optional.ofNullable(this.environmentVariables.get("GAE_VERSION")); - } - - public Optional getAppInstanceId() { - return Optional.ofNullable(this.environmentVariables.get("GAE_INSTANCE")); - } - - public Optional getAvailabilityZone() { - return CloudLocationUtil.getAvailabilityZoneFromMetadata(this.metadataConfig); - } - - public Optional getCloudRegion() { - if (this.environmentVariables.get("GAE_ENV") != null - && this.environmentVariables.get("GAE_ENV").equals("standard")) { - return CloudLocationUtil.getCloudRegionFromMetadataUsingRegion(this.metadataConfig); - } else { - return CloudLocationUtil.getCloudRegionFromMetadataUsingZone(this.metadataConfig); - } - } -} diff --git a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GCEDetector.java b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GCEDetector.java deleted file mode 100644 index 6f42ecbe..00000000 --- a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GCEDetector.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2023 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.opentelemetry.detectors; - -import java.util.Optional; - -public final class GCEDetector { - public static final GCEDetector DEFAULT_INSTANCE = new GCEDetector(); - - private final GCPMetadataConfig metadataConfig; - - GCEDetector() { - this.metadataConfig = GCPMetadataConfig.DEFAULT_INSTANCE; - } - - // for testing only - GCEDetector(GCPMetadataConfig metadataConfig) { - this.metadataConfig = metadataConfig; - } - - public Optional getProjectId() { - return Optional.ofNullable(this.metadataConfig.getProjectId()); - } - - public Optional getAvailabilityZone() { - return CloudLocationUtil.getAvailabilityZoneFromMetadata(this.metadataConfig); - } - - public Optional getCloudRegion() { - return CloudLocationUtil.getCloudRegionFromMetadataUsingZone(this.metadataConfig); - } - - public Optional getInstanceId() { - return Optional.ofNullable(this.metadataConfig.getInstanceId()); - } - - public Optional getInstanceName() { - return Optional.ofNullable(this.metadataConfig.getInstanceName()); - } - - public Optional getMachineType() { - return Optional.ofNullable(this.metadataConfig.getMachineType()); - } -} diff --git a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GCPMetadataConfig.java b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GCPMetadataConfig.java index 7d6bd356..608f2d08 100644 --- a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GCPMetadataConfig.java +++ b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GCPMetadataConfig.java @@ -1,18 +1,3 @@ -/* - * Copyright 2023 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.opentelemetry.detectors; import java.io.BufferedReader; diff --git a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GCPPlatformDetector.java b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GCPPlatformDetector.java index 9532f70a..dccadea4 100644 --- a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GCPPlatformDetector.java +++ b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GCPPlatformDetector.java @@ -1,25 +1,10 @@ -/* - * Copyright 2023 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.opentelemetry.detectors; import java.util.Optional; import java.util.function.Function; import java.util.stream.Stream; -public final class GCPPlatformDetector { +public class GCPPlatformDetector { public static final GCPPlatformDetector DEFAULT_INSTANCE = new GCPPlatformDetector(); private final GCPMetadataConfig metadataConfig; @@ -37,49 +22,74 @@ private GCPPlatformDetector() { } // Detects the GCP platform on which the application is running - public GCPPlatform detectPlatform() { + public DetectedPlatform detectPlatform() { if (!isRunningOnGcp()) { - return GCPPlatform.UNKNOWN_PLATFORM; + return generateDetectedPlatform(SupportedPlatform.UNKNOWN_PLATFORM); } - Function> detectGKE = + Function> detectGKE = environmentVariables -> environmentVariables.get("KUBERNETES_SERVICE_HOST") != null - ? Optional.of(GCPPlatform.GOOGLE_KUBERNETES_ENGINE) + ? Optional.of(SupportedPlatform.GOOGLE_KUBERNETES_ENGINE) : Optional.empty(); - Function> detectGCR = + Function> detectGCR = environmentVariables -> environmentVariables.get("K_CONFIGURATION") != null && environmentVariables.get("FUNCTION_TARGET") == null - ? Optional.of(GCPPlatform.GOOGLE_CLOUD_RUN) + ? Optional.of(SupportedPlatform.GOOGLE_CLOUD_RUN) : Optional.empty(); - Function> detectGCF = + Function> detectGCF = environmentVariables -> environmentVariables.get("FUNCTION_TARGET") != null - ? Optional.of(GCPPlatform.GOOGLE_CLOUD_FUNCTIONS) + ? Optional.of(SupportedPlatform.GOOGLE_CLOUD_FUNCTIONS) : Optional.empty(); - Function> detectGAE = + Function> detectGAE = environmentVariables -> environmentVariables.get("GAE_SERVICE") != null - ? Optional.of(GCPPlatform.GOOGLE_APP_ENGINE) + ? Optional.of(SupportedPlatform.GOOGLE_APP_ENGINE) : Optional.empty(); // Order of detection functions matters here - Stream>> platforms = + Stream>> platforms = Stream.of(detectGKE, detectGCR, detectGCF, detectGAE); - return platforms - .map(detectionFn -> detectionFn.apply(environmentVariables)) - .filter(Optional::isPresent) - .map(Optional::get) - .findFirst() - .orElse(GCPPlatform.GOOGLE_COMPUTE_ENGINE); // defaults to GCE + SupportedPlatform platform = + platforms + .map(detectionFn -> detectionFn.apply(environmentVariables)) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst() + .orElse(SupportedPlatform.GOOGLE_COMPUTE_ENGINE); // defaults to GCE + return generateDetectedPlatform(platform); } private boolean isRunningOnGcp() { return metadataConfig.getProjectId() != null && !metadataConfig.getProjectId().isEmpty(); } - /** Enum containing various Google Cloud Platforms that can be detected by the support library. */ - public enum GCPPlatform { + private DetectedPlatform generateDetectedPlatform(SupportedPlatform platform) { + DetectedPlatform detectedPlatform; + switch (platform) { + case GOOGLE_KUBERNETES_ENGINE: + detectedPlatform = new GoogleKubernetesEngine(); + break; + case GOOGLE_CLOUD_RUN: + detectedPlatform = new GoogleCloudRun(); + break; + case GOOGLE_CLOUD_FUNCTIONS: + detectedPlatform = new GoogleCloudFunction(); + break; + case GOOGLE_APP_ENGINE: + detectedPlatform = new GoogleAppEngine(); + break; + case GOOGLE_COMPUTE_ENGINE: + detectedPlatform = new GoogleComputeEngine(); + break; + default: + detectedPlatform = new UnknownPlatform(); + } + return detectedPlatform; + } + + public enum SupportedPlatform { GOOGLE_COMPUTE_ENGINE, GOOGLE_KUBERNETES_ENGINE, GOOGLE_APP_ENGINE, diff --git a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GKEDetector.java b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GKEDetector.java deleted file mode 100644 index e6c025ae..00000000 --- a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GKEDetector.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2023 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.opentelemetry.detectors; - -import java.util.Optional; - -/** Utility class to help add GKE specific attributes to a given resource */ -public final class GKEDetector { - public static final GKEDetector DEFAULT_INSTANCE = new GKEDetector(); - - private final EnvironmentVariables environmentVariables; - private final GCPMetadataConfig metadataConfig; - - GKEDetector() { - this.environmentVariables = EnvironmentVariables.DEFAULT_INSTANCE; - this.metadataConfig = GCPMetadataConfig.DEFAULT_INSTANCE; - } - - // for testing only - GKEDetector(EnvironmentVariables environmentVariables, GCPMetadataConfig metadataConfig) { - this.environmentVariables = environmentVariables; - this.metadataConfig = metadataConfig; - } - - public String getPodName() { - Optional podName = Optional.ofNullable(this.environmentVariables.get("POD_NAME")); - return podName.orElse(this.environmentVariables.get("HOSTNAME")); - } - - public Optional getNamespace() { - return Optional.ofNullable(this.environmentVariables.get("NAMESPACE")); - } - - public Optional getContainerName() { - return Optional.ofNullable(this.environmentVariables.get("CONTAINER_NAME")); - } - - public Optional getHostID() { - return Optional.ofNullable(this.metadataConfig.getInstanceId()); - } - - public Optional getClusterName() { - return Optional.ofNullable(this.metadataConfig.getClusterName()); - } - - public GKEZoneOrRegion getGKEClusterLocation() { - return new GKEZoneOrRegion(this.metadataConfig.getClusterLocation()); - } - - public enum LocationType { - ZONE, - REGION, - UNDEFINED, - } - - public static final class GKEZoneOrRegion { - - private final LocationType locationType; - private final String clusterLocation; - - GKEZoneOrRegion(String clusterLocation) { - this.clusterLocation = clusterLocation; - this.locationType = determineClusterLocationType(clusterLocation); - } - - public LocationType getLocationType() { - return this.locationType; - } - - public String getClusterLocation() { - return this.clusterLocation; - } - - private LocationType determineClusterLocationType(String clusterLocation) { - long dashCount = - (clusterLocation == null || clusterLocation.isEmpty()) - ? 0 - : clusterLocation.chars().filter(ch -> ch == '-').count(); - if (dashCount == 1) { - return LocationType.REGION; - } else if (dashCount == 2) { - return LocationType.ZONE; - } - return LocationType.UNDEFINED; - } - } -} diff --git a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleAppEngine.java b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleAppEngine.java new file mode 100644 index 00000000..813e2c45 --- /dev/null +++ b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleAppEngine.java @@ -0,0 +1,62 @@ +package com.google.cloud.opentelemetry.detectors; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GAE_APP_VERSION; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GAE_AVAILABILITY_ZONE; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GAE_CLOUD_REGION; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GAE_INSTANCE_ID; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GAE_MODULE_NAME; + +final class GoogleAppEngine implements DetectedPlatform { + private final EnvironmentVariables environmentVariables; + private final GCPMetadataConfig metadataConfig; + private final Map> availableAttributes; + + GoogleAppEngine() { + this.environmentVariables = EnvironmentVariables.DEFAULT_INSTANCE; + this.metadataConfig = GCPMetadataConfig.DEFAULT_INSTANCE; + this.availableAttributes = prepareAttributes(); + } + + // for testing only + GoogleAppEngine(EnvironmentVariables environmentVariables, GCPMetadataConfig metadataConfig) { + this.environmentVariables = environmentVariables; + this.metadataConfig = metadataConfig; + this.availableAttributes = prepareAttributes(); + } + + private Map> prepareAttributes() { + Map> map = new HashMap<>(); + map.put(GAE_MODULE_NAME, Optional.ofNullable(this.environmentVariables.get("GAE_SERVICE"))); + map.put(GAE_APP_VERSION, Optional.ofNullable(this.environmentVariables.get("GAE_VERSION"))); + map.put(GAE_INSTANCE_ID, Optional.ofNullable(this.environmentVariables.get("GAE_INSTANCE"))); + map.put( + GAE_AVAILABILITY_ZONE, + CloudLocationUtil.getAvailabilityZoneFromMetadata(this.metadataConfig)); + map.put(GAE_CLOUD_REGION, getCloudRegion()); + return Collections.unmodifiableMap(map); + } + + private Optional getCloudRegion() { + if (this.environmentVariables.get("GAE_ENV") != null + && this.environmentVariables.get("GAE_ENV").equals("standard")) { + return CloudLocationUtil.getCloudRegionFromMetadataUsingRegion(this.metadataConfig); + } else { + return CloudLocationUtil.getCloudRegionFromMetadataUsingZone(this.metadataConfig); + } + } + + @Override + public GCPPlatformDetector.SupportedPlatform getSupportedPlatform() { + return GCPPlatformDetector.SupportedPlatform.GOOGLE_APP_ENGINE; + } + + @Override + public Map> getAttributes() { + return this.availableAttributes; + } +} diff --git a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleCloudFunction.java b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleCloudFunction.java new file mode 100644 index 00000000..60b8e03b --- /dev/null +++ b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleCloudFunction.java @@ -0,0 +1,8 @@ +package com.google.cloud.opentelemetry.detectors; + +class GoogleCloudFunction extends GoogleServerlessCompute { + @Override + public GCPPlatformDetector.SupportedPlatform getSupportedPlatform() { + return GCPPlatformDetector.SupportedPlatform.GOOGLE_CLOUD_FUNCTIONS; + } +} diff --git a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleCloudRun.java b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleCloudRun.java new file mode 100644 index 00000000..dd050bec --- /dev/null +++ b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleCloudRun.java @@ -0,0 +1,23 @@ +/* + * Copyright 2023 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.opentelemetry.detectors; + +class GoogleCloudRun extends GoogleServerlessCompute { + @Override + public GCPPlatformDetector.SupportedPlatform getSupportedPlatform() { + return GCPPlatformDetector.SupportedPlatform.GOOGLE_CLOUD_RUN; + } +} diff --git a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleComputeEngine.java b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleComputeEngine.java new file mode 100644 index 00000000..418a0478 --- /dev/null +++ b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleComputeEngine.java @@ -0,0 +1,55 @@ +package com.google.cloud.opentelemetry.detectors; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GCE_AVAILABILITY_ZONE; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GCE_CLOUD_REGION; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GCE_INSTANCE_ID; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GCE_INSTANCE_NAME; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GCE_MACHINE_TYPE; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GCE_PROJECT_ID; + +final class GoogleComputeEngine implements DetectedPlatform { + private final GCPMetadataConfig metadataConfig; + private final Map> availableAttributes; + + GoogleComputeEngine() { + this.metadataConfig = GCPMetadataConfig.DEFAULT_INSTANCE; + this.availableAttributes = prepareAttributes(); + } + + // for testing only + GoogleComputeEngine( + GCPMetadataConfig metadataConfig, Map> availableAttributes) { + this.metadataConfig = metadataConfig; + this.availableAttributes = availableAttributes; + } + + private Map> prepareAttributes() { + Map> map = new HashMap<>(); + map.put(GCE_PROJECT_ID, Optional.ofNullable(this.metadataConfig.getProjectId())); + map.put( + GCE_AVAILABILITY_ZONE, + CloudLocationUtil.getAvailabilityZoneFromMetadata(this.metadataConfig)); + map.put( + GCE_CLOUD_REGION, + CloudLocationUtil.getCloudRegionFromMetadataUsingZone(this.metadataConfig)); + map.put(GCE_INSTANCE_ID, Optional.ofNullable(this.metadataConfig.getInstanceId())); + map.put(GCE_INSTANCE_NAME, Optional.ofNullable(this.metadataConfig.getInstanceName())); + map.put(GCE_MACHINE_TYPE, Optional.ofNullable(this.metadataConfig.getMachineType())); + return Collections.unmodifiableMap(map); + } + + @Override + public GCPPlatformDetector.SupportedPlatform getSupportedPlatform() { + return GCPPlatformDetector.SupportedPlatform.GOOGLE_COMPUTE_ENGINE; + } + + @Override + public Map> getAttributes() { + return this.availableAttributes; + } +} diff --git a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleKubernetesEngine.java b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleKubernetesEngine.java new file mode 100644 index 00000000..b8428cb3 --- /dev/null +++ b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleKubernetesEngine.java @@ -0,0 +1,79 @@ +package com.google.cloud.opentelemetry.detectors; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GKE_CLUSTER_LOCATION; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GKE_CLUSTER_LOCATION_TYPE; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GKE_CLUSTER_NAME; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GKE_CONTAINER_NAME; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GKE_HOST_ID; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GKE_LOCATION_TYPE_REGION; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GKE_LOCATION_TYPE_ZONE; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GKE_NAMESPACE; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GKE_POD_NAME; + +/** Utility class to help add GKE specific attributes to a given resource */ +final class GoogleKubernetesEngine implements DetectedPlatform { + private final EnvironmentVariables environmentVariables; + private final GCPMetadataConfig metadataConfig; + private final Map> availableAttributes; + + GoogleKubernetesEngine() { + this.environmentVariables = EnvironmentVariables.DEFAULT_INSTANCE; + this.metadataConfig = GCPMetadataConfig.DEFAULT_INSTANCE; + this.availableAttributes = prepareAttributes(); + } + + // for testing only + GoogleKubernetesEngine( + EnvironmentVariables environmentVariables, GCPMetadataConfig metadataConfig) { + this.environmentVariables = environmentVariables; + this.metadataConfig = metadataConfig; + this.availableAttributes = prepareAttributes(); + } + + private Map> prepareAttributes() { + Map> map = new HashMap<>(); + map.put(GKE_POD_NAME, Optional.ofNullable(getPodName())); + map.put(GKE_NAMESPACE, Optional.ofNullable(this.environmentVariables.get("NAMESPACE"))); + map.put( + GKE_CONTAINER_NAME, Optional.ofNullable(this.environmentVariables.get("CONTAINER_NAME"))); + map.put(GKE_CLUSTER_NAME, Optional.ofNullable(this.metadataConfig.getClusterName())); + map.put(GKE_CLUSTER_LOCATION, Optional.of(this.metadataConfig.getClusterLocation())); + map.put(GKE_CLUSTER_LOCATION_TYPE, Optional.of(this.getClusterLocationType())); + map.put(GKE_HOST_ID, Optional.ofNullable(this.metadataConfig.getInstanceId())); + return Collections.unmodifiableMap(map); + } + + private String getPodName() { + Optional podName = Optional.ofNullable(this.environmentVariables.get("POD_NAME")); + return podName.orElse(this.environmentVariables.get("HOSTNAME")); + } + + private String getClusterLocationType() { + String clusterLocation = this.metadataConfig.getClusterLocation(); + long dashCount = + (clusterLocation == null || clusterLocation.isEmpty()) + ? 0 + : clusterLocation.chars().filter(ch -> ch == '-').count(); + if (dashCount == 1) { + return GKE_LOCATION_TYPE_REGION; + } else if (dashCount == 2) { + return GKE_LOCATION_TYPE_ZONE; + } + return ""; + } + + @Override + public GCPPlatformDetector.SupportedPlatform getSupportedPlatform() { + return GCPPlatformDetector.SupportedPlatform.GOOGLE_KUBERNETES_ENGINE; + } + + @Override + public Map> getAttributes() { + return this.availableAttributes; + } +} diff --git a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleServerlessCompute.java b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleServerlessCompute.java new file mode 100644 index 00000000..dc3386fb --- /dev/null +++ b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/GoogleServerlessCompute.java @@ -0,0 +1,54 @@ +package com.google.cloud.opentelemetry.detectors; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +/** + * Utility class to help add attributes applicable to serverless compute in GCP to a given resource. + */ +abstract class GoogleServerlessCompute implements DetectedPlatform { + private final EnvironmentVariables environmentVariables; + private final GCPMetadataConfig metadataConfig; + private final Map> availableAttributes; + + GoogleServerlessCompute() { + this.environmentVariables = EnvironmentVariables.DEFAULT_INSTANCE; + this.metadataConfig = GCPMetadataConfig.DEFAULT_INSTANCE; + this.availableAttributes = prepareAttributes(); + } + + // for testing only + GoogleServerlessCompute( + EnvironmentVariables environmentVariables, GCPMetadataConfig metadataConfig) { + this.environmentVariables = environmentVariables; + this.metadataConfig = metadataConfig; + this.availableAttributes = prepareAttributes(); + } + + private Map> prepareAttributes() { + Map> map = new HashMap<>(); + map.put( + AttributeKeys.SERVERLESS_COMPUTE_NAME, + Optional.ofNullable(this.environmentVariables.get("K_SERVICE"))); + map.put( + AttributeKeys.SERVERLESS_COMPUTE_REVISION, + Optional.ofNullable(this.environmentVariables.get("K_REVISION"))); + map.put( + AttributeKeys.SERVERLESS_COMPUTE_AVAILABILITY_ZONE, + CloudLocationUtil.getAvailabilityZoneFromMetadata(this.metadataConfig)); + map.put( + AttributeKeys.SERVERLESS_COMPUTE_CLOUD_REGION, + CloudLocationUtil.getCloudRegionFromMetadataUsingZone(this.metadataConfig)); + map.put( + AttributeKeys.SERVERLESS_COMPUTE_INSTANCE_ID, + Optional.ofNullable(this.metadataConfig.getInstanceId())); + return Collections.unmodifiableMap(map); + } + + @Override + public Map> getAttributes() { + return this.availableAttributes; + } +} diff --git a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/ServerlessComputeDetector.java b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/ServerlessComputeDetector.java deleted file mode 100644 index 056d39ad..00000000 --- a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/ServerlessComputeDetector.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2023 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.opentelemetry.detectors; - -import java.util.Optional; - -/** - * Utility class to help add attributes applicable to serverless compute in GCP to a given resource. - */ -public final class ServerlessComputeDetector { - public static final ServerlessComputeDetector DEFAULT_INSTANCE = new ServerlessComputeDetector(); - - private final EnvironmentVariables environmentVariables; - private final GCPMetadataConfig metadataConfig; - - ServerlessComputeDetector() { - this.environmentVariables = EnvironmentVariables.DEFAULT_INSTANCE; - this.metadataConfig = GCPMetadataConfig.DEFAULT_INSTANCE; - } - - // for testing only - ServerlessComputeDetector( - EnvironmentVariables environmentVariables, GCPMetadataConfig metadataConfig) { - this.environmentVariables = environmentVariables; - this.metadataConfig = metadataConfig; - } - - public Optional getServerlessComputeName() { - return Optional.ofNullable(this.environmentVariables.get("K_SERVICE")); - } - - public Optional getServerlessComputeRevision() { - return Optional.ofNullable(this.environmentVariables.get("K_REVISION")); - } - - public Optional getAvailabilityZone() { - return CloudLocationUtil.getAvailabilityZoneFromMetadata(this.metadataConfig); - } - - public Optional getCloudRegion() { - return CloudLocationUtil.getCloudRegionFromMetadataUsingZone(this.metadataConfig); - } - - public Optional getInstanceId() { - return Optional.ofNullable(this.metadataConfig.getInstanceId()); - } -} diff --git a/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/UnknownPlatform.java b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/UnknownPlatform.java new file mode 100644 index 00000000..c36ff4fc --- /dev/null +++ b/detectors/resources-support/src/main/java/com/google/cloud/opentelemetry/detectors/UnknownPlatform.java @@ -0,0 +1,20 @@ +package com.google.cloud.opentelemetry.detectors; + +import java.util.Collections; +import java.util.Map; +import java.util.Optional; + +class UnknownPlatform implements DetectedPlatform { + + UnknownPlatform() {} + + @Override + public GCPPlatformDetector.SupportedPlatform getSupportedPlatform() { + return GCPPlatformDetector.SupportedPlatform.UNKNOWN_PLATFORM; + } + + @Override + public Map> getAttributes() { + return Collections.emptyMap(); + } +} diff --git a/detectors/resources/src/main/java/com/google/cloud/opentelemetry/detectors/GCPResourceProvider.java b/detectors/resources/src/main/java/com/google/cloud/opentelemetry/detectors/GCPResourceProvider.java index b35f38b5..5d8362a9 100644 --- a/detectors/resources/src/main/java/com/google/cloud/opentelemetry/detectors/GCPResourceProvider.java +++ b/detectors/resources/src/main/java/com/google/cloud/opentelemetry/detectors/GCPResourceProvider.java @@ -15,12 +15,16 @@ */ package com.google.cloud.opentelemetry.detectors; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.*; + import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.semconv.ResourceAttributes; +import java.util.Map; +import java.util.Optional; import java.util.logging.Logger; /** @@ -31,6 +35,16 @@ public class GCPResourceProvider implements ResourceProvider { private static final Logger LOGGER = Logger.getLogger(GCPResourceProvider.class.getSimpleName()); + private final GCPPlatformDetector detector; + + // for testing only + GCPResourceProvider(GCPPlatformDetector detector) { + this.detector = detector; + } + + public GCPResourceProvider() { + this.detector = GCPPlatformDetector.DEFAULT_INSTANCE; + } /** * Generates and returns the attributes for the resource. The attributes vary depending on the @@ -39,9 +53,9 @@ public class GCPResourceProvider implements ResourceProvider { * @return The {@link Attributes} for the detected resource. */ public Attributes getAttributes() { - GCPPlatformDetector.GCPPlatform detectedPlatform = - GCPPlatformDetector.DEFAULT_INSTANCE.detectPlatform(); - if (detectedPlatform == GCPPlatformDetector.GCPPlatform.UNKNOWN_PLATFORM) { + DetectedPlatform detectedPlatform = detector.detectPlatform(); + if (detectedPlatform.getSupportedPlatform() + == GCPPlatformDetector.SupportedPlatform.UNKNOWN_PLATFORM) { return Attributes.empty(); } @@ -49,22 +63,22 @@ public Attributes getAttributes() { AttributesBuilder attrBuilder = Attributes.builder(); attrBuilder.put(ResourceAttributes.CLOUD_PROVIDER, ResourceAttributes.CloudProviderValues.GCP); - switch (detectedPlatform) { + switch (detectedPlatform.getSupportedPlatform()) { case GOOGLE_KUBERNETES_ENGINE: - addGKEAttributes(attrBuilder); + addGKEAttributes(attrBuilder, detectedPlatform.getAttributes()); break; case GOOGLE_CLOUD_RUN: - addGCRAttributes(attrBuilder); + addGCRAttributes(attrBuilder, detectedPlatform.getAttributes()); break; case GOOGLE_CLOUD_FUNCTIONS: - addGCFAttributes(attrBuilder); + addGCFAttributes(attrBuilder, detectedPlatform.getAttributes()); break; case GOOGLE_APP_ENGINE: - addGAEAttributes(attrBuilder); + addGAEAttributes(attrBuilder, detectedPlatform.getAttributes()); break; case GOOGLE_COMPUTE_ENGINE: default: - addGCEAttributes(attrBuilder); + addGCEAttributes(attrBuilder, detectedPlatform.getAttributes()); } return attrBuilder.build(); @@ -81,28 +95,29 @@ public Resource createResource(ConfigProperties config) { * additional attributes are added/overwritten if later on, the resource is identified to be some * other platform - like GKE, GAE, etc. */ - private void addGCEAttributes(AttributesBuilder attrBuilder) { + private void addGCEAttributes( + AttributesBuilder attrBuilder, Map> attributesMap) { attrBuilder.put( ResourceAttributes.CLOUD_PLATFORM, ResourceAttributes.CloudPlatformValues.GCP_COMPUTE_ENGINE); - GCEDetector.DEFAULT_INSTANCE - .getProjectId() + attributesMap + .get(GCE_PROJECT_ID) .ifPresent(projectId -> attrBuilder.put(ResourceAttributes.CLOUD_ACCOUNT_ID, projectId)); - GCEDetector.DEFAULT_INSTANCE - .getAvailabilityZone() + attributesMap + .get(GCE_AVAILABILITY_ZONE) .ifPresent(zone -> attrBuilder.put(ResourceAttributes.CLOUD_AVAILABILITY_ZONE, zone)); - GCEDetector.DEFAULT_INSTANCE - .getCloudRegion() + attributesMap + .get(GCE_CLOUD_REGION) .ifPresent(region -> attrBuilder.put(ResourceAttributes.CLOUD_REGION, region)); - GCEDetector.DEFAULT_INSTANCE - .getInstanceId() + attributesMap + .get(GCE_INSTANCE_ID) .ifPresent(instanceId -> attrBuilder.put(ResourceAttributes.HOST_ID, instanceId)); - GCEDetector.DEFAULT_INSTANCE - .getInstanceName() + attributesMap + .get(GCE_INSTANCE_NAME) .ifPresent(instanceName -> attrBuilder.put(ResourceAttributes.HOST_NAME, instanceName)); - GCEDetector.DEFAULT_INSTANCE - .getMachineType() + attributesMap + .get(GCE_MACHINE_TYPE) .ifPresent(machineType -> attrBuilder.put(ResourceAttributes.HOST_TYPE, machineType)); } @@ -113,38 +128,50 @@ private void addGCEAttributes(AttributesBuilder attrBuilder) { * @param attrBuilder The {@link AttributesBuilder} object that needs to be updated with the * necessary keys. */ - private void addGKEAttributes(AttributesBuilder attrBuilder) { + private void addGKEAttributes( + AttributesBuilder attrBuilder, Map> attributesMap) { attrBuilder.put( ResourceAttributes.CLOUD_PLATFORM, ResourceAttributes.CloudPlatformValues.GCP_KUBERNETES_ENGINE); - attrBuilder.put(ResourceAttributes.K8S_POD_NAME, GKEDetector.DEFAULT_INSTANCE.getPodName()); - GKEDetector.DEFAULT_INSTANCE - .getNamespace() + + attributesMap + .get(GKE_POD_NAME) + .ifPresent(podName -> attrBuilder.put(ResourceAttributes.K8S_POD_NAME, podName)); + attributesMap + .get(GKE_NAMESPACE) .ifPresent(namespace -> attrBuilder.put(ResourceAttributes.K8S_NAMESPACE_NAME, namespace)); - GKEDetector.DEFAULT_INSTANCE - .getContainerName() + attributesMap + .get(GKE_CONTAINER_NAME) .ifPresent( containerName -> attrBuilder.put(ResourceAttributes.K8S_CONTAINER_NAME, containerName)); - GKEDetector.DEFAULT_INSTANCE - .getClusterName() + attributesMap + .get(GKE_CLUSTER_NAME) .ifPresent( clusterName -> attrBuilder.put(ResourceAttributes.K8S_CLUSTER_NAME, clusterName)); - GKEDetector.GKEZoneOrRegion zoneOrRegion = GKEDetector.DEFAULT_INSTANCE.getGKEClusterLocation(); - switch (zoneOrRegion.getLocationType()) { - case REGION: - attrBuilder.put(ResourceAttributes.CLOUD_REGION, zoneOrRegion.getClusterLocation()); - break; - case ZONE: - attrBuilder.put( - ResourceAttributes.CLOUD_AVAILABILITY_ZONE, zoneOrRegion.getClusterLocation()); - break; - case UNDEFINED: - default: - // TODO: Figure out how to handle unexpected conditions like this - Issue #183 - LOGGER.severe( - String.format( - "Unrecognized format for cluster location: %s", zoneOrRegion.getClusterLocation())); - } + attributesMap + .get(GKE_CLUSTER_LOCATION_TYPE) + .ifPresent( + locationType -> { + if (attributesMap.get(GKE_CLUSTER_LOCATION).isPresent()) { + switch (locationType) { + case GKE_LOCATION_TYPE_REGION: + attrBuilder.put( + ResourceAttributes.CLOUD_REGION, + attributesMap.get(GKE_CLUSTER_LOCATION).get()); + break; + case GKE_LOCATION_TYPE_ZONE: + attrBuilder.put( + ResourceAttributes.CLOUD_AVAILABILITY_ZONE, + attributesMap.get(GKE_CLUSTER_LOCATION).get()); + default: + // TODO: Figure out how to handle unexpected conditions like this - Issue #183 + LOGGER.severe( + String.format( + "Unrecognized format for cluster location: %s", + attributesMap.get(GKE_CLUSTER_LOCATION))); + } + } + }); } /** @@ -154,10 +181,11 @@ private void addGKEAttributes(AttributesBuilder attrBuilder) { * @param attrBuilder The {@link AttributesBuilder} object that needs to be updated with the * necessary keys. */ - private void addGCRAttributes(AttributesBuilder attrBuilder) { + private void addGCRAttributes( + AttributesBuilder attrBuilder, Map> attributesMap) { attrBuilder.put( ResourceAttributes.CLOUD_PLATFORM, ResourceAttributes.CloudPlatformValues.GCP_CLOUD_RUN); - addCommonAttributesForServerlessCompute(attrBuilder); + addCommonAttributesForServerlessCompute(attrBuilder, attributesMap); } /** @@ -167,11 +195,12 @@ private void addGCRAttributes(AttributesBuilder attrBuilder) { * @param attrBuilder The {@link AttributesBuilder} object that needs to be updated with the * necessary keys. */ - private void addGCFAttributes(AttributesBuilder attrBuilder) { + private void addGCFAttributes( + AttributesBuilder attrBuilder, Map> attributesMap) { attrBuilder.put( ResourceAttributes.CLOUD_PLATFORM, ResourceAttributes.CloudPlatformValues.GCP_CLOUD_FUNCTIONS); - addCommonAttributesForServerlessCompute(attrBuilder); + addCommonAttributesForServerlessCompute(attrBuilder, attributesMap); } /** @@ -181,24 +210,25 @@ private void addGCFAttributes(AttributesBuilder attrBuilder) { * @param attrBuilder The {@link AttributesBuilder} object that needs to be updated with the * necessary keys. */ - private void addGAEAttributes(AttributesBuilder attrBuilder) { + private void addGAEAttributes( + AttributesBuilder attrBuilder, Map> attributesMap) { attrBuilder.put( ResourceAttributes.CLOUD_PLATFORM, ResourceAttributes.CloudPlatformValues.GCP_APP_ENGINE); - GAEDetector.DEFAULT_INSTANCE - .getAppModuleName() + attributesMap + .get(GAE_MODULE_NAME) .ifPresent(appName -> attrBuilder.put(ResourceAttributes.FAAS_NAME, appName)); - GAEDetector.DEFAULT_INSTANCE - .getAppVersion() + attributesMap + .get(GAE_APP_VERSION) .ifPresent(appVersion -> attrBuilder.put(ResourceAttributes.FAAS_VERSION, appVersion)); - GAEDetector.DEFAULT_INSTANCE - .getAppInstanceId() + attributesMap + .get(GAE_INSTANCE_ID) .ifPresent( appInstanceId -> attrBuilder.put(ResourceAttributes.FAAS_INSTANCE, appInstanceId)); - GAEDetector.DEFAULT_INSTANCE - .getCloudRegion() + attributesMap + .get(GAE_CLOUD_REGION) .ifPresent(cloudRegion -> attrBuilder.put(ResourceAttributes.CLOUD_REGION, cloudRegion)); - GAEDetector.DEFAULT_INSTANCE - .getAvailabilityZone() + attributesMap + .get(GAE_AVAILABILITY_ZONE) .ifPresent( cloudAvailabilityZone -> attrBuilder.put(ResourceAttributes.CLOUD_AVAILABILITY_ZONE, cloudAvailabilityZone)); @@ -211,25 +241,22 @@ private void addGAEAttributes(AttributesBuilder attrBuilder) { * @param attrBuilder The {@link AttributesBuilder} object that needs to be updated with the * necessary keys. */ - private void addCommonAttributesForServerlessCompute(AttributesBuilder attrBuilder) { - ServerlessComputeDetector.DEFAULT_INSTANCE - .getServerlessComputeName() - .ifPresent( - serverlessComputeName -> - attrBuilder.put(ResourceAttributes.FAAS_NAME, serverlessComputeName)); - ServerlessComputeDetector.DEFAULT_INSTANCE - .getServerlessComputeRevision() - .ifPresent( - serverlessComputeVersion -> - attrBuilder.put(ResourceAttributes.FAAS_VERSION, serverlessComputeVersion)); - ServerlessComputeDetector.DEFAULT_INSTANCE - .getInstanceId() + private void addCommonAttributesForServerlessCompute( + AttributesBuilder attrBuilder, Map> attributesMap) { + attributesMap + .get(SERVERLESS_COMPUTE_NAME) + .ifPresent(name -> attrBuilder.put(ResourceAttributes.FAAS_NAME, name)); + attributesMap + .get(SERVERLESS_COMPUTE_REVISION) + .ifPresent(revision -> attrBuilder.put(ResourceAttributes.FAAS_VERSION, revision)); + attributesMap + .get(SERVERLESS_COMPUTE_INSTANCE_ID) .ifPresent(instanceId -> attrBuilder.put(ResourceAttributes.FAAS_INSTANCE, instanceId)); - ServerlessComputeDetector.DEFAULT_INSTANCE - .getAvailabilityZone() + attributesMap + .get(SERVERLESS_COMPUTE_AVAILABILITY_ZONE) .ifPresent(zone -> attrBuilder.put(ResourceAttributes.CLOUD_AVAILABILITY_ZONE, zone)); - ServerlessComputeDetector.DEFAULT_INSTANCE - .getCloudRegion() + attributesMap + .get(SERVERLESS_COMPUTE_CLOUD_REGION) .ifPresent(region -> attrBuilder.put(ResourceAttributes.CLOUD_REGION, region)); } } diff --git a/detectors/resources/src/test/java/com/google/cloud/opentelemetry/detectors/GCPResourceProviderTest.java b/detectors/resources/src/test/java/com/google/cloud/opentelemetry/detectors/GCPResourceProviderTest.java index 82c80cb7..c2dc5940 100644 --- a/detectors/resources/src/test/java/com/google/cloud/opentelemetry/detectors/GCPResourceProviderTest.java +++ b/detectors/resources/src/test/java/com/google/cloud/opentelemetry/detectors/GCPResourceProviderTest.java @@ -15,11 +15,25 @@ */ package com.google.cloud.opentelemetry.detectors; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GCE_AVAILABILITY_ZONE; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GCE_CLOUD_REGION; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GCE_INSTANCE_ID; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GCE_INSTANCE_NAME; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GCE_MACHINE_TYPE; +import static com.google.cloud.opentelemetry.detectors.AttributeKeys.GCE_PROJECT_ID; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.semconv.ResourceAttributes; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.mockito.Mockito; @RunWith(JUnit4.class) public class GCPResourceProviderTest { @@ -28,6 +42,63 @@ public void testDummy() { // Dummy test assertThat(true).isEqualTo(true); } + + private DetectedPlatform generateMockGCEPlatform() { + return new DetectedPlatform() { + @Override + public GCPPlatformDetector.SupportedPlatform getSupportedPlatform() { + return GCPPlatformDetector.SupportedPlatform.GOOGLE_COMPUTE_ENGINE; + } + + @Override + public Map> getAttributes() { + return new HashMap<>() { + { + put(GCE_PROJECT_ID, Optional.of("test-project-id")); + put(GCE_AVAILABILITY_ZONE, Optional.empty()); + put(GCE_CLOUD_REGION, Optional.of("australia-southeast1")); + put(GCE_INSTANCE_ID, Optional.of("random-id")); + put(GCE_INSTANCE_NAME, Optional.of("instance-name")); + put(GCE_MACHINE_TYPE, Optional.of("gce-m2")); + } + }; + } + }; + } + + @Test + public void testGCEResourceAttributesMapping() { + GCPPlatformDetector mockDetector = Mockito.mock(GCPPlatformDetector.class); + DetectedPlatform mockPlatform = generateMockGCEPlatform(); + Mockito.when(mockDetector.detectPlatform()).thenReturn(mockPlatform); + + Resource gotResource = new GCPResourceProvider(mockDetector).createResource(null); + + assertEquals( + ResourceAttributes.CloudPlatformValues.GCP_COMPUTE_ENGINE, + gotResource.getAttributes().get(ResourceAttributes.CLOUD_PLATFORM)); + assertEquals( + ResourceAttributes.CloudProviderValues.GCP, + gotResource.getAttributes().get(ResourceAttributes.CLOUD_PROVIDER)); + + assertEquals( + mockPlatform.getAttributes().get(GCE_PROJECT_ID).orElse(""), + gotResource.getAttributes().get(ResourceAttributes.CLOUD_ACCOUNT_ID)); + assertEquals( + mockPlatform.getAttributes().get(GCE_INSTANCE_ID).orElse(""), + gotResource.getAttributes().get(ResourceAttributes.HOST_ID)); + assertEquals( + mockPlatform.getAttributes().get(GCE_INSTANCE_NAME).orElse(""), + gotResource.getAttributes().get(ResourceAttributes.HOST_NAME)); + assertEquals( + mockPlatform.getAttributes().get(GCE_MACHINE_TYPE).orElse(""), + gotResource.getAttributes().get(ResourceAttributes.HOST_TYPE)); + assertNull(gotResource.getAttributes().get(ResourceAttributes.CLOUD_AVAILABILITY_ZONE)); + assertEquals( + mockPlatform.getAttributes().get(GCE_CLOUD_REGION).orElse(""), + gotResource.getAttributes().get(ResourceAttributes.CLOUD_REGION)); + } + // @Rule public final WireMockRule wireMockRule = new WireMockRule(8089); // private final GCPMetadataConfig metadataConfig = new // GCPMetadataConfig("http://localhost:8089/", EnvironmentVariables.DEFAULT_INSTANCE);