Skip to content

Declarative config: Cloud component providers #2014

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jul 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions aws-resources/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ otelJava.moduleName.set("io.opentelemetry.contrib.aws.resource")

dependencies {
api("io.opentelemetry:opentelemetry-api")
compileOnly("io.opentelemetry:opentelemetry-api-incubator")
api("io.opentelemetry:opentelemetry-sdk")

implementation("io.opentelemetry.semconv:opentelemetry-semconv")
Expand All @@ -20,6 +21,7 @@ dependencies {
implementation("com.squareup.okhttp3:okhttp")

testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
testImplementation("io.opentelemetry:opentelemetry-api-incubator")
testImplementation("io.opentelemetry:opentelemetry-sdk-testing")

testImplementation("com.linecorp.armeria:armeria-junit5")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.contrib.aws.resource.internal;

import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.contrib.aws.resource.BeanstalkResource;
import io.opentelemetry.contrib.aws.resource.Ec2Resource;
import io.opentelemetry.contrib.aws.resource.EcsResource;
import io.opentelemetry.contrib.aws.resource.EksResource;
import io.opentelemetry.contrib.aws.resource.LambdaResource;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.resources.ResourceBuilder;

public class AwsResourceDetector implements ComponentProvider<Resource> {

@Override
public Class<Resource> getType() {
return Resource.class;
}

@Override
public String getName() {
return "aws";
}

@Override
public Resource create(DeclarativeConfigProperties config) {
ResourceBuilder builder = Resource.builder();
builder.putAll(BeanstalkResource.get());
builder.putAll(Ec2Resource.get());
builder.putAll(EcsResource.get());
builder.putAll(EksResource.get());
builder.putAll(LambdaResource.get());
return builder.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
io.opentelemetry.contrib.aws.resource.internal.AwsResourceDetector
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.contrib.aws.resource;

import static org.assertj.core.api.Assertions.assertThat;

import io.opentelemetry.common.ComponentLoader;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import org.junit.jupiter.api.Test;

class ResourceComponentProviderTest {

@Test
@SuppressWarnings("rawtypes")
void providerIsLoaded() {
Iterable<ComponentProvider> providers =
ComponentLoader.forClassLoader(ResourceComponentProviderTest.class.getClassLoader())
.load(ComponentProvider.class);
assertThat(providers).extracting(ComponentProvider::getName).containsExactly("aws");
}
}
2 changes: 2 additions & 0 deletions azure-resources/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ java {

dependencies {
api("io.opentelemetry:opentelemetry-api")
compileOnly("io.opentelemetry:opentelemetry-api-incubator")
api("io.opentelemetry:opentelemetry-sdk")

implementation("io.opentelemetry.semconv:opentelemetry-semconv")
Expand All @@ -26,6 +27,7 @@ dependencies {

testImplementation("io.opentelemetry.semconv:opentelemetry-semconv-incubating")
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
testImplementation("io.opentelemetry:opentelemetry-api-incubator")
testImplementation("io.opentelemetry:opentelemetry-sdk-testing")

// testImplementation("org.mockito:mockito-core")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.CloudPlatformIncubatingValues.AZURE_AKS;
import static io.opentelemetry.contrib.azure.resource.IncubatingAttributes.K8S_CLUSTER_NAME;

import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.resources.Resource;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -56,12 +55,12 @@ public AzureAksResourceProvider() {
@Override
public int order() {
// run after the fast cloud resource providers that only check environment variables
// and before the AKS provider
// and before the VM provider
return 100;
}

@Override
public Resource createResource(ConfigProperties configProperties) {
public Resource createResource() {
if (environment.get(KUBERNETES_SERVICE_HOST) == null) {
return Resource.empty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.api.internal.StringUtils;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.resources.Resource;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -60,7 +59,7 @@ public AzureAppServiceResourceProvider() {
}

@Override
public Resource createResource(ConfigProperties config) {
public Resource createResource() {
return Resource.create(getAttributes());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.resources.Resource;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -45,7 +44,7 @@ public AzureContainersResourceProvider() {
}

@Override
public Resource createResource(ConfigProperties config) {
public Resource createResource() {
return Resource.create(getAttributes());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.resources.Resource;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -47,7 +46,7 @@ public AzureFunctionsResourceProvider() {
}

@Override
public Resource createResource(ConfigProperties config) {
public Resource createResource() {
return Resource.create(getAttributes());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.contrib.azure.resource;

import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.resources.ResourceBuilder;

public class AzureResourceDetector implements ComponentProvider<Resource> {

@Override
public Class<Resource> getType() {
return Resource.class;
}

@Override
public String getName() {
return "azure";
}

@Override
public Resource create(DeclarativeConfigProperties config) {
Builder builder = new Builder();
builder.add(new AzureFunctionsResourceProvider());
builder.add(new AzureAppServiceResourceProvider());
builder.add(new AzureContainersResourceProvider());
builder.addIfEmpty(new AzureAksResourceProvider());
builder.addIfEmpty(new AzureVmResourceProvider());
return builder.builder.build();
}

private static class Builder {
final ResourceBuilder builder = Resource.builder();
int attributesCount = 0;

private void add(CloudResourceProvider provider) {
Attributes attributes = provider.createResource().getAttributes();
builder.putAll(attributes);
attributesCount += attributes.size();
}

private void addIfEmpty(CloudResourceProvider provider) {
if (attributesCount == 0) {
add(provider);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.resources.Resource;
import java.io.IOException;
import java.util.HashMap;
Expand Down Expand Up @@ -88,7 +87,7 @@ public int order() {
}

@Override
public Resource createResource(ConfigProperties config) {
public Resource createResource() {
return client
.get()
.map(body -> parseMetadata(body, COMPUTE_MAPPING, AZURE_VM))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,12 @@ public abstract class CloudResourceProvider implements ConditionalResourceProvid
public final boolean shouldApply(ConfigProperties config, Resource existing) {
return existing.getAttribute(CLOUD_PROVIDER) == null;
}

@Override
public final Resource createResource(ConfigProperties config) {
// not using config in any providers
return createResource();
}

abstract Resource createResource();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
io.opentelemetry.contrib.azure.resource.AzureResourceDetector
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.contrib.azure.resource;

import static org.assertj.core.api.Assertions.assertThat;

import io.opentelemetry.common.ComponentLoader;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import org.junit.jupiter.api.Test;

class ResourceComponentProviderTest {

@Test
@SuppressWarnings("rawtypes")
void providerIsLoaded() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there's any good way to do an end-to-end style test for these resource detectors like I did here: https://github.com/open-telemetry/opentelemetry-java-contrib/blob/main/samplers/src/test/java/internal/RuleBasedRoutingSamplerComponentProviderTest.java#L39

I.e.:

  • Have a chunk of yaml that uses the azure resource detector like users would
  • Call the SDK methods to parse the YAML and create SDK components from it
  • Assert that the resource contains expected attributes

This has the benefit of being able to act as a form of documentation for users.

The assertions may be difficult though because OpenTelemetrySdk doesn't make it easy to access the resource.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great idea - I'll create a follow-up PR for this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created #2047

Iterable<ComponentProvider> providers =
ComponentLoader.forClassLoader(ResourceComponentProviderTest.class.getClassLoader())
.load(ComponentProvider.class);
assertThat(providers).extracting(ComponentProvider::getName).containsExactly("azure");
}
}
2 changes: 2 additions & 0 deletions cloudfoundry-resources/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ otelJava.moduleName.set("io.opentelemetry.contrib.cloudfoundry.resources")

dependencies {
api("io.opentelemetry:opentelemetry-api")
compileOnly("io.opentelemetry:opentelemetry-api-incubator")
api("io.opentelemetry:opentelemetry-sdk")
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")

Expand All @@ -19,6 +20,7 @@ dependencies {
testImplementation("io.opentelemetry.semconv:opentelemetry-semconv-incubating")

testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
testImplementation("io.opentelemetry:opentelemetry-api-incubator")
testImplementation("io.opentelemetry:opentelemetry-sdk-testing")
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.contrib.cloudfoundry.resources;

import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import io.opentelemetry.sdk.resources.Resource;

public class CloudFoundryResourceDetector implements ComponentProvider<Resource> {

@Override
public Class<Resource> getType() {
return Resource.class;
}

@Override
public String getName() {
return "cloud_foundry";
}

@Override
public Resource create(DeclarativeConfigProperties config) {
return CloudFoundryResource.get();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
io.opentelemetry.contrib.cloudfoundry.resources.CloudFoundryResourceDetector
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.contrib.cloudfoundry.resources;

import static org.assertj.core.api.Assertions.assertThat;

import io.opentelemetry.common.ComponentLoader;
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
import org.junit.jupiter.api.Test;

class ResourceComponentProviderTest {

@Test
@SuppressWarnings("rawtypes")
void providerIsLoaded() {
Iterable<ComponentProvider> providers =
ComponentLoader.forClassLoader(ResourceComponentProviderTest.class.getClassLoader())
.load(ComponentProvider.class);
assertThat(providers).extracting(ComponentProvider::getName).containsExactly("cloud_foundry");
}
}
2 changes: 2 additions & 0 deletions gcp-resources/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ otelJava.moduleName.set("io.opentelemetry.contrib.gcp.resource")

dependencies {
api("io.opentelemetry:opentelemetry-api")
compileOnly("io.opentelemetry:opentelemetry-api-incubator")
api("io.opentelemetry:opentelemetry-sdk")

// Provides GCP resource detection support
Expand All @@ -21,6 +22,7 @@ dependencies {
implementation("com.fasterxml.jackson.core:jackson-core")

testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
testImplementation("io.opentelemetry:opentelemetry-api-incubator")
testImplementation("io.opentelemetry:opentelemetry-sdk-testing")

testImplementation("org.mockito:mockito-core")
Expand Down
Loading
Loading