From cf9d2503006a72c9805365489e43c64a243e4442 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 10 Jul 2025 16:29:35 +0200 Subject: [PATCH 01/29] add missing declarative config resource providers --- .../resources/library/build.gradle.kts | 2 +- .../resources/AttributeResourceProvider.java | 19 ++++-- .../resources/JarServiceNameDetector.java | 4 ++ .../JarResourceComponentProvider.java | 24 +++++++ .../ManifestResourceComponentProvider.java | 24 +++++++ .../internal/ResourceCustomizerProvider.java | 63 +++++++++++++++++++ .../ManifestResourceProviderTest.java | 6 ++ .../ResourceCustomizerProviderTest.java | 39 ++++++++++++ .../SpringBootServiceNameDetector.java | 3 + .../SpringBootServiceVersionDetector.java | 4 ++ .../SpringResourceComponentProvider.java | 39 ++++++++++++ .../tooling/DistroComponentProvider.java | 30 +++++++++ ...vider.java => DistroResourceProvider.java} | 6 +- 13 files changed, 256 insertions(+), 7 deletions(-) create mode 100644 instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/JarResourceComponentProvider.java create mode 100644 instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceComponentProvider.java create mode 100644 instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ResourceCustomizerProvider.java create mode 100644 instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ResourceCustomizerProviderTest.java create mode 100644 instrumentation/spring/spring-boot-resources/javaagent/src/main/java/io/opentelemetry/instrumentation/spring/resources/SpringResourceComponentProvider.java create mode 100644 javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroComponentProvider.java rename javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/{DistroVersionResourceProvider.java => DistroResourceProvider.java} (89%) diff --git a/instrumentation/resources/library/build.gradle.kts b/instrumentation/resources/library/build.gradle.kts index 931468c7d94c..003b33a17f96 100644 --- a/instrumentation/resources/library/build.gradle.kts +++ b/instrumentation/resources/library/build.gradle.kts @@ -8,12 +8,12 @@ dependencies { compileOnly("io.opentelemetry:opentelemetry-api-incubator") implementation("io.opentelemetry:opentelemetry-sdk-common") implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi") + implementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") implementation("io.opentelemetry.semconv:opentelemetry-semconv") annotationProcessor("com.google.auto.service:auto-service") compileOnly("com.google.auto.service:auto-service-annotations") testCompileOnly("com.google.auto.service:auto-service-annotations") - testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") testImplementation("org.junit.jupiter:junit-jupiter-api") } 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..d4fc9bd1d4be 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"}) + public 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..a706d665d86b 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 @@ -46,6 +46,10 @@ private JarServiceNameDetector(Supplier> jarPathSupplier) { @Override public Resource createResource(ConfigProperties config) { + return create(); + } + + public Resource create() { return jarPathSupplier .get() .map( 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..b43a4a3d6424 --- /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 host 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", () -> new JarServiceNameDetector().create()); + } +} 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..deb88eefa6de --- /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 host 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", () -> new ManifestResourceProvider().createUnconditional()); + } +} diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ResourceCustomizerProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ResourceCustomizerProvider.java new file mode 100644 index 000000000000..7acaf20678be --- /dev/null +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ResourceCustomizerProvider.java @@ -0,0 +1,63 @@ +/* + * 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.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 { + + private static final List NEEDED_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 : NEEDED_DETECTORS) { + if (!names.contains(name)) { + ExperimentalResourceDetectorModel detector = new ExperimentalResourceDetectorModel(); + detector.getAdditionalProperties().put(name, null); + detectors.add(detector); + } + } + return model; + }); + } +} 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/ResourceCustomizerProviderTest.java b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ResourceCustomizerProviderTest.java new file mode 100644 index 000000000000..908c0b2a793d --- /dev/null +++ b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ResourceCustomizerProviderTest.java @@ -0,0 +1,39 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.resources.internal; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; +import io.opentelemetry.testing.internal.jackson.core.JsonProcessingException; +import io.opentelemetry.testing.internal.jackson.databind.ObjectMapper; +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\":[],\"detectionDevelopment\":{\"attributes\":null,\"detectors\":[" + + "{\"additionalProperties\":{\"distribution\":null}}," + + "{\"additionalProperties\":{\"service\":null}}]}," + + "\"schemaUrl\":null,\"attributesList\":null}"); + } catch (JsonProcessingException e) { + throw new AssertionError(e); + } + }); + } +} 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..aeba99cff5c8 --- /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 host 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/src/main/java/io/opentelemetry/javaagent/tooling/DistroComponentProvider.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroComponentProvider.java new file mode 100644 index 000000000000..0a917402ac24 --- /dev/null +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroComponentProvider.java @@ -0,0 +1,30 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.tooling; + +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; + +@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/DistroResourceProvider.java similarity index 89% rename from javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroVersionResourceProvider.java rename to javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroResourceProvider.java index 53fe1d65a5d1..7cd52d56ce41 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroVersionResourceProvider.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroResourceProvider.java @@ -15,10 +15,14 @@ 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( From 70cc64c34af8da46c25918f668b62343911e108a Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 10 Jul 2025 16:48:05 +0200 Subject: [PATCH 02/29] add missing declarative config resource providers --- .../opentelemetry/javaagent/tooling/DistroComponentProvider.java | 1 + 1 file changed, 1 insertion(+) diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroComponentProvider.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroComponentProvider.java index 0a917402ac24..8febbe978690 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroComponentProvider.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroComponentProvider.java @@ -10,6 +10,7 @@ import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; import io.opentelemetry.sdk.resources.Resource; +@SuppressWarnings("rawtypes") @AutoService(ComponentProvider.class) public class DistroComponentProvider implements ComponentProvider { From cadc2375c1ec203c482cffe65c04b2109194c086 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 10 Jul 2025 17:42:49 +0200 Subject: [PATCH 03/29] add missing declarative config resource providers --- ...igTest.java => ResourceDeclarativeConfigTest.java} | 2 +- javaagent-tooling/build.gradle.kts | 1 + .../{ => resources}/DistroComponentProvider.java | 2 +- .../{ => resources}/DistroResourceProvider.java | 3 ++- .../resources}/ResourceCustomizerProvider.java | 2 +- .../resources}/ResourceCustomizerProviderTest.java | 11 ++++------- 6 files changed, 10 insertions(+), 11 deletions(-) rename instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/{DeclarativeConfigTest.java => ResourceDeclarativeConfigTest.java} (98%) rename javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/{ => resources}/DistroComponentProvider.java (93%) rename javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/{ => resources}/DistroResourceProvider.java (90%) rename {instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal => javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources}/ResourceCustomizerProvider.java (97%) rename {instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal => javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/resources}/ResourceCustomizerProviderTest.java (62%) 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 4033d6173235..882dc9af7539 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/javaagent-tooling/build.gradle.kts b/javaagent-tooling/build.gradle.kts index 653ff1bdf1ce..848c87e7da82 100644 --- a/javaagent-tooling/build.gradle.kts +++ b/javaagent-tooling/build.gradle.kts @@ -62,6 +62,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/DistroComponentProvider.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/DistroComponentProvider.java similarity index 93% rename from javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroComponentProvider.java rename to javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/DistroComponentProvider.java index 8febbe978690..e9a2d614d404 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroComponentProvider.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/DistroComponentProvider.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.tooling; +package io.opentelemetry.javaagent.tooling.resources; import com.google.auto.service.AutoService; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroResourceProvider.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/DistroResourceProvider.java similarity index 90% rename from javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroResourceProvider.java rename to javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/DistroResourceProvider.java index 7cd52d56ce41..b2c76e33dacb 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/DistroResourceProvider.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/DistroResourceProvider.java @@ -3,13 +3,14 @@ * 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; diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ResourceCustomizerProvider.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/ResourceCustomizerProvider.java similarity index 97% rename from instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ResourceCustomizerProvider.java rename to javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/ResourceCustomizerProvider.java index 7acaf20678be..ba8504f41fce 100644 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ResourceCustomizerProvider.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/ResourceCustomizerProvider.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.resources.internal; +package io.opentelemetry.javaagent.tooling.resources; import com.google.auto.service.AutoService; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer; diff --git a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ResourceCustomizerProviderTest.java b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/resources/ResourceCustomizerProviderTest.java similarity index 62% rename from instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ResourceCustomizerProviderTest.java rename to javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/resources/ResourceCustomizerProviderTest.java index 908c0b2a793d..9c4bbe24c94f 100644 --- a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ResourceCustomizerProviderTest.java +++ b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/resources/ResourceCustomizerProviderTest.java @@ -3,13 +3,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.resources.internal; +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 io.opentelemetry.testing.internal.jackson.core.JsonProcessingException; -import io.opentelemetry.testing.internal.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; class ResourceCustomizerProviderTest { @@ -27,10 +27,7 @@ void customize() { try { assertThat(objectMapper.writeValueAsString(configurationModel.getResource())) .isEqualTo( - "{\"attributes\":[],\"detectionDevelopment\":{\"attributes\":null,\"detectors\":[" - + "{\"additionalProperties\":{\"distribution\":null}}," - + "{\"additionalProperties\":{\"service\":null}}]}," - + "\"schemaUrl\":null,\"attributesList\":null}"); + "{\"attributes\":[],\"detection/development\":{\"detectors\":[{\"distribution\":null},{\"service\":null}]}}"); } catch (JsonProcessingException e) { throw new AssertionError(e); } From a128a8f37cdba42977601101daa2a456f9fc08b5 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 10 Jul 2025 19:57:55 +0200 Subject: [PATCH 04/29] prevent that view config file is loaded --- .../internal/properties/SpringConfigPropertiesTest.java | 1 - .../src/test/resources/application.yaml | 3 --- 2 files changed, 4 deletions(-) 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 ] From 677bf187a8cdcecea47f47f7df31debea9e7e773 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 16 Jul 2025 16:58:23 +0200 Subject: [PATCH 05/29] pr review --- instrumentation/resources/library/build.gradle.kts | 3 ++- .../instrumentation/resources/AttributeResourceProvider.java | 2 +- .../instrumentation/resources/ManifestResourceProvider.java | 5 +++++ .../internal/ManifestResourceComponentProvider.java | 2 +- .../tooling/resources/ResourceCustomizerProvider.java | 4 ++-- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/instrumentation/resources/library/build.gradle.kts b/instrumentation/resources/library/build.gradle.kts index 003b33a17f96..bb41a8b31dd9 100644 --- a/instrumentation/resources/library/build.gradle.kts +++ b/instrumentation/resources/library/build.gradle.kts @@ -8,12 +8,13 @@ dependencies { compileOnly("io.opentelemetry:opentelemetry-api-incubator") implementation("io.opentelemetry:opentelemetry-sdk-common") implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi") - implementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") + compileOnly("io.opentelemetry:opentelemetry-sdk-extension-incubator") implementation("io.opentelemetry.semconv:opentelemetry-semconv") annotationProcessor("com.google.auto.service:auto-service") compileOnly("com.google.auto.service:auto-service-annotations") testCompileOnly("com.google.auto.service:auto-service-annotations") + testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") testImplementation("org.junit.jupiter:junit-jupiter-api") } 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 d4fc9bd1d4be..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 @@ -70,7 +70,7 @@ public final Resource createResource(ConfigProperties config) { } @SuppressWarnings({"unchecked", "rawtypes"}) - public final Resource createUnconditional() { + protected final Resource createUnconditional() { return create((Set) attributeGetters.keySet()); } 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 2946ad3d8776..21d74db8b859 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 @@ -9,6 +9,7 @@ import com.google.auto.service.AutoService; 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 +70,10 @@ public void registerAttributes(Builder builder) { this(() -> Optional.ofNullable(jarPathFinder.detectJarPath()), manifestReader); } + public Resource create() { + 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/ManifestResourceComponentProvider.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceComponentProvider.java index deb88eefa6de..5c1be3d92783 100644 --- 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 @@ -19,6 +19,6 @@ @AutoService(ComponentProvider.class) public class ManifestResourceComponentProvider extends ResourceComponentProvider { public ManifestResourceComponentProvider() { - super("manifest", () -> new ManifestResourceProvider().createUnconditional()); + super("manifest", () -> new ManifestResourceProvider().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 index ba8504f41fce..283cef928240 100644 --- 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 @@ -27,7 +27,7 @@ @AutoService(DeclarativeConfigurationCustomizerProvider.class) public class ResourceCustomizerProvider implements DeclarativeConfigurationCustomizerProvider { - private static final List NEEDED_DETECTORS = Arrays.asList("distribution", "service"); + private static final List REQUIRED_DETECTORS = Arrays.asList("distribution", "service"); @Override public void customize(DeclarativeConfigurationCustomizer customizer) { @@ -50,7 +50,7 @@ public void customize(DeclarativeConfigurationCustomizer customizer) { .flatMap(detector -> detector.getAdditionalProperties().keySet().stream()) .collect(Collectors.toSet()); - for (String name : NEEDED_DETECTORS) { + for (String name : REQUIRED_DETECTORS) { if (!names.contains(name)) { ExperimentalResourceDetectorModel detector = new ExperimentalResourceDetectorModel(); detector.getAdditionalProperties().put(name, null); From b594dfbbf9854e927b8499f39cddd322a10822a6 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 16 Jul 2025 18:47:53 +0200 Subject: [PATCH 06/29] add docs --- .../tooling/resources/ResourceCustomizerProvider.java | 4 ++++ 1 file changed, 4 insertions(+) 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 index 283cef928240..3b7967619f0d 100644 --- 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 @@ -27,6 +27,10 @@ @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 From 6219ad9c2213c55e18e9a50e6169b3a2176a0066 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 17 Jul 2025 09:10:51 +0200 Subject: [PATCH 07/29] pr feedback --- .../resources/internal/JarResourceComponentProvider.java | 2 +- .../resources/internal/ManifestResourceComponentProvider.java | 2 +- .../spring/resources/SpringResourceComponentProvider.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 index b43a4a3d6424..2e605edbfa91 100644 --- 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 @@ -10,7 +10,7 @@ import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; /** - * Declarative config host resource provider. + * 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. 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 index 5c1be3d92783..07888c1e27ab 100644 --- 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 @@ -10,7 +10,7 @@ import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; /** - * Declarative config host resource provider. + * 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. 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 index aeba99cff5c8..7c1ef57a8317 100644 --- 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 @@ -11,7 +11,7 @@ import io.opentelemetry.sdk.resources.Resource; /** - * Declarative config host resource provider. + * 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. From 9ffb6555640f212ce4c83fe52e3043adb77686d8 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Sat, 16 Aug 2025 11:53:51 +0200 Subject: [PATCH 08/29] pr review --- .../instrumentation/resources/JarServiceNameDetector.java | 8 +++++++- .../resources/ManifestResourceProvider.java | 4 +++- .../internal/ContainerResourceComponentProvider.java | 2 +- .../resources/internal/HostResourceComponentProvider.java | 2 +- .../resources/internal/JarResourceComponentProvider.java | 2 +- .../internal/ManifestResourceComponentProvider.java | 2 +- .../internal/ProcessResourceComponentProvider.java | 2 +- .../resources/internal/ResourceComponentProvider.java | 8 ++++---- 8 files changed, 19 insertions(+), 11 deletions(-) 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 a706d665d86b..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; @@ -49,7 +50,12 @@ public Resource createResource(ConfigProperties config) { return create(); } - public Resource 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 21d74db8b859..6b689ce1b1d2 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,6 +8,7 @@ import static java.util.logging.Level.FINE; 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; @@ -70,7 +71,8 @@ public void registerAttributes(Builder builder) { this(() -> Optional.ofNullable(jarPathFinder.detectJarPath()), manifestReader); } - public Resource create() { + @SuppressWarnings("unused") + public Resource createResource(DeclarativeConfigProperties config) { return createUnconditional(); } 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 index 2e605edbfa91..8c6f766046d8 100644 --- 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 @@ -19,6 +19,6 @@ @AutoService(ComponentProvider.class) public class JarResourceComponentProvider extends ResourceComponentProvider { public JarResourceComponentProvider() { - super("jar", () -> new JarServiceNameDetector().create()); + 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 index 07888c1e27ab..091f7219163b 100644 --- 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 @@ -19,6 +19,6 @@ @AutoService(ComponentProvider.class) public class ManifestResourceComponentProvider extends ResourceComponentProvider { public ManifestResourceComponentProvider() { - super("manifest", () -> new ManifestResourceProvider().create()); + 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); } } From acce0281f8b2c17f61dc9d8ec005ee28689fb6d5 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 20 Aug 2025 09:08:07 +0200 Subject: [PATCH 09/29] fix --- .../resources/AttributeResourceProvider.java | 5 +++-- .../resources/ManifestResourceProvider.java | 7 ------- .../resources/ManifestResourceProviderTest.java | 6 +++++- 3 files changed, 8 insertions(+), 10 deletions(-) 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 82dce4684e08..5f55cf25d992 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 @@ -9,6 +9,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.internal.ConditionalResourceProvider; import io.opentelemetry.sdk.resources.Resource; @@ -69,8 +70,8 @@ public final Resource createResource(ConfigProperties config) { return create(filteredKeys); } - @SuppressWarnings({"unchecked", "rawtypes"}) - protected final Resource createUnconditional() { + @SuppressWarnings({"unchecked", "rawtypes", "unused"}) + public final Resource createResource(DeclarativeConfigProperties config) { return create((Set) attributeGetters.keySet()); } 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 6b689ce1b1d2..2946ad3d8776 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,9 +8,7 @@ import static java.util.logging.Level.FINE; 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; @@ -71,11 +69,6 @@ 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/test/java/io/opentelemetry/instrumentation/resources/ManifestResourceProviderTest.java b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/ManifestResourceProviderTest.java index d6c088b9c7df..bbe387f2efff 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 @@ -10,6 +10,7 @@ import static org.assertj.core.api.Assertions.assertThat; 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.internal.DefaultConfigProperties; import io.opentelemetry.sdk.resources.Resource; @@ -99,7 +100,10 @@ Collection createResource() { if (t.existing.getAttributes().isEmpty()) { // component provider does not consider existing resource - assertThat(provider.createUnconditional().getAttributes()) + assertThat( + provider + .createResource(DeclarativeConfigProperties.empty()) + .getAttributes()) .isEqualTo(resource.getAttributes()); } })) From e0829555dc04a4fc9205d72d16e1f6a9b74721ff Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 21 Aug 2025 13:15:46 +0200 Subject: [PATCH 10/29] pr feedback --- .../instrumentation/resources/AttributeResourceProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5f55cf25d992..56c78bd44eca 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 @@ -70,7 +70,7 @@ public final Resource createResource(ConfigProperties config) { return create(filteredKeys); } - @SuppressWarnings({"unchecked", "rawtypes", "unused"}) + @SuppressWarnings({"unchecked", "rawtypes"}) public final Resource createResource(DeclarativeConfigProperties config) { return create((Set) attributeGetters.keySet()); } From 27d6dc7f74d68e88bf8f17c0761dbf9eea26b80f Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 21 Aug 2025 13:20:33 +0200 Subject: [PATCH 11/29] pr feedback --- .../spring/resources/SpringBootServiceNameDetector.java | 7 ++++++- .../spring/resources/SpringBootServiceVersionDetector.java | 7 ++++++- .../spring/resources/SpringResourceComponentProvider.java | 4 ++-- 3 files changed, 14 insertions(+), 4 deletions(-) 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 18a8f23cf338..fa754bdf0816 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 @@ -9,6 +9,7 @@ import static java.util.logging.Level.FINER; import com.google.auto.service.AutoService; +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; @@ -74,7 +75,11 @@ public Resource createResource(ConfigProperties config) { return create(); } - Resource create() { + public Resource createResource(DeclarativeConfigProperties config) { + return create(); + } + + private 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 ba68d6bca0ea..4a457a334af6 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 @@ -8,6 +8,7 @@ import static java.util.logging.Level.FINE; import com.google.auto.service.AutoService; +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.resources.Resource; @@ -44,7 +45,11 @@ public Resource createResource(ConfigProperties config) { return create(); } - Resource create() { + public Resource createResource(DeclarativeConfigProperties config) { + return create(); + } + + private 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 index 7c1ef57a8317..a6eff7234e59 100644 --- 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 @@ -33,7 +33,7 @@ public String getName() { @Override public Resource create(DeclarativeConfigProperties config) { return new SpringBootServiceVersionDetector() - .create() - .merge(new SpringBootServiceNameDetector().create()); + .createResource(config) + .merge(new SpringBootServiceNameDetector().createResource(config)); } } From 582adac76940b084af4d3d46f9e78b4f9d3908ab Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 22 Aug 2025 06:56:48 +0200 Subject: [PATCH 12/29] separate resource extraction from supported interfaces --- .../resources/JarServiceNameDetector.java | 56 +----------- .../resources/ManifestResourceProvider.java | 54 +++--------- .../resources/ProcessArguments.java | 15 ---- .../resources/ProcessResource.java | 1 + .../JarResourceComponentProvider.java | 3 +- .../JarServiceNameResourceExtractor.java | 62 +++++++++++++ .../{ => internal}/MainJarPathFinder.java | 3 +- .../{ => internal}/MainJarPathHolder.java | 2 +- .../ManifestResourceComponentProvider.java | 3 +- .../internal/ManifestResourceExtractor.java | 85 ++++++++++++++++++ .../resources/internal/ProcessArguments.java | 19 ++++ .../ManifestResourceProviderTest.java | 49 ++--------- .../JarServiceNameResourceExtractorTest.java} | 70 +++++++-------- .../ManifestResourceExtractorTest.java | 88 +++++++++++++++++++ 14 files changed, 318 insertions(+), 192 deletions(-) delete mode 100644 instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/ProcessArguments.java create mode 100644 instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractor.java rename instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/{ => internal}/MainJarPathFinder.java (97%) rename instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/{ => internal}/MainJarPathHolder.java (86%) create mode 100644 instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractor.java create mode 100644 instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessArguments.java rename instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/{JarServiceNameDetectorTest.java => internal/JarServiceNameResourceExtractorTest.java} (62%) create mode 100644 instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractorTest.java 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 89fdb28b8085..24c40387b5cd 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 @@ -5,67 +5,25 @@ package io.opentelemetry.instrumentation.resources; -import static java.util.logging.Level.FINE; - import com.google.auto.service.AutoService; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.instrumentation.resources.internal.JarServiceNameResourceExtractor; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider; import io.opentelemetry.sdk.autoconfigure.spi.internal.ConditionalResourceProvider; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.semconv.ServiceAttributes; -import java.nio.file.Path; import java.util.Map; -import java.util.Optional; -import java.util.function.Supplier; -import java.util.logging.Logger; /** - * A {@link ResourceProvider} that will attempt to detect the application name from the jar name. + * A {@link ResourceProvider} that will attempt to detect the service.name from the + * * main jar file name. */ @AutoService(ResourceProvider.class) public final class JarServiceNameDetector implements ConditionalResourceProvider { - private static final Logger logger = Logger.getLogger(JarServiceNameDetector.class.getName()); - - private final Supplier> jarPathSupplier; - - @SuppressWarnings("unused") // SPI - public JarServiceNameDetector() { - this(MainJarPathHolder::getJarPath); - } - - private JarServiceNameDetector(Supplier> jarPathSupplier) { - this.jarPathSupplier = jarPathSupplier; - } - - // visible for tests - JarServiceNameDetector(MainJarPathFinder jarPathFinder) { - this(() -> Optional.ofNullable(jarPathFinder.detectJarPath())); - } - @Override public Resource createResource(ConfigProperties config) { - return create(); - } - - @SuppressWarnings("unused") - public Resource createResource(DeclarativeConfigProperties config) { - return create(); - } - - private Resource create() { - return jarPathSupplier - .get() - .map( - jarPath -> { - String serviceName = getServiceName(jarPath); - logger.log( - FINE, "Auto-detected service name from the jar file name: {0}", serviceName); - return Resource.create(Attributes.of(ServiceAttributes.SERVICE_NAME, serviceName)); - }) - .orElseGet(Resource::empty); + return new JarServiceNameResourceExtractor().extract(); } @Override @@ -77,12 +35,6 @@ public boolean shouldApply(ConfigProperties config, Resource existing) { && "unknown_service:java".equals(existing.getAttribute(ServiceAttributes.SERVICE_NAME)); } - private static String getServiceName(Path jarPath) { - String jarName = jarPath.getFileName().toString(); - int dotIndex = jarName.lastIndexOf("."); - return dotIndex == -1 ? jarName : jarName.substring(0, dotIndex); - } - @Override public int order() { // make it run later than the SpringBootServiceNameDetector 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 2946ad3d8776..c0c7255c0f3b 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,76 +8,48 @@ import static java.util.logging.Level.FINE; import com.google.auto.service.AutoService; +import io.opentelemetry.instrumentation.resources.internal.ManifestResourceExtractor; 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; import java.util.Optional; -import java.util.function.Function; import java.util.function.Supplier; -import java.util.jar.JarFile; -import java.util.jar.Manifest; -import java.util.logging.Logger; /** * A {@link ResourceProvider} that will attempt to detect the service.name and * service.version from META-INF/MANIFEST.MF. */ @AutoService(ResourceProvider.class) -public final class ManifestResourceProvider extends AttributeResourceProvider { - - private static final Logger logger = Logger.getLogger(ManifestResourceProvider.class.getName()); +public final class ManifestResourceProvider extends AttributeResourceProvider { @SuppressWarnings("unused") // SPI public ManifestResourceProvider() { - this(MainJarPathHolder::getJarPath, ManifestResourceProvider::readManifest); + this(() -> new ManifestResourceExtractor().extract()); } - private ManifestResourceProvider( - Supplier> jarPathSupplier, Function> manifestReader) { + // Visible for testing + ManifestResourceProvider( + Supplier resourceSupplier) { super( - new AttributeProvider() { + new AttributeProvider() { @Override - public Optional readData() { - return jarPathSupplier.get().flatMap(manifestReader); + public Optional readData() { + return Optional.of(resourceSupplier.get()); } @Override - public void registerAttributes(Builder builder) { + public void registerAttributes(Builder builder) { builder .add( ServiceAttributes.SERVICE_NAME, - manifest -> { - String serviceName = - manifest.getMainAttributes().getValue("Implementation-Title"); - return Optional.ofNullable(serviceName); - }) + r -> Optional.ofNullable(r.getAttribute(ServiceAttributes.SERVICE_NAME))) .add( ServiceAttributes.SERVICE_VERSION, - manifest -> { - String serviceVersion = - manifest.getMainAttributes().getValue("Implementation-Version"); - return Optional.ofNullable(serviceVersion); - }); + r -> Optional.ofNullable(r.getAttribute(ServiceAttributes.SERVICE_VERSION))); } }); } - // Visible for testing - ManifestResourceProvider( - MainJarPathFinder jarPathFinder, Function> manifestReader) { - this(() -> Optional.ofNullable(jarPathFinder.detectJarPath()), manifestReader); - } - - private static Optional readManifest(Path jarPath) { - try (JarFile jarFile = new JarFile(jarPath.toFile(), false)) { - return Optional.of(jarFile.getManifest()); - } catch (IOException exception) { - logger.log(FINE, "Error reading manifest", exception); - return Optional.empty(); - } - } - @Override public int order() { // make it run later than SpringBootServiceNameDetector diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/ProcessArguments.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/ProcessArguments.java deleted file mode 100644 index c835f876965c..000000000000 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/ProcessArguments.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.resources; - -final class ProcessArguments { - - static String[] getProcessArguments() { - return new String[0]; - } - - private ProcessArguments() {} -} diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/ProcessResource.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/ProcessResource.java index 666c2964d8e2..20470efbfa92 100644 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/ProcessResource.java +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/ProcessResource.java @@ -8,6 +8,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.instrumentation.resources.internal.ProcessArguments; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.semconv.SchemaUrls; import java.io.File; 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 index 8c6f766046d8..938dae452199 100644 --- 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 @@ -6,7 +6,6 @@ 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; /** @@ -19,6 +18,6 @@ @AutoService(ComponentProvider.class) public class JarResourceComponentProvider extends ResourceComponentProvider { public JarResourceComponentProvider() { - super("jar", p -> new JarServiceNameDetector().createResource(p)); + super("jar", p -> new JarServiceNameResourceExtractor().extract()); } } diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractor.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractor.java new file mode 100644 index 000000000000..a93e7c86aa73 --- /dev/null +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractor.java @@ -0,0 +1,62 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.resources.internal; + +import static java.util.logging.Level.FINE; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.semconv.ServiceAttributes; +import java.nio.file.Path; +import java.util.Optional; +import java.util.function.Supplier; +import java.util.logging.Logger; + +/** + * A resource extractor that will attempt to detect the service.name from the + * main jar file name. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class JarServiceNameResourceExtractor { + + private static final Logger logger = Logger.getLogger(JarServiceNameResourceExtractor.class.getName()); + + private final Supplier> jarPathSupplier; + + public JarServiceNameResourceExtractor() { + this(MainJarPathHolder::getJarPath); + } + + // visible for tests + JarServiceNameResourceExtractor(MainJarPathFinder jarPathFinder) { + this(() -> Optional.ofNullable(jarPathFinder.detectJarPath())); + } + + private JarServiceNameResourceExtractor(Supplier> jarPathSupplier) { + this.jarPathSupplier = jarPathSupplier; + } + + public Resource extract() { + return jarPathSupplier + .get() + .map( + jarPath -> { + String serviceName = getServiceName(jarPath); + logger.log( + FINE, "Auto-detected service name from the jar file name: {0}", serviceName); + return Resource.create(Attributes.of(ServiceAttributes.SERVICE_NAME, serviceName)); + }) + .orElseGet(Resource::empty); + } + + private static String getServiceName(Path jarPath) { + String jarName = jarPath.getFileName().toString(); + int dotIndex = jarName.lastIndexOf("."); + return dotIndex == -1 ? jarName : jarName.substring(0, dotIndex); + } +} diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/MainJarPathFinder.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/MainJarPathFinder.java similarity index 97% rename from instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/MainJarPathFinder.java rename to instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/MainJarPathFinder.java index c0c7588698f2..99148e95b716 100644 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/MainJarPathFinder.java +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/MainJarPathFinder.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.resources; +package io.opentelemetry.instrumentation.resources.internal; import java.nio.file.Files; import java.nio.file.InvalidPathException; @@ -14,6 +14,7 @@ import java.util.function.Supplier; import javax.annotation.Nullable; + class MainJarPathFinder { private final Supplier getProcessHandleArguments; private final Function getSystemProperty; diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/MainJarPathHolder.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/MainJarPathHolder.java similarity index 86% rename from instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/MainJarPathHolder.java rename to instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/MainJarPathHolder.java index c6948d3eca39..ee6df00ca345 100644 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/MainJarPathHolder.java +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/MainJarPathHolder.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.resources; +package io.opentelemetry.instrumentation.resources.internal; import java.nio.file.Path; import java.util.Optional; 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 index 091f7219163b..0d290adef0a2 100644 --- 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 @@ -6,7 +6,6 @@ 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; /** @@ -19,6 +18,6 @@ @AutoService(ComponentProvider.class) public class ManifestResourceComponentProvider extends ResourceComponentProvider { public ManifestResourceComponentProvider() { - super("manifest", p -> new ManifestResourceProvider().createResource(p)); + super("manifest", p -> new ManifestResourceExtractor().extract()); } } diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractor.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractor.java new file mode 100644 index 000000000000..1aae397955b7 --- /dev/null +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractor.java @@ -0,0 +1,85 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.resources.internal; + +import static java.util.logging.Level.WARNING; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.semconv.ServiceAttributes; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.logging.Logger; + +/** + * A resource extractor that will attempt to detect the service.name and + * service.version from META-INF/MANIFEST.MF. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class ManifestResourceExtractor { + + private static final Logger logger = Logger.getLogger(ManifestResourceExtractor.class.getName()); + + private final Supplier> jarPathSupplier; + + private final Function> manifestReader; + + public ManifestResourceExtractor() { + this(MainJarPathHolder::getJarPath, ManifestResourceExtractor::readManifest); + } + + // Visible for testing + ManifestResourceExtractor( + MainJarPathFinder jarPathFinder, Function> manifestReader) { + this(() -> Optional.ofNullable(jarPathFinder.detectJarPath()), manifestReader); + } + + private ManifestResourceExtractor( + Supplier> jarPathSupplier, Function> manifestReader) { + this.jarPathSupplier = jarPathSupplier; + this.manifestReader = manifestReader; + } + + public Resource extract() { + return jarPathSupplier + .get() + .flatMap(manifestReader) + .map( + manifest -> extract(manifest)) + .orElseGet(Resource::empty); + } + + private static Resource extract(Manifest manifest) { + String serviceName = manifest.getMainAttributes().getValue("Implementation-Title"); + AttributesBuilder builder = Attributes.builder(); + if (serviceName != null) { + builder.put(ServiceAttributes.SERVICE_NAME, serviceName); + } + + String serviceVersion = manifest.getMainAttributes().getValue("Implementation-Version"); + if (serviceVersion != null) { + builder.put(ServiceAttributes.SERVICE_VERSION, serviceVersion); + } + return Resource.create(builder.build()); + } + + private static Optional readManifest(Path jarPath) { + try (JarFile jarFile = new JarFile(jarPath.toFile(), false)) { + return Optional.of(jarFile.getManifest()); + } catch (IOException exception) { + logger.log(WARNING, "Error reading manifest", exception); + return Optional.empty(); + } + } +} diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessArguments.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessArguments.java new file mode 100644 index 000000000000..9f2e6e4a3350 --- /dev/null +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessArguments.java @@ -0,0 +1,19 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.resources.internal; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class ProcessArguments { + + public static String[] getProcessArguments() { + return new String[0]; + } + + private ProcessArguments() {} +} 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 bbe387f2efff..e562f6d8251d 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 @@ -10,15 +10,11 @@ import static org.assertj.core.api.Assertions.assertThat; 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.internal.DefaultConfigProperties; import io.opentelemetry.sdk.resources.Resource; -import java.io.InputStream; import java.util.Collection; import java.util.Collections; -import java.util.Optional; -import java.util.jar.Manifest; import java.util.stream.Collectors; import java.util.stream.Stream; import org.junit.jupiter.api.DynamicTest; @@ -30,14 +26,14 @@ private static class TestCase { private final String name; private final String expectedName; private final String expectedVersion; - private final InputStream input; + private final Resource input; private final Resource existing; TestCase( String name, String expectedName, String expectedVersion, - InputStream input, + Resource input, Resource existing) { this.name = name; this.expectedName = expectedName; @@ -56,20 +52,17 @@ Collection createResource() { "name ok", "demo", "0.0.1-SNAPSHOT", - openClasspathResource("MANIFEST.MF"), + Resource.create( + Attributes.of(SERVICE_NAME, "demo", SERVICE_VERSION, "0.0.1-SNAPSHOT")), Resource.getDefault()), - new TestCase("name - no resource", null, null, null, Resource.getDefault()), new TestCase( - "name - empty resource", - null, - null, - openClasspathResource("empty-MANIFEST.MF"), - Resource.getDefault()), + "name - empty resource", null, null, Resource.getDefault(), Resource.getDefault()), new TestCase( "name already detected", null, "0.0.1-SNAPSHOT", - openClasspathResource("MANIFEST.MF"), + Resource.create( + Attributes.of(SERVICE_NAME, "demo", SERVICE_VERSION, "0.0.1-SNAPSHOT")), Resource.create(Attributes.of(SERVICE_NAME, "old")))) .map( t -> @@ -77,40 +70,14 @@ Collection createResource() { t.name, () -> { ManifestResourceProvider provider = - new ManifestResourceProvider( - new MainJarPathFinder( - () -> JarServiceNameDetectorTest.getArgs("app.jar"), - prop -> null, - JarServiceNameDetectorTest::failPath), - p -> { - try { - Manifest manifest = new Manifest(); - manifest.read(t.input); - return Optional.of(manifest); - } catch (Exception e) { - return Optional.empty(); - } - }); + new ManifestResourceProvider(() -> t.input); provider.shouldApply(config, t.existing); Resource resource = provider.createResource(config); 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 - .createResource(DeclarativeConfigProperties.empty()) - .getAttributes()) - .isEqualTo(resource.getAttributes()); - } })) .collect(Collectors.toList()); } - - private static InputStream openClasspathResource(String resource) { - return ManifestResourceProviderTest.class.getClassLoader().getResourceAsStream(resource); - } } diff --git a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/JarServiceNameDetectorTest.java b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractorTest.java similarity index 62% rename from instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/JarServiceNameDetectorTest.java rename to instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractorTest.java index ff8ce66848ef..b9bf85f780d8 100644 --- a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/JarServiceNameDetectorTest.java +++ b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractorTest.java @@ -3,13 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.instrumentation.resources; +package io.opentelemetry.instrumentation.resources.internal; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_NAME; import static org.junit.jupiter.params.provider.Arguments.arguments; -import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.resources.Resource; import java.nio.file.Path; import java.nio.file.Paths; @@ -21,74 +20,71 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) // todo split JarFileDetectorTest and JarServiceNameDetectorTest -class JarServiceNameDetectorTest { - - @Mock ConfigProperties config; +class JarServiceNameResourceExtractorTest { @Test - void createResource_empty() { + void extractResource_empty() { String[] processArgs = new String[0]; Function getProperty = prop -> null; - Predicate fileExists = JarServiceNameDetectorTest::failPath; - JarServiceNameDetector serviceNameProvider = getDetector(processArgs, getProperty, fileExists); + Predicate fileExists = JarServiceNameResourceExtractorTest::failPath; + JarServiceNameResourceExtractor serviceNameProvider = getFinder(processArgs, getProperty, fileExists); - Resource resource = serviceNameProvider.createResource(config); + Resource resource = serviceNameProvider.extract(); assertThat(resource.getAttributes()).isEmpty(); } - private static JarServiceNameDetector getDetector( + private static JarServiceNameResourceExtractor getFinder( String[] processArgs, Function getProperty, Predicate fileExists) { - return new JarServiceNameDetector( + return new JarServiceNameResourceExtractor( new MainJarPathFinder(() -> processArgs, getProperty, fileExists)); } @Test - void createResource_noJarFileInArgs() { + void extractResource_noJarFileInArgs() { String[] args = new String[] {"-Dtest=42", "-Xmx666m", "-jar"}; - JarServiceNameDetector serviceNameProvider = - getDetector(args, prop -> null, JarServiceNameDetectorTest::failPath); + JarServiceNameResourceExtractor serviceNameProvider = + getFinder(args, prop -> null, JarServiceNameResourceExtractorTest::failPath); - Resource resource = serviceNameProvider.createResource(config); + Resource resource = serviceNameProvider.extract(); assertThat(resource.getAttributes()).isEmpty(); } @Test - void createResource_processHandleJar() { - JarServiceNameDetector serviceNameProvider = - getDetector(getArgs("my-service.jar"), prop -> null, JarServiceNameDetectorTest::failPath); + void extractResource_processHandleJar() { + JarServiceNameResourceExtractor serviceNameProvider = + getFinder(getArgs("my-service.jar"), prop -> null, JarServiceNameResourceExtractorTest::failPath); - Resource resource = serviceNameProvider.createResource(config); + Resource resource = serviceNameProvider.extract(); assertThat(resource.getAttributes()).hasSize(1).containsEntry(SERVICE_NAME, "my-service"); } @Test - void createResource_processHandleJarExtraFlag() { + void extractResource_processHandleJarExtraFlag() { String path = Paths.get("path", "to", "app", "my-service.jar").toString(); - JarServiceNameDetector serviceNameProvider = - getDetector( + JarServiceNameResourceExtractor serviceNameProvider = + getFinder( new String[] {"-Dtest=42", "-jar", "-Xmx512m", path, "abc", "def"}, prop -> null, - JarServiceNameDetectorTest::failPath); + JarServiceNameResourceExtractorTest::failPath); - Resource resource = serviceNameProvider.createResource(config); + Resource resource = serviceNameProvider.extract(); assertThat(resource.getAttributes()).hasSize(1).containsEntry(SERVICE_NAME, "my-service"); } @Test - void createResource_processHandleJarWithoutExtension() { - JarServiceNameDetector serviceNameProvider = - getDetector(getArgs("my-service"), prop -> null, JarServiceNameDetectorTest::failPath); + void extractResource_processHandleJarWithoutExtension() { + JarServiceNameResourceExtractor serviceNameProvider = + getFinder(getArgs("my-service"), prop -> null, JarServiceNameResourceExtractorTest::failPath); - Resource resource = serviceNameProvider.createResource(config); + Resource resource = serviceNameProvider.extract(); assertThat(resource.getAttributes()).hasSize(1).containsEntry(SERVICE_NAME, "my-service"); } @@ -100,15 +96,15 @@ static String[] getArgs(String jarName) { @ParameterizedTest @MethodSource("sunCommandLineArguments") - void createResource_sunCommandLine(String commandLine, Path jarPath) { + void extractResource_sunCommandLine(String commandLine, Path jarPath) { Function getProperty = key -> "sun.java.command".equals(key) ? commandLine : null; Predicate fileExists = jarPath::equals; - JarServiceNameDetector serviceNameProvider = - getDetector(new String[0], getProperty, fileExists); + JarServiceNameResourceExtractor serviceNameProvider = + getFinder(new String[0], getProperty, fileExists); - Resource resource = serviceNameProvider.createResource(config); + Resource resource = serviceNameProvider.extract(); assertThat(resource.getAttributes()).hasSize(1).containsEntry(SERVICE_NAME, "my-service"); } @@ -116,15 +112,15 @@ void createResource_sunCommandLine(String commandLine, Path jarPath) { // regression test for // https://github.com/open-telemetry/opentelemetry-java-instrumentation/pull/7567 @Test - void createResource_sunCommandLineProblematicArgs() { + void extractResource_sunCommandLineProblematicArgs() { Function getProperty = key -> key.equals("sun.java.command") ? "one C:/two" : null; Predicate fileExists = path -> false; - JarServiceNameDetector serviceNameProvider = - getDetector(new String[0], getProperty, fileExists); + JarServiceNameResourceExtractor serviceNameProvider = + getFinder(new String[0], getProperty, fileExists); - Resource resource = serviceNameProvider.createResource(config); + Resource resource = serviceNameProvider.extract(); assertThat(resource.getAttributes()).isEmpty(); } diff --git a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractorTest.java b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractorTest.java new file mode 100644 index 000000000000..82e50f2569fc --- /dev/null +++ b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractorTest.java @@ -0,0 +1,88 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.resources.internal; + +import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_NAME; +import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_VERSION; +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.sdk.resources.Resource; +import java.io.InputStream; +import java.util.Collection; +import java.util.Optional; +import java.util.jar.Manifest; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.TestFactory; + +class ManifestResourceExtractorTest { + + private static class TestCase { + private final String name; + private final String expectedName; + private final String expectedVersion; + private final InputStream input; + + TestCase( + String name, + String expectedName, + String expectedVersion, + InputStream input) { + this.name = name; + this.expectedName = expectedName; + this.expectedVersion = expectedVersion; + this.input = input; + } + } + + @TestFactory + Collection extractResource() { + return Stream.of( + new TestCase( + "name ok", + "demo", + "0.0.1-SNAPSHOT", + openClasspathResource("MANIFEST.MF")), + new TestCase("name - no resource", null, null, null), + new TestCase( + "name - empty resource", + null, + null, + openClasspathResource("empty-MANIFEST.MF"))) + .map( + t -> + DynamicTest.dynamicTest( + t.name, + () -> { + ManifestResourceExtractor finder = + new ManifestResourceExtractor( + new MainJarPathFinder( + () -> JarServiceNameResourceExtractorTest.getArgs("app.jar"), + prop -> null, + JarServiceNameResourceExtractorTest::failPath), + p -> { + try { + Manifest manifest = new Manifest(); + manifest.read(t.input); + return Optional.of(manifest); + } catch (Exception e) { + return Optional.empty(); + } + }); + + Resource resource = finder.extract(); + assertThat(resource.getAttribute(SERVICE_NAME)).isEqualTo(t.expectedName); + assertThat(resource.getAttribute(SERVICE_VERSION)) + .isEqualTo(t.expectedVersion); + })) + .collect(Collectors.toList()); + } + + private static InputStream openClasspathResource(String resource) { + return ManifestResourceExtractorTest.class.getClassLoader().getResourceAsStream(resource); + } +} From e242758aa5c3f309a0bdf1823db9d70f320bdfc5 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 22 Aug 2025 07:00:12 +0200 Subject: [PATCH 13/29] separate resource extraction from supported interfaces --- .../resources/AttributeResourceProvider.java | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) 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 56c78bd44eca..31f4d18c2ec5 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 @@ -9,7 +9,6 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.AttributesBuilder; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.internal.ConditionalResourceProvider; import io.opentelemetry.sdk.resources.Resource; @@ -21,7 +20,6 @@ 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 @@ -67,25 +65,16 @@ public final boolean shouldApply(ConfigProperties config, Resource existing) { @Override public final Resource createResource(ConfigProperties config) { - return create(filteredKeys); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - public final Resource createResource(DeclarativeConfigProperties config) { - 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 -> keys.contains(e.getKey())) + .filter(e -> filteredKeys.contains(e.getKey())) .forEach( e -> e.getValue() From 40a3106e8c6b9c65d380c4b5f1831df0c8add212 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 22 Aug 2025 07:03:46 +0200 Subject: [PATCH 14/29] separate resource extraction from supported interfaces --- .../instrumentation/resources/ManifestResourceProviderTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e562f6d8251d..336850c8e78e 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 @@ -56,7 +56,7 @@ Collection createResource() { Attributes.of(SERVICE_NAME, "demo", SERVICE_VERSION, "0.0.1-SNAPSHOT")), Resource.getDefault()), new TestCase( - "name - empty resource", null, null, Resource.getDefault(), Resource.getDefault()), + "name - empty resource", null, null, Resource.empty(), Resource.getDefault()), new TestCase( "name already detected", null, From 7a0a61e0fd144ca9637ed94d4949bc6c6af708c8 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 22 Aug 2025 07:07:11 +0200 Subject: [PATCH 15/29] separate resource extraction from supported interfaces --- .../resources/ProcessArguments.java | 15 --------------- .../resources/internal/ProcessArguments.java | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 15 deletions(-) delete mode 100644 instrumentation/resources/library/src/main/java9/io/opentelemetry/instrumentation/resources/ProcessArguments.java create mode 100644 instrumentation/resources/library/src/main/java9/io/opentelemetry/instrumentation/resources/internal/ProcessArguments.java diff --git a/instrumentation/resources/library/src/main/java9/io/opentelemetry/instrumentation/resources/ProcessArguments.java b/instrumentation/resources/library/src/main/java9/io/opentelemetry/instrumentation/resources/ProcessArguments.java deleted file mode 100644 index b32f6c361524..000000000000 --- a/instrumentation/resources/library/src/main/java9/io/opentelemetry/instrumentation/resources/ProcessArguments.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.resources; - -final class ProcessArguments { - - static String[] getProcessArguments() { - return ProcessHandle.current().info().arguments().orElseGet(() -> new String[0]); - } - - private ProcessArguments() {} -} diff --git a/instrumentation/resources/library/src/main/java9/io/opentelemetry/instrumentation/resources/internal/ProcessArguments.java b/instrumentation/resources/library/src/main/java9/io/opentelemetry/instrumentation/resources/internal/ProcessArguments.java new file mode 100644 index 000000000000..04155cfed85e --- /dev/null +++ b/instrumentation/resources/library/src/main/java9/io/opentelemetry/instrumentation/resources/internal/ProcessArguments.java @@ -0,0 +1,19 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.resources.internal; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class ProcessArguments { + + public static String[] getProcessArguments() { + return ProcessHandle.current().info().arguments().orElseGet(() -> new String[0]); + } + + private ProcessArguments() {} +} From 850a699ae44adf6be3803aab17ba03cdc0ba687f Mon Sep 17 00:00:00 2001 From: otelbot <197425009+otelbot@users.noreply.github.com> Date: Fri, 22 Aug 2025 05:16:25 +0000 Subject: [PATCH 16/29] ./gradlew spotlessApply --- .../resources/JarServiceNameDetector.java | 4 ++-- .../resources/ManifestResourceProvider.java | 3 +-- .../JarServiceNameResourceExtractor.java | 7 ++++--- .../resources/internal/MainJarPathFinder.java | 1 - .../internal/ManifestResourceExtractor.java | 3 +-- .../resources/internal/ProcessArguments.java | 4 ++-- .../resources/internal/ProcessArguments.java | 4 ++-- .../JarServiceNameResourceExtractorTest.java | 9 ++++++--- .../internal/ManifestResourceExtractorTest.java | 17 +++-------------- 9 files changed, 21 insertions(+), 31 deletions(-) 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 24c40387b5cd..490da764ce56 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 @@ -15,8 +15,8 @@ import java.util.Map; /** - * A {@link ResourceProvider} that will attempt to detect the service.name from the - * * main jar file name. + * A {@link ResourceProvider} that will attempt to detect the service.name from the * + * main jar file name. */ @AutoService(ResourceProvider.class) public final class JarServiceNameDetector implements ConditionalResourceProvider { 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 c0c7255c0f3b..c8ba723a9728 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 @@ -28,8 +28,7 @@ public ManifestResourceProvider() { } // Visible for testing - ManifestResourceProvider( - Supplier resourceSupplier) { + ManifestResourceProvider(Supplier resourceSupplier) { super( new AttributeProvider() { @Override diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractor.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractor.java index a93e7c86aa73..d9c09b9a4073 100644 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractor.java +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractor.java @@ -16,15 +16,16 @@ import java.util.logging.Logger; /** - * A resource extractor that will attempt to detect the service.name from the - * main jar file name. + * A resource extractor that will attempt to detect the service.name from the main jar + * file name. * *

This class is internal and is hence not for public use. Its APIs are unstable and can change * at any time. */ public final class JarServiceNameResourceExtractor { - private static final Logger logger = Logger.getLogger(JarServiceNameResourceExtractor.class.getName()); + private static final Logger logger = + Logger.getLogger(JarServiceNameResourceExtractor.class.getName()); private final Supplier> jarPathSupplier; diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/MainJarPathFinder.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/MainJarPathFinder.java index 99148e95b716..dec6f642deb4 100644 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/MainJarPathFinder.java +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/MainJarPathFinder.java @@ -14,7 +14,6 @@ import java.util.function.Supplier; import javax.annotation.Nullable; - class MainJarPathFinder { private final Supplier getProcessHandleArguments; private final Function getSystemProperty; diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractor.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractor.java index 1aae397955b7..c2341a3da083 100644 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractor.java +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractor.java @@ -55,8 +55,7 @@ public Resource extract() { return jarPathSupplier .get() .flatMap(manifestReader) - .map( - manifest -> extract(manifest)) + .map(manifest -> extract(manifest)) .orElseGet(Resource::empty); } diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessArguments.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessArguments.java index 9f2e6e4a3350..24ebce1fc1cb 100644 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessArguments.java +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ProcessArguments.java @@ -6,8 +6,8 @@ package io.opentelemetry.instrumentation.resources.internal; /** - * This class is internal and is hence not for public use. Its APIs are unstable and can change - * at any time. + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. */ public final class ProcessArguments { diff --git a/instrumentation/resources/library/src/main/java9/io/opentelemetry/instrumentation/resources/internal/ProcessArguments.java b/instrumentation/resources/library/src/main/java9/io/opentelemetry/instrumentation/resources/internal/ProcessArguments.java index 04155cfed85e..2361d1f14080 100644 --- a/instrumentation/resources/library/src/main/java9/io/opentelemetry/instrumentation/resources/internal/ProcessArguments.java +++ b/instrumentation/resources/library/src/main/java9/io/opentelemetry/instrumentation/resources/internal/ProcessArguments.java @@ -6,8 +6,8 @@ package io.opentelemetry.instrumentation.resources.internal; /** - * This class is internal and is hence not for public use. Its APIs are unstable and can change - * at any time. + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. */ public final class ProcessArguments { diff --git a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractorTest.java b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractorTest.java index b9bf85f780d8..59190321a1b3 100644 --- a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractorTest.java +++ b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractorTest.java @@ -31,7 +31,8 @@ void extractResource_empty() { String[] processArgs = new String[0]; Function getProperty = prop -> null; Predicate fileExists = JarServiceNameResourceExtractorTest::failPath; - JarServiceNameResourceExtractor serviceNameProvider = getFinder(processArgs, getProperty, fileExists); + JarServiceNameResourceExtractor serviceNameProvider = + getFinder(processArgs, getProperty, fileExists); Resource resource = serviceNameProvider.extract(); @@ -58,7 +59,8 @@ void extractResource_noJarFileInArgs() { @Test void extractResource_processHandleJar() { JarServiceNameResourceExtractor serviceNameProvider = - getFinder(getArgs("my-service.jar"), prop -> null, JarServiceNameResourceExtractorTest::failPath); + getFinder( + getArgs("my-service.jar"), prop -> null, JarServiceNameResourceExtractorTest::failPath); Resource resource = serviceNameProvider.extract(); @@ -82,7 +84,8 @@ void extractResource_processHandleJarExtraFlag() { @Test void extractResource_processHandleJarWithoutExtension() { JarServiceNameResourceExtractor serviceNameProvider = - getFinder(getArgs("my-service"), prop -> null, JarServiceNameResourceExtractorTest::failPath); + getFinder( + getArgs("my-service"), prop -> null, JarServiceNameResourceExtractorTest::failPath); Resource resource = serviceNameProvider.extract(); diff --git a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractorTest.java b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractorTest.java index 82e50f2569fc..88d112090f80 100644 --- a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractorTest.java +++ b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractorTest.java @@ -27,11 +27,7 @@ private static class TestCase { private final String expectedVersion; private final InputStream input; - TestCase( - String name, - String expectedName, - String expectedVersion, - InputStream input) { + TestCase(String name, String expectedName, String expectedVersion, InputStream input) { this.name = name; this.expectedName = expectedName; this.expectedVersion = expectedVersion; @@ -42,17 +38,10 @@ private static class TestCase { @TestFactory Collection extractResource() { return Stream.of( - new TestCase( - "name ok", - "demo", - "0.0.1-SNAPSHOT", - openClasspathResource("MANIFEST.MF")), + new TestCase("name ok", "demo", "0.0.1-SNAPSHOT", openClasspathResource("MANIFEST.MF")), new TestCase("name - no resource", null, null, null), new TestCase( - "name - empty resource", - null, - null, - openClasspathResource("empty-MANIFEST.MF"))) + "name - empty resource", null, null, openClasspathResource("empty-MANIFEST.MF"))) .map( t -> DynamicTest.dynamicTest( From a33147fd7c61e5b592b6f22a988cb577f6e3fb82 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 22 Aug 2025 08:19:00 +0200 Subject: [PATCH 17/29] fix --- .../javaagent/bootstrap/AgentClassLoaderTest.groovy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javaagent-bootstrap/src/test/groovy/io/opentelemetry/javaagent/bootstrap/AgentClassLoaderTest.groovy b/javaagent-bootstrap/src/test/groovy/io/opentelemetry/javaagent/bootstrap/AgentClassLoaderTest.groovy index a0a73390d036..27300475fd6e 100644 --- a/javaagent-bootstrap/src/test/groovy/io/opentelemetry/javaagent/bootstrap/AgentClassLoaderTest.groovy +++ b/javaagent-bootstrap/src/test/groovy/io/opentelemetry/javaagent/bootstrap/AgentClassLoaderTest.groovy @@ -56,7 +56,7 @@ class AgentClassLoaderTest extends Specification { def "multi release jar"() { setup: boolean jdk8 = "1.8" == System.getProperty("java.specification.version") - def mrJarClass = Class.forName("io.opentelemetry.instrumentation.resources.ProcessArguments") + def mrJarClass = Class.forName("io.opentelemetry.instrumentation.resources.internal.ProcessArguments") // sdk is a multi release jar URL multiReleaseJar = mrJarClass.getProtectionDomain().getCodeSource().getLocation() AgentClassLoader loader = new AgentClassLoader(new File(multiReleaseJar.toURI())) { @@ -67,7 +67,7 @@ class AgentClassLoaderTest extends Specification { } when: - URL url = loader.findResource("io/opentelemetry/instrumentation/resources/ProcessArguments.class") + URL url = loader.findResource("io/opentelemetry/instrumentation/resources/internal/ProcessArguments.class") then: url != null @@ -75,7 +75,7 @@ class AgentClassLoaderTest extends Specification { jdk8 != url.toString().contains("META-INF/versions/9/") and: - Class clazz = loader.loadClass("io.opentelemetry.instrumentation.resources.ProcessArguments") + Class clazz = loader.loadClass("io.opentelemetry.instrumentation.resources.internal.ProcessArguments") // class was loaded by agent loader used in this test clazz.getClassLoader() == loader Method method = clazz.getDeclaredMethod("getProcessArguments") From 550bc66d24ba701c2acaf610302b3ac563e76925 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 29 Aug 2025 15:39:04 +0200 Subject: [PATCH 18/29] fix rebase --- .../resources/internal/ManifestResourceExtractor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractor.java b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractor.java index c2341a3da083..2fede180f443 100644 --- a/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractor.java +++ b/instrumentation/resources/library/src/main/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractor.java @@ -5,7 +5,7 @@ package io.opentelemetry.instrumentation.resources.internal; -import static java.util.logging.Level.WARNING; +import static java.util.logging.Level.FINE; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.AttributesBuilder; @@ -77,7 +77,7 @@ private static Optional readManifest(Path jarPath) { try (JarFile jarFile = new JarFile(jarPath.toFile(), false)) { return Optional.of(jarFile.getManifest()); } catch (IOException exception) { - logger.log(WARNING, "Error reading manifest", exception); + logger.log(FINE, "Error reading manifest", exception); return Optional.empty(); } } From 77f3fbc3fdea49b24bdb0c54a6249716e219ebb8 Mon Sep 17 00:00:00 2001 From: otelbot <197425009+otelbot@users.noreply.github.com> Date: Fri, 29 Aug 2025 13:42:37 +0000 Subject: [PATCH 19/29] ./gradlew spotlessApply --- .../instrumentation/resources/ManifestResourceProvider.java | 2 -- 1 file changed, 2 deletions(-) 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 c8ba723a9728..927f85e8fe60 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 @@ -5,8 +5,6 @@ package io.opentelemetry.instrumentation.resources; -import static java.util.logging.Level.FINE; - import com.google.auto.service.AutoService; import io.opentelemetry.instrumentation.resources.internal.ManifestResourceExtractor; import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider; From dd2014732e29d63e65410aa8313d8f76b814f636 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 2 Sep 2025 16:14:17 +0200 Subject: [PATCH 20/29] set enabled in test --- .../opentelemetryapi/ResourceTest.java | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 instrumentation/opentelemetry-api/opentelemetry-api-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/ResourceTest.java diff --git a/instrumentation/opentelemetry-api/opentelemetry-api-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/ResourceTest.java b/instrumentation/opentelemetry-api/opentelemetry-api-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/ResourceTest.java new file mode 100644 index 000000000000..9d514ea5d226 --- /dev/null +++ b/instrumentation/opentelemetry-api/opentelemetry-api-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/ResourceTest.java @@ -0,0 +1,64 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.opentelemetryapi; + +import static io.opentelemetry.api.trace.SpanKind.PRODUCER; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; +import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_NAME; +import static io.opentelemetry.semconv.TelemetryAttributes.TELEMETRY_SDK_LANGUAGE; +import static io.opentelemetry.semconv.TelemetryAttributes.TELEMETRY_SDK_NAME; +import static io.opentelemetry.semconv.TelemetryAttributes.TELEMETRY_SDK_VERSION; +import static io.opentelemetry.semconv.incubating.ServiceIncubatingAttributes.SERVICE_INSTANCE_ID; +import static io.opentelemetry.semconv.incubating.TelemetryIncubatingAttributes.TELEMETRY_DISTRO_NAME; +import static io.opentelemetry.semconv.incubating.TelemetryIncubatingAttributes.TELEMETRY_DISTRO_VERSION; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +/** + * Tests the resource providers in javaagent-tooling: DistroComponentProvider + * andResourceCustomizerProvider + */ +class ResourceTest { + + @RegisterExtension + private static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); + + @Test + void distroAndServiceResourceAttributes() { + // When + Tracer tracer = GlobalOpenTelemetry.getTracer("test"); + Span testSpan = tracer.spanBuilder("test").setSpanKind(PRODUCER).startSpan(); + testSpan.end(); + + // Then + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("test") + .hasKind(PRODUCER) + .hasNoParent() + .hasResourceSatisfying( + r -> + r.hasAttributesSatisfyingExactly( + equalTo(TELEMETRY_SDK_LANGUAGE, "java"), + equalTo(TELEMETRY_SDK_NAME, "opentelemetry"), + satisfies(TELEMETRY_SDK_VERSION, v -> v.isNotBlank()), + equalTo(SERVICE_NAME, "unknown_service:java"), + satisfies(SERVICE_INSTANCE_ID, v -> v.isNotBlank()), + equalTo( + TELEMETRY_DISTRO_NAME, + "opentelemetry-java-instrumentation"), + satisfies(TELEMETRY_DISTRO_VERSION, v -> v.isNotBlank()))))); + } +} From b2b21db07f84158bcbfbd55a1cb8f429d2ccbdda Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 5 Sep 2025 09:13:07 +0200 Subject: [PATCH 21/29] add smoke test --- .../opentelemetryapi/ResourceTest.java | 64 ---------------- .../ResourceCustomizerSmokeTest.groovy | 76 +++++++++++++++++++ .../test/resources/declarative-config.yaml | 6 ++ 3 files changed, 82 insertions(+), 64 deletions(-) delete mode 100644 instrumentation/opentelemetry-api/opentelemetry-api-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/ResourceTest.java create mode 100644 smoke-tests/src/test/groovy/io/opentelemetry/smoketest/ResourceCustomizerSmokeTest.groovy create mode 100644 smoke-tests/src/test/resources/declarative-config.yaml diff --git a/instrumentation/opentelemetry-api/opentelemetry-api-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/ResourceTest.java b/instrumentation/opentelemetry-api/opentelemetry-api-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/ResourceTest.java deleted file mode 100644 index 9d514ea5d226..000000000000 --- a/instrumentation/opentelemetry-api/opentelemetry-api-1.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/ResourceTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.opentelemetryapi; - -import static io.opentelemetry.api.trace.SpanKind.PRODUCER; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; -import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_NAME; -import static io.opentelemetry.semconv.TelemetryAttributes.TELEMETRY_SDK_LANGUAGE; -import static io.opentelemetry.semconv.TelemetryAttributes.TELEMETRY_SDK_NAME; -import static io.opentelemetry.semconv.TelemetryAttributes.TELEMETRY_SDK_VERSION; -import static io.opentelemetry.semconv.incubating.ServiceIncubatingAttributes.SERVICE_INSTANCE_ID; -import static io.opentelemetry.semconv.incubating.TelemetryIncubatingAttributes.TELEMETRY_DISTRO_NAME; -import static io.opentelemetry.semconv.incubating.TelemetryIncubatingAttributes.TELEMETRY_DISTRO_VERSION; - -import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.Tracer; -import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; -import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -/** - * Tests the resource providers in javaagent-tooling: DistroComponentProvider - * andResourceCustomizerProvider - */ -class ResourceTest { - - @RegisterExtension - private static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); - - @Test - void distroAndServiceResourceAttributes() { - // When - Tracer tracer = GlobalOpenTelemetry.getTracer("test"); - Span testSpan = tracer.spanBuilder("test").setSpanKind(PRODUCER).startSpan(); - testSpan.end(); - - // Then - testing.waitAndAssertTraces( - trace -> - trace.hasSpansSatisfyingExactly( - span -> - span.hasName("test") - .hasKind(PRODUCER) - .hasNoParent() - .hasResourceSatisfying( - r -> - r.hasAttributesSatisfyingExactly( - equalTo(TELEMETRY_SDK_LANGUAGE, "java"), - equalTo(TELEMETRY_SDK_NAME, "opentelemetry"), - satisfies(TELEMETRY_SDK_VERSION, v -> v.isNotBlank()), - equalTo(SERVICE_NAME, "unknown_service:java"), - satisfies(SERVICE_INSTANCE_ID, v -> v.isNotBlank()), - equalTo( - TELEMETRY_DISTRO_NAME, - "opentelemetry-java-instrumentation"), - satisfies(TELEMETRY_DISTRO_VERSION, v -> v.isNotBlank()))))); - } -} diff --git a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/ResourceCustomizerSmokeTest.groovy b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/ResourceCustomizerSmokeTest.groovy new file mode 100644 index 000000000000..1431c27a8ade --- /dev/null +++ b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/ResourceCustomizerSmokeTest.groovy @@ -0,0 +1,76 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.smoketest + + +import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest +import spock.lang.IgnoreIf +import spock.lang.Unroll + +import java.time.Duration + +import static io.opentelemetry.smoketest.TestContainerManager.useWindowsContainers + +@IgnoreIf({ useWindowsContainers() }) +class ResourceCustomizerSmokeTest extends SmokeTest { + + protected String getTargetImage(String jdk) { + "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-spring-boot:jdk$jdk-20241021.11448062567" + } + + @Override + protected List getExtraResources() { + [ + ResourceMapping.of("declarative-config.yaml", "/declarative-config.yaml"), + ] + } + + @Override + protected Map getExtraEnv() { + return ["OTEL_EXPERIMENTAL_CONFIG_FILE": "declarative-config.yaml"] + } + + @Override + protected TargetWaitStrategy getWaitStrategy() { + return new TargetWaitStrategy.Log(Duration.ofMinutes(1), ".*Started SpringbootApplication in.*") + } + + @Unroll + def "spring boot smoke test on JDK #jdk"(int jdk) { + setup: + startTarget(jdk) + + when: + client().get("/greeting").aggregate().join() + Collection traces = waitForTraces() + + then: "declarative config is applied" + def serviceName = findResourceAttribute(traces, "service.name") + .map { it.stringValue } + .findAny() + serviceName.isPresent() + serviceName.get() == "declarative-config-smoke-test" + + then: "service detector is added by customizer" + def serviceInstanceId = findResourceAttribute(traces, "service.instance.id") + .map { it.stringValue } + .findAny() + serviceInstanceId.isPresent() + + then: "distro detector is added by customizer" + def distroName = findResourceAttribute(traces, "telemetry.distro.name") + .map { it.stringValue } + .findAny() + distroName.isPresent() + serviceName.get() == "opentelemetry-java-instrumentation" + + cleanup: + stopTarget() + + where: + jdk << [8, 11, 17] + } +} diff --git a/smoke-tests/src/test/resources/declarative-config.yaml b/smoke-tests/src/test/resources/declarative-config.yaml new file mode 100644 index 000000000000..d4502f9ada90 --- /dev/null +++ b/smoke-tests/src/test/resources/declarative-config.yaml @@ -0,0 +1,6 @@ +file_format: 1.0-rc.1 +# add extra resource attributes to verify that declarative config is picked up +resource: + attributes: + - name: service.name + value: declarative-config-smoke-test From 194d2cbe387e3dcdf699b159adcc7f9cab49f4d2 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 5 Sep 2025 09:56:46 +0200 Subject: [PATCH 22/29] add smoke test --- .../smoketest/ResourceCustomizerSmokeTest.groovy | 5 ++++- smoke-tests/src/test/resources/declarative-config.yaml | 10 ++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/ResourceCustomizerSmokeTest.groovy b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/ResourceCustomizerSmokeTest.groovy index 1431c27a8ade..68a26ace042c 100644 --- a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/ResourceCustomizerSmokeTest.groovy +++ b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/ResourceCustomizerSmokeTest.groovy @@ -47,6 +47,9 @@ class ResourceCustomizerSmokeTest extends SmokeTest { client().get("/greeting").aggregate().join() Collection traces = waitForTraces() + then: "There is one trace" + traces.size() > 0 + then: "declarative config is applied" def serviceName = findResourceAttribute(traces, "service.name") .map { it.stringValue } @@ -65,7 +68,7 @@ class ResourceCustomizerSmokeTest extends SmokeTest { .map { it.stringValue } .findAny() distroName.isPresent() - serviceName.get() == "opentelemetry-java-instrumentation" + distroName.get() == "opentelemetry-java-instrumentation" cleanup: stopTarget() diff --git a/smoke-tests/src/test/resources/declarative-config.yaml b/smoke-tests/src/test/resources/declarative-config.yaml index d4502f9ada90..be55f1ab6167 100644 --- a/smoke-tests/src/test/resources/declarative-config.yaml +++ b/smoke-tests/src/test/resources/declarative-config.yaml @@ -1,4 +1,14 @@ file_format: 1.0-rc.1 + +tracer_provider: + processors: + - batch: + schedule_delay: 10 + max_export_batch_size: 1 + exporter: + otlp_grpc: + endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT} + # add extra resource attributes to verify that declarative config is picked up resource: attributes: From 03ef3ed3e3355461afe65605a054225c3dcf04bb Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 11 Sep 2025 13:09:14 +0200 Subject: [PATCH 23/29] pr review --- .../instrumentation/resources/JarServiceNameDetector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 490da764ce56..b661d12917ae 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 @@ -15,7 +15,7 @@ import java.util.Map; /** - * A {@link ResourceProvider} that will attempt to detect the service.name from the * + * A {@link ResourceProvider} that will attempt to detect the service.name from the * main jar file name. */ @AutoService(ResourceProvider.class) From db3a54a8afc528e911a44b7454450c9808b457b9 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 11 Sep 2025 13:49:04 +0200 Subject: [PATCH 24/29] pr review --- .../JarServiceNameResourceExtractorTest.java | 16 +++++----- .../ManifestResourceExtractorTest.java | 31 +++++++++---------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractorTest.java b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractorTest.java index 59190321a1b3..0a9596b0f1ce 100644 --- a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractorTest.java +++ b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/JarServiceNameResourceExtractorTest.java @@ -32,14 +32,14 @@ void extractResource_empty() { Function getProperty = prop -> null; Predicate fileExists = JarServiceNameResourceExtractorTest::failPath; JarServiceNameResourceExtractor serviceNameProvider = - getFinder(processArgs, getProperty, fileExists); + getExtractor(processArgs, getProperty, fileExists); Resource resource = serviceNameProvider.extract(); assertThat(resource.getAttributes()).isEmpty(); } - private static JarServiceNameResourceExtractor getFinder( + private static JarServiceNameResourceExtractor getExtractor( String[] processArgs, Function getProperty, Predicate fileExists) { return new JarServiceNameResourceExtractor( new MainJarPathFinder(() -> processArgs, getProperty, fileExists)); @@ -49,7 +49,7 @@ private static JarServiceNameResourceExtractor getFinder( void extractResource_noJarFileInArgs() { String[] args = new String[] {"-Dtest=42", "-Xmx666m", "-jar"}; JarServiceNameResourceExtractor serviceNameProvider = - getFinder(args, prop -> null, JarServiceNameResourceExtractorTest::failPath); + getExtractor(args, prop -> null, JarServiceNameResourceExtractorTest::failPath); Resource resource = serviceNameProvider.extract(); @@ -59,7 +59,7 @@ void extractResource_noJarFileInArgs() { @Test void extractResource_processHandleJar() { JarServiceNameResourceExtractor serviceNameProvider = - getFinder( + getExtractor( getArgs("my-service.jar"), prop -> null, JarServiceNameResourceExtractorTest::failPath); Resource resource = serviceNameProvider.extract(); @@ -71,7 +71,7 @@ void extractResource_processHandleJar() { void extractResource_processHandleJarExtraFlag() { String path = Paths.get("path", "to", "app", "my-service.jar").toString(); JarServiceNameResourceExtractor serviceNameProvider = - getFinder( + getExtractor( new String[] {"-Dtest=42", "-jar", "-Xmx512m", path, "abc", "def"}, prop -> null, JarServiceNameResourceExtractorTest::failPath); @@ -84,7 +84,7 @@ void extractResource_processHandleJarExtraFlag() { @Test void extractResource_processHandleJarWithoutExtension() { JarServiceNameResourceExtractor serviceNameProvider = - getFinder( + getExtractor( getArgs("my-service"), prop -> null, JarServiceNameResourceExtractorTest::failPath); Resource resource = serviceNameProvider.extract(); @@ -105,7 +105,7 @@ void extractResource_sunCommandLine(String commandLine, Path jarPath) { Predicate fileExists = jarPath::equals; JarServiceNameResourceExtractor serviceNameProvider = - getFinder(new String[0], getProperty, fileExists); + getExtractor(new String[0], getProperty, fileExists); Resource resource = serviceNameProvider.extract(); @@ -121,7 +121,7 @@ void extractResource_sunCommandLineProblematicArgs() { Predicate fileExists = path -> false; JarServiceNameResourceExtractor serviceNameProvider = - getFinder(new String[0], getProperty, fileExists); + getExtractor(new String[0], getProperty, fileExists); Resource resource = serviceNameProvider.extract(); diff --git a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractorTest.java b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractorTest.java index 88d112090f80..0aa8544a96cd 100644 --- a/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractorTest.java +++ b/instrumentation/resources/library/src/test/java/io/opentelemetry/instrumentation/resources/internal/ManifestResourceExtractorTest.java @@ -47,23 +47,22 @@ Collection extractResource() { DynamicTest.dynamicTest( t.name, () -> { - ManifestResourceExtractor finder = + Resource resource = new ManifestResourceExtractor( - new MainJarPathFinder( - () -> JarServiceNameResourceExtractorTest.getArgs("app.jar"), - prop -> null, - JarServiceNameResourceExtractorTest::failPath), - p -> { - try { - Manifest manifest = new Manifest(); - manifest.read(t.input); - return Optional.of(manifest); - } catch (Exception e) { - return Optional.empty(); - } - }); - - Resource resource = finder.extract(); + new MainJarPathFinder( + () -> JarServiceNameResourceExtractorTest.getArgs("app.jar"), + prop -> null, + JarServiceNameResourceExtractorTest::failPath), + p -> { + try { + Manifest manifest = new Manifest(); + manifest.read(t.input); + return Optional.of(manifest); + } catch (Exception e) { + return Optional.empty(); + } + }) + .extract(); assertThat(resource.getAttribute(SERVICE_NAME)).isEqualTo(t.expectedName); assertThat(resource.getAttribute(SERVICE_VERSION)) .isEqualTo(t.expectedVersion); From c69a836ae9edb59cb07069b2a0197e5105d937e9 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 11 Sep 2025 13:53:19 +0200 Subject: [PATCH 25/29] pr review --- .../spring/resources/SpringBootServiceNameDetector.java | 2 +- .../spring/resources/SpringBootServiceVersionDetector.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 fa754bdf0816..c54542fdf9f7 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 @@ -75,7 +75,7 @@ public Resource createResource(ConfigProperties config) { return create(); } - public Resource createResource(DeclarativeConfigProperties config) { + Resource createResource(DeclarativeConfigProperties config) { return create(); } 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 4a457a334af6..f888deda2d3f 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 @@ -45,7 +45,7 @@ public Resource createResource(ConfigProperties config) { return create(); } - public Resource createResource(DeclarativeConfigProperties config) { + Resource createResource(DeclarativeConfigProperties config) { return create(); } From a47828ca253b90fb036b0e5bacb957405cf757d8 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 11 Sep 2025 14:01:12 +0200 Subject: [PATCH 26/29] pr review --- .../tooling/resources/ResourceCustomizerProvider.java | 3 --- ...okeTest.groovy => DeclarativeConfigurationSmokeTest.groovy} | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) rename smoke-tests/src/test/groovy/io/opentelemetry/smoketest/{ResourceCustomizerSmokeTest.groovy => DeclarativeConfigurationSmokeTest.groovy} (97%) 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 index 3b7967619f0d..dc9233ca2e45 100644 --- 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 @@ -20,9 +20,6 @@ /** * 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 { diff --git a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/ResourceCustomizerSmokeTest.groovy b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.groovy similarity index 97% rename from smoke-tests/src/test/groovy/io/opentelemetry/smoketest/ResourceCustomizerSmokeTest.groovy rename to smoke-tests/src/test/groovy/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.groovy index 68a26ace042c..921705e57336 100644 --- a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/ResourceCustomizerSmokeTest.groovy +++ b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.groovy @@ -15,7 +15,7 @@ import java.time.Duration import static io.opentelemetry.smoketest.TestContainerManager.useWindowsContainers @IgnoreIf({ useWindowsContainers() }) -class ResourceCustomizerSmokeTest extends SmokeTest { +class DeclarativeConfigurationSmokeTest extends SmokeTest { protected String getTargetImage(String jdk) { "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-spring-boot:jdk$jdk-20241021.11448062567" From 48a4105945a258b1af258e2c553a8869a63d9e7a Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 11 Sep 2025 18:46:38 +0200 Subject: [PATCH 27/29] pr review --- .../resources/DistroComponentProvider.java | 4 ++-- .../tooling/resources/DistroResourceProvider.java | 9 +++------ .../resources/ResourceCustomizerProvider.java | 13 +++++++------ .../DeclarativeConfigurationSmokeTest.groovy | 15 +-------------- 4 files changed, 13 insertions(+), 28 deletions(-) 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 index e9a2d614d404..498b0474863e 100644 --- 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 @@ -21,11 +21,11 @@ public Class getType() { @Override public String getName() { - return "distribution"; + return "opentelemetry-javaagent-distribution"; } @Override public Resource create(DeclarativeConfigProperties config) { - return DistroResourceProvider.get(); + return DistroResourceProvider.get("opentelemetry-javaagent"); } } diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/DistroResourceProvider.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/DistroResourceProvider.java index b2c76e33dacb..782878082ea7 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/DistroResourceProvider.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/resources/DistroResourceProvider.java @@ -20,17 +20,14 @@ public class DistroResourceProvider implements ResourceProvider { @Override public Resource createResource(ConfigProperties config) { - return get(); + return get("opentelemetry-java-instrumentation"); } - static Resource get() { + static Resource get(String distroName) { return AgentVersion.VERSION == null ? Resource.empty() : Resource.create( Attributes.of( - TELEMETRY_DISTRO_NAME, - "opentelemetry-java-instrumentation", - TELEMETRY_DISTRO_VERSION, - AgentVersion.VERSION)); + TELEMETRY_DISTRO_NAME, distroName, TELEMETRY_DISTRO_VERSION, AgentVersion.VERSION)); } } 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 index dc9233ca2e45..0beebe01d112 100644 --- 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 @@ -11,7 +11,7 @@ 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.Collections; import java.util.List; import java.util.Objects; import java.util.Set; @@ -24,11 +24,10 @@ @AutoService(DeclarativeConfigurationCustomizerProvider.class) public class ResourceCustomizerProvider implements DeclarativeConfigurationCustomizerProvider { - // distribution: adds "distro.name" and "distro.version" attributes + // opentelemetry-javaagent-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"); + private static final List REQUIRED_DETECTORS = + Collections.singletonList("opentelemetry-javaagent-distribution"); @Override public void customize(DeclarativeConfigurationCustomizer customizer) { @@ -55,7 +54,9 @@ public void customize(DeclarativeConfigurationCustomizer customizer) { if (!names.contains(name)) { ExperimentalResourceDetectorModel detector = new ExperimentalResourceDetectorModel(); detector.getAdditionalProperties().put(name, null); - detectors.add(detector); + // add first (the least precedence) + // so that the user can add a differently named detector that takes precedence + detectors.add(0, detector); } } return model; diff --git a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.groovy b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.groovy index 921705e57336..464f52272bd6 100644 --- a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.groovy +++ b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.groovy @@ -50,25 +50,12 @@ class DeclarativeConfigurationSmokeTest extends SmokeTest { then: "There is one trace" traces.size() > 0 - then: "declarative config is applied" - def serviceName = findResourceAttribute(traces, "service.name") - .map { it.stringValue } - .findAny() - serviceName.isPresent() - serviceName.get() == "declarative-config-smoke-test" - - then: "service detector is added by customizer" - def serviceInstanceId = findResourceAttribute(traces, "service.instance.id") - .map { it.stringValue } - .findAny() - serviceInstanceId.isPresent() - then: "distro detector is added by customizer" def distroName = findResourceAttribute(traces, "telemetry.distro.name") .map { it.stringValue } .findAny() distroName.isPresent() - distroName.get() == "opentelemetry-java-instrumentation" + distroName.get() == "opentelemetry-javaagent" cleanup: stopTarget() From b808538bbe250f1c5f55307b1cecd6d7a4c60c0b Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 11 Sep 2025 19:02:11 +0200 Subject: [PATCH 28/29] pr review --- .../DeclarativeConfigurationSmokeTest.groovy | 18 +++++++++++++----- .../opentelemetry/smoketest/SmokeTest.groovy | 9 +++++++++ .../src/test/resources/declarative-config.yaml | 5 +++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.groovy b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.groovy index 464f52272bd6..54fd5c6563a0 100644 --- a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.groovy +++ b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.groovy @@ -50,12 +50,20 @@ class DeclarativeConfigurationSmokeTest extends SmokeTest { then: "There is one trace" traces.size() > 0 + then: "explicitly set attribute is present" + hasResourceAttribute(traces, "service.name", "declarative-config-smoke-test") + + then: "explicitly set container detector is used" + findResourceAttribute(traces, "container.id").findAny().isPresent() + + then: "explicitly set container process detector is used" + findResourceAttribute(traces, "process.executable.path").findAny().isPresent() + + then: "explicitly set container host detector is used" + findResourceAttribute(traces, "host.name").findAny().isPresent() + then: "distro detector is added by customizer" - def distroName = findResourceAttribute(traces, "telemetry.distro.name") - .map { it.stringValue } - .findAny() - distroName.isPresent() - distroName.get() == "opentelemetry-javaagent" + hasResourceAttribute(traces, "telemetry.distro.name", "opentelemetry-javaagent") cleanup: stopTarget() diff --git a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/SmokeTest.groovy b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/SmokeTest.groovy index d8bdee7dfa3b..d2f6f53e613f 100644 --- a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/SmokeTest.groovy +++ b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/SmokeTest.groovy @@ -118,6 +118,15 @@ abstract class SmokeTest extends Specification { .map { it.value } } + protected static boolean hasResourceAttribute(Collection traces, + String attributeKey, + String attributeValue) { + return findResourceAttribute(traces, attributeKey) + .filter { it.stringValue == attributeValue } + .findAny() + .isPresent() + } + protected static int countSpansByName(Collection traces, String spanName) { return getSpanStream(traces).filter { it.name == spanName }.count() } diff --git a/smoke-tests/src/test/resources/declarative-config.yaml b/smoke-tests/src/test/resources/declarative-config.yaml index be55f1ab6167..ce39f4c3a830 100644 --- a/smoke-tests/src/test/resources/declarative-config.yaml +++ b/smoke-tests/src/test/resources/declarative-config.yaml @@ -11,6 +11,11 @@ tracer_provider: # add extra resource attributes to verify that declarative config is picked up resource: + detection/development: + detectors: + - container: + - host: + - process: attributes: - name: service.name value: declarative-config-smoke-test From 3a44358731a3d35a2d285b0fdfe5d6938a5889df Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 11 Sep 2025 19:43:56 +0200 Subject: [PATCH 29/29] pr review --- .../tooling/resources/ResourceCustomizerProviderTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 9c4bbe24c94f..5b50cc913437 100644 --- 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 @@ -27,7 +27,7 @@ void customize() { try { assertThat(objectMapper.writeValueAsString(configurationModel.getResource())) .isEqualTo( - "{\"attributes\":[],\"detection/development\":{\"detectors\":[{\"distribution\":null},{\"service\":null}]}}"); + "{\"attributes\":[],\"detection/development\":{\"detectors\":[{\"opentelemetry-javaagent-distribution\":null}]}}"); } catch (JsonProcessingException e) { throw new AssertionError(e); }