diff --git a/instrumentation/resources/library/build.gradle.kts b/instrumentation/resources/library/build.gradle.kts index 931468c7d94c..bb41a8b31dd9 100644 --- a/instrumentation/resources/library/build.gradle.kts +++ b/instrumentation/resources/library/build.gradle.kts @@ -8,6 +8,7 @@ dependencies { compileOnly("io.opentelemetry:opentelemetry-api-incubator") implementation("io.opentelemetry:opentelemetry-sdk-common") implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi") + compileOnly("io.opentelemetry:opentelemetry-sdk-extension-incubator") implementation("io.opentelemetry.semconv:opentelemetry-semconv") annotationProcessor("com.google.auto.service:auto-service") diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/AttributeResourceProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/AttributeResourceProvider.java index 594b69cad2cb..82dce4684e08 100644 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/AttributeResourceProvider.java +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/AttributeResourceProvider.java @@ -20,6 +20,7 @@ import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import javax.annotation.Nullable; /** * An easier alternative to {@link io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider}, which @@ -45,7 +46,6 @@ public AttributeBuilder add(AttributeKey key, Function> ge } private Set> filteredKeys; - private final Map, Function>> attributeGetters = new HashMap<>(); @@ -66,16 +66,25 @@ public final boolean shouldApply(ConfigProperties config, Resource existing) { @Override public final Resource createResource(ConfigProperties config) { + return create(filteredKeys); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + protected final Resource createUnconditional() { + return create((Set) attributeGetters.keySet()); + } + + private Resource create(@Nullable Set> keys) { + if (keys == null) { + throw new IllegalStateException("shouldApply should be called first"); + } return attributeProvider .readData() .map( data -> { - if (filteredKeys == null) { - throw new IllegalStateException("shouldApply should be called first"); - } AttributesBuilder builder = Attributes.builder(); attributeGetters.entrySet().stream() - .filter(e -> filteredKeys.contains(e.getKey())) + .filter(e -> keys.contains(e.getKey())) .forEach( e -> e.getValue() diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/JarServiceNameDetector.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/JarServiceNameDetector.java index 7ffaeaa2d170..89fdb28b8085 100644 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/JarServiceNameDetector.java +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/JarServiceNameDetector.java @@ -9,6 +9,7 @@ import com.google.auto.service.AutoService; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider; import io.opentelemetry.sdk.autoconfigure.spi.internal.ConditionalResourceProvider; @@ -46,6 +47,15 @@ private JarServiceNameDetector(Supplier> jarPathSupplier) { @Override public Resource createResource(ConfigProperties config) { + return create(); + } + + @SuppressWarnings("unused") + public Resource createResource(DeclarativeConfigProperties config) { + return create(); + } + + private Resource create() { return jarPathSupplier .get() .map( diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/ManifestResourceProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/ManifestResourceProvider.java index c5cb94af8de6..80fbedd5ce9b 100644 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/ManifestResourceProvider.java +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/ManifestResourceProvider.java @@ -8,7 +8,9 @@ import static java.util.logging.Level.WARNING; import com.google.auto.service.AutoService; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider; +import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.semconv.ServiceAttributes; import java.io.IOException; import java.nio.file.Path; @@ -69,6 +71,11 @@ public void registerAttributes(Builder builder) { this(() -> Optional.ofNullable(jarPathFinder.detectJarPath()), manifestReader); } + @SuppressWarnings("unused") + public Resource createResource(DeclarativeConfigProperties config) { + return createUnconditional(); + } + private static Optional readManifest(Path jarPath) { try (JarFile jarFile = new JarFile(jarPath.toFile(), false)) { return Optional.of(jarFile.getManifest()); diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ContainerResourceComponentProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ContainerResourceComponentProvider.java index 426f3c2ec9b4..141e4bd91386 100644 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ContainerResourceComponentProvider.java +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ContainerResourceComponentProvider.java @@ -19,6 +19,6 @@ @AutoService(ComponentProvider.class) public class ContainerResourceComponentProvider extends ResourceComponentProvider { public ContainerResourceComponentProvider() { - super("container", ContainerResource::get); + super("container", p -> ContainerResource.get()); } } diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/HostResourceComponentProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/HostResourceComponentProvider.java index dd0b0f519cfd..a65382557539 100644 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/HostResourceComponentProvider.java +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/HostResourceComponentProvider.java @@ -21,6 +21,6 @@ @AutoService(ComponentProvider.class) public class HostResourceComponentProvider extends ResourceComponentProvider { public HostResourceComponentProvider() { - super("host", () -> HostResource.get().merge(HostIdResource.get()).merge(OsResource.get())); + super("host", p -> HostResource.get().merge(HostIdResource.get()).merge(OsResource.get())); } } diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/JarResourceComponentProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/JarResourceComponentProvider.java new file mode 100644 index 000000000000..8c6f766046d8 --- /dev/null +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/JarResourceComponentProvider.java @@ -0,0 +1,24 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.resources.internal; + +import com.google.auto.service.AutoService; +import io.opentelemetry.instrumentation.resources.JarServiceNameDetector; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; + +/** + * Declarative config jar resource provider. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +@SuppressWarnings("rawtypes") +@AutoService(ComponentProvider.class) +public class JarResourceComponentProvider extends ResourceComponentProvider { + public JarResourceComponentProvider() { + super("jar", p -> new JarServiceNameDetector().createResource(p)); + } +} diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceComponentProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceComponentProvider.java new file mode 100644 index 000000000000..091f7219163b --- /dev/null +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceComponentProvider.java @@ -0,0 +1,24 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.resources.internal; + +import com.google.auto.service.AutoService; +import io.opentelemetry.instrumentation.resources.ManifestResourceProvider; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; + +/** + * Declarative config manifest resource provider. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +@SuppressWarnings("rawtypes") +@AutoService(ComponentProvider.class) +public class ManifestResourceComponentProvider extends ResourceComponentProvider { + public ManifestResourceComponentProvider() { + super("manifest", p -> new ManifestResourceProvider().createResource(p)); + } +} diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessResourceComponentProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessResourceComponentProvider.java index cbdb53ad2c6f..13d26c85503b 100644 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessResourceComponentProvider.java +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessResourceComponentProvider.java @@ -20,6 +20,6 @@ @AutoService(ComponentProvider.class) public class ProcessResourceComponentProvider extends ResourceComponentProvider { public ProcessResourceComponentProvider() { - super("process", () -> ProcessResource.get().merge(ProcessRuntimeResource.get())); + super("process", p -> ProcessResource.get().merge(ProcessRuntimeResource.get())); } } diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ResourceComponentProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ResourceComponentProvider.java index 04508560f883..841839ccd03f 100644 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ResourceComponentProvider.java +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ResourceComponentProvider.java @@ -8,15 +8,15 @@ import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; import io.opentelemetry.sdk.resources.Resource; -import java.util.function.Supplier; +import java.util.function.Function; /** Abstract class to simply {@link Resource} {@link ComponentProvider} implementations. */ abstract class ResourceComponentProvider implements ComponentProvider { private final String name; - private final Supplier supplier; + private final Function supplier; - ResourceComponentProvider(String name, Supplier supplier) { + ResourceComponentProvider(String name, Function supplier) { this.name = name; this.supplier = supplier; } @@ -33,6 +33,6 @@ public String getName() { @Override public Resource create(DeclarativeConfigProperties declarativeConfigProperties) { - return supplier.get(); + return supplier.apply(declarativeConfigProperties); } } diff --git a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/ManifestResourceProviderTest.java b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/ManifestResourceProviderTest.java index 2986337d892a..d6c088b9c7df 100644 --- a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/ManifestResourceProviderTest.java +++ b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/ManifestResourceProviderTest.java @@ -96,6 +96,12 @@ Collection createResource() { assertThat(resource.getAttribute(SERVICE_NAME)).isEqualTo(t.expectedName); assertThat(resource.getAttribute(SERVICE_VERSION)) .isEqualTo(t.expectedVersion); + + if (t.existing.getAttributes().isEmpty()) { + // component provider does not consider existing resource + assertThat(provider.createUnconditional().getAttributes()) + .isEqualTo(resource.getAttributes()); + } })) .collect(Collectors.toList()); } diff --git a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/DeclarativeConfigTest.java b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ResourceDeclarativeConfigTest.java similarity index 98% rename from instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/DeclarativeConfigTest.java rename to instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ResourceDeclarativeConfigTest.java index 870c4ec72a52..15472bcb9bba 100644 --- a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/DeclarativeConfigTest.java +++ b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ResourceDeclarativeConfigTest.java @@ -22,7 +22,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -class DeclarativeConfigTest { +class ResourceDeclarativeConfigTest { // just to ensure that the test exporters are registered @RegisterExtension diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/SpringConfigPropertiesTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/SpringConfigPropertiesTest.java index 9754ccb3b7ad..02433342b1ab 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/SpringConfigPropertiesTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/SpringConfigPropertiesTest.java @@ -105,7 +105,6 @@ void mapObjectHeaders(String key) { public static Stream listProperties() { return Stream.of( - Arguments.of("otel.experimental.metrics.view.config", Arrays.asList("a", "b")), Arguments.of("otel.experimental.resource.disabled.keys", Arrays.asList("a", "b")), Arguments.of("otel.propagators", Arrays.asList("baggage", "b3")), Arguments.of("otel.logs.exporter", Collections.singletonList("console")), diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/resources/application.yaml b/instrumentation/spring/spring-boot-autoconfigure/src/test/resources/application.yaml index c9485005a6a7..bfbad4f868be 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/resources/application.yaml +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/resources/application.yaml @@ -1,8 +1,5 @@ otel: experimental: - metrics: - view: - config: [ a,b ] resource: disabled: keys: [ a,b ] diff --git a/instrumentation/spring/spring-boot-resources/javaagent/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceNameDetector.java b/instrumentation/spring/spring-boot-resources/javaagent/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceNameDetector.java index 0bcdb527095a..18a8f23cf338 100644 --- a/instrumentation/spring/spring-boot-resources/javaagent/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceNameDetector.java +++ b/instrumentation/spring/spring-boot-resources/javaagent/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceNameDetector.java @@ -71,7 +71,10 @@ public SpringBootServiceNameDetector() { @Override public Resource createResource(ConfigProperties config) { + return create(); + } + Resource create() { logger.log(FINER, "Performing Spring Boot service name auto-detection..."); // Note: The order should be consistent with the order of Spring matching, but noting // that we have "first one wins" while Spring has "last one wins". diff --git a/instrumentation/spring/spring-boot-resources/javaagent/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceVersionDetector.java b/instrumentation/spring/spring-boot-resources/javaagent/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceVersionDetector.java index 865279de3064..ba68d6bca0ea 100644 --- a/instrumentation/spring/spring-boot-resources/javaagent/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceVersionDetector.java +++ b/instrumentation/spring/spring-boot-resources/javaagent/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringBootServiceVersionDetector.java @@ -41,6 +41,10 @@ public SpringBootServiceVersionDetector() { @Override public Resource createResource(ConfigProperties config) { + return create(); + } + + Resource create() { return getServiceVersionFromBuildInfo() .map( version -> { diff --git a/instrumentation/spring/spring-boot-resources/javaagent/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringResourceComponentProvider.java b/instrumentation/spring/spring-boot-resources/javaagent/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringResourceComponentProvider.java new file mode 100644 index 000000000000..7c1ef57a8317 --- /dev/null +++ b/instrumentation/spring/spring-boot-resources/javaagent/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringResourceComponentProvider.java @@ -0,0 +1,39 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.resources; + +import com.google.auto.service.AutoService; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.resources.Resource; + +/** + * Declarative config spring resource provider. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +@SuppressWarnings("rawtypes") +@AutoService(ComponentProvider.class) +public class SpringResourceComponentProvider implements ComponentProvider { + + @Override + public Class getType() { + return Resource.class; + } + + @Override + public String getName() { + return "spring"; + } + + @Override + public Resource create(DeclarativeConfigProperties config) { + return new SpringBootServiceVersionDetector() + .create() + .merge(new SpringBootServiceNameDetector().create()); + } +} diff --git a/javaagent-tooling/build.gradle.kts b/javaagent-tooling/build.gradle.kts index c44a7c4c0a65..a449ec529f9d 100644 --- a/javaagent-tooling/build.gradle.kts +++ b/javaagent-tooling/build.gradle.kts @@ -61,6 +61,7 @@ dependencies { testImplementation(project(":testing-common")) testImplementation("com.google.guava:guava") testImplementation("org.junit-pioneer:junit-pioneer") + testImplementation("com.fasterxml.jackson.core:jackson-databind") } testing { diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/DistroComponentProvider.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/DistroComponentProvider.java new file mode 100644 index 000000000000..e9a2d614d404 --- /dev/null +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/DistroComponentProvider.java @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.tooling.resources; + +import com.google.auto.service.AutoService; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.resources.Resource; + +@SuppressWarnings("rawtypes") +@AutoService(ComponentProvider.class) +public class DistroComponentProvider implements ComponentProvider { + + @Override + public Class getType() { + return Resource.class; + } + + @Override + public String getName() { + return "distribution"; + } + + @Override + public Resource create(DeclarativeConfigProperties config) { + return DistroResourceProvider.get(); + } +} diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroVersionResourceProvider.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/DistroResourceProvider.java similarity index 81% rename from javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroVersionResourceProvider.java rename to javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/DistroResourceProvider.java index 53fe1d65a5d1..b2c76e33dacb 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroVersionResourceProvider.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/DistroResourceProvider.java @@ -3,22 +3,27 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.tooling; +package io.opentelemetry.javaagent.tooling.resources; import static io.opentelemetry.semconv.incubating.TelemetryIncubatingAttributes.TELEMETRY_DISTRO_NAME; import static io.opentelemetry.semconv.incubating.TelemetryIncubatingAttributes.TELEMETRY_DISTRO_VERSION; import com.google.auto.service.AutoService; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.javaagent.tooling.AgentVersion; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider; import io.opentelemetry.sdk.resources.Resource; @AutoService(ResourceProvider.class) -public class DistroVersionResourceProvider implements ResourceProvider { +public class DistroResourceProvider implements ResourceProvider { @Override public Resource createResource(ConfigProperties config) { + return get(); + } + + static Resource get() { return AgentVersion.VERSION == null ? Resource.empty() : Resource.create( diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/ResourceCustomizerProvider.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/ResourceCustomizerProvider.java new file mode 100644 index 000000000000..3b7967619f0d --- /dev/null +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/ResourceCustomizerProvider.java @@ -0,0 +1,67 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.tooling.resources; + +import com.google.auto.service.AutoService; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectionModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ResourceModel; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Adds essential resource detectors to the resource model in declarative configuration, if they are + * not already present. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +@AutoService(DeclarativeConfigurationCustomizerProvider.class) +public class ResourceCustomizerProvider implements DeclarativeConfigurationCustomizerProvider { + + // distribution: adds "distro.name" and "distro.version" attributes + // (DistroComponentProvider in this package) + // service: adds "service.name" and "service.instance.id" attributes + // (https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetector.java) + private static final List REQUIRED_DETECTORS = Arrays.asList("distribution", "service"); + + @Override + public void customize(DeclarativeConfigurationCustomizer customizer) { + customizer.addModelCustomizer( + model -> { + ResourceModel resource = model.getResource(); + if (resource == null) { + resource = new ResourceModel(); + model.withResource(resource); + } + ExperimentalResourceDetectionModel detectionModel = resource.getDetectionDevelopment(); + if (detectionModel == null) { + detectionModel = new ExperimentalResourceDetectionModel(); + resource.withDetectionDevelopment(detectionModel); + } + List detectors = + Objects.requireNonNull(detectionModel.getDetectors()); + Set names = + detectors.stream() + .flatMap(detector -> detector.getAdditionalProperties().keySet().stream()) + .collect(Collectors.toSet()); + + for (String name : REQUIRED_DETECTORS) { + if (!names.contains(name)) { + ExperimentalResourceDetectorModel detector = new ExperimentalResourceDetectorModel(); + detector.getAdditionalProperties().put(name, null); + detectors.add(detector); + } + } + return model; + }); + } +} diff --git a/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/resources/ResourceCustomizerProviderTest.java b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/resources/ResourceCustomizerProviderTest.java new file mode 100644 index 000000000000..9c4bbe24c94f --- /dev/null +++ b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/resources/ResourceCustomizerProviderTest.java @@ -0,0 +1,36 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.tooling.resources; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; +import org.junit.jupiter.api.Test; + +class ResourceCustomizerProviderTest { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void customize() { + new ResourceCustomizerProvider() + .customize( + customizer -> { + OpenTelemetryConfigurationModel configurationModel = + customizer.apply(new OpenTelemetryConfigurationModel()); + + try { + assertThat(objectMapper.writeValueAsString(configurationModel.getResource())) + .isEqualTo( + "{\"attributes\":[],\"detection/development\":{\"detectors\":[{\"distribution\":null},{\"service\":null}]}}"); + } catch (JsonProcessingException e) { + throw new AssertionError(e); + } + }); + } +}