diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 229f08131b..d0f4aa71b2 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -54,6 +54,7 @@ body:
- OpenTelemetry.ResourceDetectors.Host
- OpenTelemetry.ResourceDetectors.Process
- OpenTelemetry.ResourceDetectors.ProcessRuntime
+ - OpenTelemetry.Resources.Gcp
- OpenTelemetry.Sampler.AWS
- OpenTelemetry.SemanticConventions
validations:
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
index 9fecb78998..2d8c7483d7 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -54,6 +54,7 @@ body:
- OpenTelemetry.ResourceDetectors.Host
- OpenTelemetry.ResourceDetectors.Process
- OpenTelemetry.ResourceDetectors.ProcessRuntime
+ - OpenTelemetry.Resources.Gcp
- OpenTelemetry.Sampler.AWS
- OpenTelemetry.SemanticConventions
diff --git a/.github/codecov.yml b/.github/codecov.yml
index 93c6e5eb08..3981524084 100644
--- a/.github/codecov.yml
+++ b/.github/codecov.yml
@@ -119,6 +119,11 @@ flags:
paths:
- src/OpenTelemetry.ResourceDetectors.Azure
+ unittests-Resources.Gcp:
+ carryforward: true
+ paths:
+ - src/OpenTelemetry.Resources.Gcp
+
unittests-ResourceDetectors.Host:
carryforward: true
paths:
diff --git a/.github/component_owners.yml b/.github/component_owners.yml
index 73aba2c284..7df093a797 100644
--- a/.github/component_owners.yml
+++ b/.github/component_owners.yml
@@ -79,6 +79,9 @@ components:
src/OpenTelemetry.ResourceDetectors.ProcessRuntime/:
- Kielek
- lachmatt
+ src/OpenTelemetry.Resources.Gcp/:
+ - matt-hensley
+ - pyohannes
src/OpenTelemetry.Sampler.AWS/:
- srprash
- atshaw43
@@ -169,6 +172,9 @@ components:
test/OpenTelemetry.ResourceDetectors.ProcessRuntime.Tests/:
- Kielek
- lachmatt
+ test/OpenTelemetry.Resources.Gcp.Tests/:
+ - matt-hensley
+ - pyohannes
test/OpenTelemetry.Sampler.AWS.Tests/:
- srprash
- atshaw43
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a6e0614a40..f07c34505b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -30,6 +30,7 @@ jobs:
eventcounters: ['*/OpenTelemetry.Instrumentation.EventCounters*/**', 'examples/event-counters/**', '!**/*.md']
extensions: ['*/OpenTelemetry.Extensions/**', '*/OpenTelemetry.Extensions.Tests/**', '!**/*.md']
geneva: ['*/OpenTelemetry.Exporter.Geneva*/**', '!**/*.md']
+ gcp: ['*/OpenTelemetry.Resources.Gcp*/**', '!**/*.md']
grpcnetclient: ['*/OpenTelemetry.Instrumentation.GrpcNetClient*/**', '!**/*.md']
host: ['*/OpenTelemetry.ResourceDetectors.Host*/**', '!**/*.md']
http: ['*/OpenTelemetry.Instrumentation.Http*/**', '!**/*.md']
@@ -59,6 +60,7 @@ jobs:
'!*/OpenTelemetry.ResourceDetectors.Process.Tests/**',
'!*/OpenTelemetry.ResourceDetectors.ProcessRuntime/**',
'!*/OpenTelemetry.ResourceDetectors.ProcessRuntime.Tests/**',
+ '!*/OpenTelemetry.Resources.Gcp*/**',
'!*/OpenTelemetry.Instrumentation.EventCounters*/**',
'!examples/event-counters/**',
'!*/OpenTelemetry.Extensions/**',
@@ -167,6 +169,17 @@ jobs:
project-name: OpenTelemetry.Exporter.Geneva
code-cov-name: Exporter.Geneva
+ build-test-gcp:
+ needs: detect-changes
+ if: |
+ contains(needs.detect-changes.outputs.changes, 'gcp')
+ || contains(needs.detect-changes.outputs.changes, 'build')
+ || contains(needs.detect-changes.outputs.changes, 'shared')
+ uses: ./.github/workflows/Component.BuildTest.yml
+ with:
+ project-name: OpenTelemetry.Resources.Gcp
+ code-cov-name: Resources.Gcp
+
build-test-grpcnetclient:
needs: detect-changes
if: |
@@ -379,7 +392,8 @@ jobs:
OpenTelemetry.ResourceDetectors.Azure.Tests.csproj,
OpenTelemetry.ResourceDetectors.Host.Tests.csproj,
OpenTelemetry.ResourceDetectors.Process.Tests.csproj,
- OpenTelemetry.ResourceDetectors.ProcessRuntime.Tests.csproj
+ OpenTelemetry.ResourceDetectors.ProcessRuntime.Tests.csproj,
+ OpenTelemetry.Resources.Gcp.Tests.csproj
$failedProjects = @()
@@ -426,6 +440,7 @@ jobs:
|| contains(needs.detect-changes.outputs.changes, 'aws')
|| contains(needs.detect-changes.outputs.changes, 'azure')
|| contains(needs.detect-changes.outputs.changes, 'extensions')
+ || contains(needs.detect-changes.outputs.changes, 'gcp')
|| contains(needs.detect-changes.outputs.changes, 'grpcnetclient')
|| contains(needs.detect-changes.outputs.changes, 'host')
|| contains(needs.detect-changes.outputs.changes, 'http')
@@ -454,6 +469,7 @@ jobs:
build-test-eventcounters,
build-test-extensions,
build-test-geneva,
+ build-test-gcp,
build-test-grpcnetclient,
build-test-host,
build-test-http,
diff --git a/.github/workflows/package-Resources.Gcp.yml b/.github/workflows/package-Resources.Gcp.yml
new file mode 100644
index 0000000000..a10b917607
--- /dev/null
+++ b/.github/workflows/package-Resources.Gcp.yml
@@ -0,0 +1,21 @@
+name: Pack OpenTelemetry.Resources.Gcp
+
+on:
+ workflow_dispatch:
+ inputs:
+ logLevel:
+ description: 'Log level'
+ required: true
+ default: 'warning'
+ push:
+ tags:
+ - 'Resources.Gcp-*' # trigger when we create a tag with prefix "Resources.Gcp-"
+
+jobs:
+ call-build-test-pack:
+ permissions:
+ contents: write
+ uses: ./.github/workflows/Component.Package.yml
+ with:
+ project-name: OpenTelemetry.Resources.Gcp
+ secrets: inherit
diff --git a/build/Projects/OpenTelemetry.Resources.Gcp.proj b/build/Projects/OpenTelemetry.Resources.Gcp.proj
new file mode 100644
index 0000000000..19364c3155
--- /dev/null
+++ b/build/Projects/OpenTelemetry.Resources.Gcp.proj
@@ -0,0 +1,32 @@
+
+
+
+ $([System.IO.Directory]::GetParent($(MSBuildThisFileDirectory)).Parent.Parent.FullName)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/opentelemetry-dotnet-contrib.sln b/opentelemetry-dotnet-contrib.sln
index 0809cbac97..e8bfaa1c85 100644
--- a/opentelemetry-dotnet-contrib.sln
+++ b/opentelemetry-dotnet-contrib.sln
@@ -338,6 +338,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Projects", "Projects", "{04
build\Projects\OpenTelemetry.ResourceDetectors.Host.proj = build\Projects\OpenTelemetry.ResourceDetectors.Host.proj
build\Projects\OpenTelemetry.ResourceDetectors.Process.proj = build\Projects\OpenTelemetry.ResourceDetectors.Process.proj
build\Projects\OpenTelemetry.ResourceDetectors.ProcessRuntime.proj = build\Projects\OpenTelemetry.ResourceDetectors.ProcessRuntime.proj
+ build\Projects\OpenTelemetry.Resources.Gcp.proj = build\Projects\OpenTelemetry.Resources.Gcp.proj
build\Projects\OpenTelemetry.SemanticConventions.proj = build\Projects\OpenTelemetry.SemanticConventions.proj
EndProjectSection
EndProject
@@ -355,6 +356,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.ResourceDetec
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.PersistentStorage.Abstractions.Tests", "test\OpenTelemetry.PersistentStorage.Abstractions.Tests\OpenTelemetry.PersistentStorage.Abstractions.Tests.csproj", "{7AD707F9-DC6D-430A-8834-D5DCD517BF6E}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Resources.Gcp", "src\OpenTelemetry.Resources.Gcp\OpenTelemetry.Resources.Gcp.csproj", "{CBC6D677-D1FF-470E-A244-477E8616A245}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Resources.Gcp.Tests", "test\OpenTelemetry.Resources.Gcp.Tests\OpenTelemetry.Resources.Gcp.Tests.csproj", "{EECE8D5F-C319-42E8-B37C-A41D6FF43E4A}"
+EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Instrumentation.SqlClient", "src\OpenTelemetry.Instrumentation.SqlClient\OpenTelemetry.Instrumentation.SqlClient.csproj", "{737D1A9E-5A1A-4F4F-830B-E98ED100994C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Instrumentation.SqlClient.Tests", "test\OpenTelemetry.Instrumentation.SqlClient.Tests\OpenTelemetry.Instrumentation.SqlClient.Tests.csproj", "{9C996130-74D7-4FB7-8277-2EE6EBA2BFA6}"
@@ -749,6 +754,14 @@ Global
{1156D564-2E3C-47D6-97C1-FF3ADEDC41C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1156D564-2E3C-47D6-97C1-FF3ADEDC41C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1156D564-2E3C-47D6-97C1-FF3ADEDC41C8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CBC6D677-D1FF-470E-A244-477E8616A245}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CBC6D677-D1FF-470E-A244-477E8616A245}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CBC6D677-D1FF-470E-A244-477E8616A245}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CBC6D677-D1FF-470E-A244-477E8616A245}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EECE8D5F-C319-42E8-B37C-A41D6FF43E4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EECE8D5F-C319-42E8-B37C-A41D6FF43E4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EECE8D5F-C319-42E8-B37C-A41D6FF43E4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EECE8D5F-C319-42E8-B37C-A41D6FF43E4A}.Release|Any CPU.Build.0 = Release|Any CPU
{0156E342-CE63-46F5-992D-691A7CCB50F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0156E342-CE63-46F5-992D-691A7CCB50F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0156E342-CE63-46F5-992D-691A7CCB50F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -882,6 +895,8 @@ Global
{BE92357F-DE09-477D-AFDB-6AD1D7AC7BA1} = {22DF5DC0-1290-4E83-A9D8-6BB7DE3B3E63}
{7371E920-ECD0-403A-A009-7A1A301D9763} = {2097345F-4DD3-477D-BC54-A922F9B2B402}
{1156D564-2E3C-47D6-97C1-FF3ADEDC41C8} = {2097345F-4DD3-477D-BC54-A922F9B2B402}
+ {CBC6D677-D1FF-470E-A244-477E8616A245} = {22DF5DC0-1290-4E83-A9D8-6BB7DE3B3E63}
+ {EECE8D5F-C319-42E8-B37C-A41D6FF43E4A} = {2097345F-4DD3-477D-BC54-A922F9B2B402}
{0156E342-CE63-46F5-992D-691A7CCB50F8} = {22DF5DC0-1290-4E83-A9D8-6BB7DE3B3E63}
{2E1A5759-1431-4724-8885-3E9447FBF617} = {2097345F-4DD3-477D-BC54-A922F9B2B402}
{A8FF0DEB-F371-42FC-8A53-A8C25FE408FC} = {22DF5DC0-1290-4E83-A9D8-6BB7DE3B3E63}
diff --git a/src/OpenTelemetry.Resources.Gcp/.publicApi/PublicAPI.Shipped.txt b/src/OpenTelemetry.Resources.Gcp/.publicApi/PublicAPI.Shipped.txt
new file mode 100644
index 0000000000..7dc5c58110
--- /dev/null
+++ b/src/OpenTelemetry.Resources.Gcp/.publicApi/PublicAPI.Shipped.txt
@@ -0,0 +1 @@
+#nullable enable
diff --git a/src/OpenTelemetry.Resources.Gcp/.publicApi/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Resources.Gcp/.publicApi/PublicAPI.Unshipped.txt
new file mode 100644
index 0000000000..2cd50017d2
--- /dev/null
+++ b/src/OpenTelemetry.Resources.Gcp/.publicApi/PublicAPI.Unshipped.txt
@@ -0,0 +1,2 @@
+OpenTelemetry.Resources.GcpResourceBuilderExtensions
+static OpenTelemetry.Resources.GcpResourceBuilderExtensions.AddGcpDetector(this OpenTelemetry.Resources.ResourceBuilder! builder) -> OpenTelemetry.Resources.ResourceBuilder!
diff --git a/src/OpenTelemetry.Resources.Gcp/AssemblyInfo.cs b/src/OpenTelemetry.Resources.Gcp/AssemblyInfo.cs
new file mode 100644
index 0000000000..0751701190
--- /dev/null
+++ b/src/OpenTelemetry.Resources.Gcp/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using System.Runtime.CompilerServices;
+
+#if SIGNED
+[assembly: InternalsVisibleTo("OpenTelemetry.Resources.Gcp.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010051c1562a090fb0c9f391012a32198b5e5d9a60e9b80fa2d7b434c9e5ccb7259bd606e66f9660676afc6692b8cdc6793d190904551d2103b7b22fa636dcbb8208839785ba402ea08fc00c8f1500ccef28bbf599aa64ffb1e1d5dc1bf3420a3777badfe697856e9d52070a50c3ea5821c80bef17ca3acffa28f89dd413f096f898")]
+#else
+[assembly: InternalsVisibleTo("OpenTelemetry.Resources.Gcp.Tests")]
+#endif
diff --git a/src/OpenTelemetry.Resources.Gcp/CHANGELOG.md b/src/OpenTelemetry.Resources.Gcp/CHANGELOG.md
new file mode 100644
index 0000000000..e1852ed3a7
--- /dev/null
+++ b/src/OpenTelemetry.Resources.Gcp/CHANGELOG.md
@@ -0,0 +1,9 @@
+# Changelog
+
+## Unreleased
+
+* Add Google Cloud Platform resource detector for GKE, GAE, GCR, and GCE. Dectector
+ is accessible via `AddGcpDetector` extension method on `ResourceBuilder`.
+ ([#1691](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/1691))
+
+For more details, please refer to the [README](README.md).
diff --git a/src/OpenTelemetry.Resources.Gcp/GcpResourceBuilderExtensions.cs b/src/OpenTelemetry.Resources.Gcp/GcpResourceBuilderExtensions.cs
new file mode 100644
index 0000000000..154242bb04
--- /dev/null
+++ b/src/OpenTelemetry.Resources.Gcp/GcpResourceBuilderExtensions.cs
@@ -0,0 +1,24 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using OpenTelemetry.Internal;
+using OpenTelemetry.Resources.Gcp;
+
+namespace OpenTelemetry.Resources;
+
+///
+/// Extension methods to simplify registering of Google Cloud Platform resource detectors.
+///
+public static class GcpResourceBuilderExtensions
+{
+ ///
+ /// Enables Google Cloud Platform resource detector.
+ ///
+ /// being configured.
+ /// The instance of being configured.
+ public static ResourceBuilder AddGcpDetector(this ResourceBuilder builder)
+ {
+ Guard.ThrowIfNull(builder);
+ return builder.AddDetector(new GcpResourceDetector());
+ }
+}
diff --git a/src/OpenTelemetry.Resources.Gcp/GcpResourceDetector.cs b/src/OpenTelemetry.Resources.Gcp/GcpResourceDetector.cs
new file mode 100644
index 0000000000..de5d212484
--- /dev/null
+++ b/src/OpenTelemetry.Resources.Gcp/GcpResourceDetector.cs
@@ -0,0 +1,92 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using System.Collections.Generic;
+using Google.Api.Gax;
+using OpenTelemetry.Trace;
+
+namespace OpenTelemetry.Resources.Gcp;
+
+///
+/// Resource detector for Google Cloud Platform (GCP).
+///
+internal sealed class GcpResourceDetector : IResourceDetector
+{
+ ///
+ public Resource Detect()
+ {
+ var platform = Platform.Instance();
+
+ if (platform == null || platform.ProjectId == null)
+ {
+ return Resource.Empty;
+ }
+
+ var attributeList = platform.Type switch
+ {
+ PlatformType.Gke => ExtractGkeResourceAttributes(platform),
+ PlatformType.CloudRun => ExtractCloudRunResourceAttributes(platform),
+ PlatformType.Gae => ExtractGaeResourceAttributes(platform),
+ PlatformType.Gce => ExtractGceResourceAttributes(platform),
+ _ => ExtractGceResourceAttributes(platform),
+ };
+
+ return new Resource(attributeList);
+ }
+
+ internal static List> ExtractGkeResourceAttributes(Platform platform)
+ {
+ List> attributeList = new()
+ {
+ new(ResourceSemanticConventions.AttributeCloudProvider, ResourceAttributeConstants.GcpCloudProviderValue),
+ new(ResourceSemanticConventions.AttributeCloudAccount, platform.ProjectId),
+ new(ResourceSemanticConventions.AttributeCloudPlatform, ResourceAttributeConstants.GcpGkePlatformValue),
+ new(ResourceSemanticConventions.AttributeCloudZone, platform.GkeDetails.Zone),
+ new(ResourceSemanticConventions.AttributeHostId, platform.GkeDetails.InstanceId),
+ new(ResourceSemanticConventions.AttributeK8sCluster, platform.GkeDetails.ClusterName),
+ new(ResourceSemanticConventions.AttributeK8sNamespace, platform.GkeDetails.NamespaceId),
+ new(ResourceSemanticConventions.AttributeK8sPod, platform.GkeDetails.HostName),
+ };
+
+ return attributeList;
+ }
+
+ internal static List> ExtractCloudRunResourceAttributes(Platform platform)
+ {
+ List> attributeList = new()
+ {
+ new(ResourceSemanticConventions.AttributeCloudProvider, ResourceAttributeConstants.GcpCloudProviderValue),
+ new(ResourceSemanticConventions.AttributeCloudAccount, platform.ProjectId),
+ new(ResourceSemanticConventions.AttributeCloudAvailabilityZone, platform.CloudRunDetails.Zone),
+ new(ResourceSemanticConventions.AttributeCloudPlatform, ResourceAttributeConstants.GcpCloudRunPlatformValue),
+ new(ResourceSemanticConventions.AttributeCloudRegion, platform.CloudRunDetails.Region),
+ };
+
+ return attributeList;
+ }
+
+ internal static List> ExtractGaeResourceAttributes(Platform platform)
+ {
+ List> attributeList = new()
+ {
+ new(ResourceSemanticConventions.AttributeCloudProvider, ResourceAttributeConstants.GcpCloudProviderValue),
+ new(ResourceSemanticConventions.AttributeCloudAccount, platform.ProjectId),
+ new(ResourceSemanticConventions.AttributeCloudPlatform, ResourceAttributeConstants.GcpGaePlatformValue),
+ };
+ return attributeList;
+ }
+
+ internal static List> ExtractGceResourceAttributes(Platform platform)
+ {
+ List> attributeList = new()
+ {
+ new(ResourceSemanticConventions.AttributeCloudProvider, ResourceAttributeConstants.GcpCloudProviderValue),
+ new(ResourceSemanticConventions.AttributeCloudAccount, platform.ProjectId),
+ new(ResourceSemanticConventions.AttributeCloudPlatform, ResourceAttributeConstants.GcpGcePlatformValue),
+ new(ResourceSemanticConventions.AttributeHostId, platform.GceDetails.InstanceId),
+ new(ResourceSemanticConventions.AttributeCloudAvailabilityZone, platform.GceDetails.Location),
+ };
+
+ return attributeList;
+ }
+}
diff --git a/src/OpenTelemetry.Resources.Gcp/OpenTelemetry.Resources.Gcp.csproj b/src/OpenTelemetry.Resources.Gcp/OpenTelemetry.Resources.Gcp.csproj
new file mode 100644
index 0000000000..e0b3c71433
--- /dev/null
+++ b/src/OpenTelemetry.Resources.Gcp/OpenTelemetry.Resources.Gcp.csproj
@@ -0,0 +1,25 @@
+
+
+ net6.0;netstandard2.0
+ OpenTelemetry Resource Detectors for Google Cloud Platform environments
+ $(PackageTags);ResourceDetector
+ Resources.Gcp-
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/OpenTelemetry.Resources.Gcp/README.md b/src/OpenTelemetry.Resources.Gcp/README.md
new file mode 100644
index 0000000000..3171fa579c
--- /dev/null
+++ b/src/OpenTelemetry.Resources.Gcp/README.md
@@ -0,0 +1,85 @@
+# Resource Detectors for Google Cloud Platform environments
+
+[![NuGet version badge](https://img.shields.io/nuget/v/OpenTelemetry.Resources.Gcp)](https://www.nuget.org/packages/OpenTelemetry.Resources.Gcp)
+[![NuGet download count badge](https://img.shields.io/nuget/dt/OpenTelemetry.ResourceDetectors.Azure)](https://www.nuget.org/packages/OpenTelemetry.ResourceDetectors.Azure)
+
+This package contains [Resource
+Detectors](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md#detecting-resource-information-from-the-environment)
+for applications running in Google Cloud Platform environments.
+
+## Installation
+
+```shell
+dotnet add package --prerelease OpenTelemetry.Resources.Gcp
+```
+
+```csharp
+using OpenTelemetry;
+using OpenTelemetry.Resources;
+
+using var meterProvider = Sdk.CreateMeterProviderBuilder()
+ // other configurations
+ .ConfigureResource(resource => resource.AddGcpDetector())
+ .Build();
+
+using var tracerProvider = Sdk.CreateTracerProviderBuilder()
+ // other configurations
+ .ConfigureResource(resource => resource.AddGcpDetector())
+ .Build();
+
+using var loggerFactory = LoggerFactory.Create(builder =>
+{
+ builder.AddOpenTelemetry(options =>
+ {
+ options.SetResourceBuilder(ResourceBuilder
+ .CreateDefault()
+ .AddGcpDetector());
+ });
+});
+```
+
+## Resource Attributes
+
+The following OpenTelemetry semantic conventions will be detected depending on
+which Google Cloud Platform environment an application is running in.
+
+### Google Kubernetes Engine
+
+|-------------------------|-----------------------|
+| Attribute | Value |
+| cloud.provider | gcp |
+| cloud.platform | gcp_kubernetes_engine |
+| cloud.account.id | auto |
+| cloud.availability_zone | auto |
+| host.id | auto |
+| k8s.cluster.name | auto |
+| k8s.namespace.name | auto |
+| k8s.pod.name | auto |
+
+### Google App Engine
+
+|-------------------------|----------------|
+| Attribute | Value |
+| cloud.provider | gcp |
+| cloud.platform | gcp_app_engine |
+| cloud.account.id | auto |
+
+### Google Cloud Run
+
+|-------------------------|---------------|
+| Attribute | Value |
+| cloud.provider | gcp |
+| cloud.platform | gcp_cloud_run |
+| cloud.account.id | auto |
+| cloud.availability_zone | auto |
+| cloud.region | auto |
+
+### Google Compute Engine
+
+|-------------------------|--------------------|
+| Attribute | Value |
+| cloud.provider | gcp |
+| cloud.platform | gcp_compute_engine |
+| cloud.account.id | auto |
+| cloud.availability_zone | auto |
+| host.id | auto |
diff --git a/src/OpenTelemetry.Resources.Gcp/ResourceAttributeConstants.cs b/src/OpenTelemetry.Resources.Gcp/ResourceAttributeConstants.cs
new file mode 100644
index 0000000000..6c9a0b8c36
--- /dev/null
+++ b/src/OpenTelemetry.Resources.Gcp/ResourceAttributeConstants.cs
@@ -0,0 +1,14 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+namespace OpenTelemetry.Resources.Gcp;
+
+internal sealed class ResourceAttributeConstants
+{
+ // GCP resource attributes constant values
+ internal const string GcpCloudProviderValue = "gcp";
+ internal const string GcpGcePlatformValue = "gcp_compute_engine";
+ internal const string GcpGaePlatformValue = "gcp_app_engine";
+ internal const string GcpCloudRunPlatformValue = "gcp_cloud_run";
+ internal const string GcpGkePlatformValue = "gcp_kubernetes_engine";
+}
diff --git a/src/Shared/ResourceSemanticConventions.cs b/src/Shared/ResourceSemanticConventions.cs
index 4b4aa6a9ea..22903d04bc 100644
--- a/src/Shared/ResourceSemanticConventions.cs
+++ b/src/Shared/ResourceSemanticConventions.cs
@@ -44,6 +44,7 @@ internal static class ResourceSemanticConventions
public const string AttributeProcessUsername = "process.username";
public const string AttributeCloudAccount = "cloud.account.id";
+ public const string AttributeCloudAvailabilityZone = "cloud.availability_zone";
public const string AttributeCloudPlatform = "cloud.platform";
public const string AttributeCloudProvider = "cloud.provider";
public const string AttributeCloudRegion = "cloud.region";
diff --git a/test/OpenTelemetry.Resources.Gcp.Tests/GcpResourceDetectorTests.cs b/test/OpenTelemetry.Resources.Gcp.Tests/GcpResourceDetectorTests.cs
new file mode 100644
index 0000000000..6369d7fda2
--- /dev/null
+++ b/test/OpenTelemetry.Resources.Gcp.Tests/GcpResourceDetectorTests.cs
@@ -0,0 +1,96 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+using System.Linq;
+using Google.Api.Gax;
+using OpenTelemetry.Trace;
+
+namespace OpenTelemetry.Resources.Gcp.Tests;
+
+public class GcpResourceDetectorTests
+{
+ [Fact]
+ public void TestExtractGkeResourceAttributes()
+ {
+ var details = new GkePlatformDetails(
+ metadataJson: "json",
+ projectId: "projectId",
+ clusterName: "clusterName",
+ location: "location",
+ hostName: "hostName",
+ instanceId: "instanceId",
+ zone: "us-central1-a",
+ namespaceId: "namespaceId",
+ podId: "podId",
+ containerName: "containerName",
+ clusterLocation: "clusterLocation");
+ var platform = new Platform(details);
+ var attrs = GcpResourceDetector.ExtractGkeResourceAttributes(platform).ToDictionary(x => x.Key, x => x.Value);
+ Assert.NotNull(attrs);
+ Assert.Equal(8, attrs.Count);
+ Assert.Equal(ResourceAttributeConstants.GcpCloudProviderValue, attrs[ResourceSemanticConventions.AttributeCloudProvider]);
+ Assert.Equal("projectId", attrs[ResourceSemanticConventions.AttributeCloudAccount]);
+ Assert.Equal(ResourceAttributeConstants.GcpGkePlatformValue, attrs[ResourceSemanticConventions.AttributeCloudPlatform]);
+ Assert.Equal("us-central1-a", attrs[ResourceSemanticConventions.AttributeCloudZone]);
+ Assert.Equal("instanceId", attrs[ResourceSemanticConventions.AttributeHostId]);
+ Assert.Equal("clusterName", attrs[ResourceSemanticConventions.AttributeK8sCluster]);
+ Assert.Equal("namespaceId", attrs[ResourceSemanticConventions.AttributeK8sNamespace]);
+ Assert.Equal("hostName", attrs[ResourceSemanticConventions.AttributeK8sPod]);
+ }
+
+ [Fact]
+ public void TestExtractCloudRunResourceAttributes()
+ {
+ var details = new CloudRunPlatformDetails(
+ metadataJson: "json",
+ projectId: "projectId",
+ zone: "us-central1-a",
+ serviceName: "serviceName",
+ revisionName: "revisionName",
+ configurationName: "configurationName");
+ var platform = new Platform(details);
+ var attrs = GcpResourceDetector.ExtractCloudRunResourceAttributes(platform).ToDictionary(x => x.Key, x => x.Value);
+ Assert.NotNull(attrs);
+ Assert.Equal(5, attrs.Count);
+ Assert.Equal(ResourceAttributeConstants.GcpCloudProviderValue, attrs[ResourceSemanticConventions.AttributeCloudProvider]);
+ Assert.Equal("projectId", attrs[ResourceSemanticConventions.AttributeCloudAccount]);
+ Assert.Equal("us-central1-a", attrs[ResourceSemanticConventions.AttributeCloudAvailabilityZone]);
+ Assert.Equal(ResourceAttributeConstants.GcpCloudRunPlatformValue, attrs[ResourceSemanticConventions.AttributeCloudPlatform]);
+ Assert.Equal("us-central1", attrs[ResourceSemanticConventions.AttributeCloudRegion]);
+ }
+
+ [Fact]
+ public void TestExtractGaeResourceAttributes()
+ {
+ var details = new GaePlatformDetails(
+ gcloudProject: "gcloudProject",
+ gaeInstance: "gaeInstance",
+ gaeService: "gaeService",
+ gaeVersion: "gaeVersion");
+ var platform = new Platform(details);
+ var attrs = GcpResourceDetector.ExtractGaeResourceAttributes(platform).ToDictionary(x => x.Key, x => x.Value);
+ Assert.NotNull(attrs);
+ Assert.Equal(3, attrs.Count);
+ Assert.Equal(ResourceAttributeConstants.GcpCloudProviderValue, attrs[ResourceSemanticConventions.AttributeCloudProvider]);
+ Assert.Equal("gcloudProject", attrs[ResourceSemanticConventions.AttributeCloudAccount]);
+ Assert.Equal(ResourceAttributeConstants.GcpGaePlatformValue, attrs[ResourceSemanticConventions.AttributeCloudPlatform]);
+ }
+
+ [Fact]
+ public void TestExtractGceResourceAttributes()
+ {
+ var details = new GcePlatformDetails(
+ metadataJson: "json",
+ projectId: "projectId",
+ instanceId: "instanceId",
+ zoneName: "projects/12345/zones/us-central1-a");
+ var platform = new Platform(details);
+ var attrs = GcpResourceDetector.ExtractGceResourceAttributes(platform).ToDictionary(x => x.Key, x => x.Value);
+ Assert.NotNull(attrs);
+ Assert.Equal(5, attrs.Count);
+ Assert.Equal(ResourceAttributeConstants.GcpCloudProviderValue, attrs[ResourceSemanticConventions.AttributeCloudProvider]);
+ Assert.Equal("projectId", attrs[ResourceSemanticConventions.AttributeCloudAccount]);
+ Assert.Equal(ResourceAttributeConstants.GcpGcePlatformValue, attrs[ResourceSemanticConventions.AttributeCloudPlatform]);
+ Assert.Equal("instanceId", attrs[ResourceSemanticConventions.AttributeHostId]);
+ }
+}
diff --git a/test/OpenTelemetry.Resources.Gcp.Tests/GlobalUsings.cs b/test/OpenTelemetry.Resources.Gcp.Tests/GlobalUsings.cs
new file mode 100644
index 0000000000..c9112be5f0
--- /dev/null
+++ b/test/OpenTelemetry.Resources.Gcp.Tests/GlobalUsings.cs
@@ -0,0 +1,4 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+global using Xunit;
diff --git a/test/OpenTelemetry.Resources.Gcp.Tests/OpenTelemetry.Resources.Gcp.Tests.csproj b/test/OpenTelemetry.Resources.Gcp.Tests/OpenTelemetry.Resources.Gcp.Tests.csproj
new file mode 100644
index 0000000000..e1df281415
--- /dev/null
+++ b/test/OpenTelemetry.Resources.Gcp.Tests/OpenTelemetry.Resources.Gcp.Tests.csproj
@@ -0,0 +1,18 @@
+
+
+
+ Unit test project for GCP Detector for OpenTelemetry
+
+ $(SupportedNetTargets)
+ $(TargetFrameworks);$(NetFrameworkMinimumSupportedVersion)
+
+
+
+
+
+
+
+
+
+
+