From 4010699f6cd75ee93e5dc3af56d6c827bee53529 Mon Sep 17 00:00:00 2001 From: Rajkaran Yadav Date: Thu, 3 Sep 2026 03:20:46 +0530 Subject: [PATCH 1/2] feat: stabilize ServiceInstanceIdResourceProvider by moving to autoconfigure Move ServiceInstanceIdResourceProvider from incubator to stable autoconfigure module to align with the now-stable service.instance.id semantic convention. Changes: - Add ServiceInstanceIdResourceProvider to autoconfigure module with @since 1.47.0 - Register provider in META-INF/services for autoconfigure SPI discovery - Deprecate incubator ServiceInstanceIdResourceProvider with migration guidance - Update existing tests to accommodate new stable provider behavior - Add comprehensive test coverage for stable provider - Update EnvironmentResourceProvider documentation for provider ordering - Add changelog entry for this stabilization Backward compatibility: - Incubator provider remains functional but deprecated - Existing autoconfigure users automatically get stable provider - Users can override service.instance.id via configuration - Provider order maintained (runs after EnvironmentResourceProvider) Resolves #8410 --- CHANGELOG.md | 5 ++ .../EnvironmentResourceProvider.java | 2 +- .../ServiceInstanceIdResourceProvider.java | 54 +++++++++++++++++++ ...try.sdk.autoconfigure.spi.ResourceProvider | 1 + .../ResourceConfigurationTest.java | 28 ++++++---- ...ServiceInstanceIdResourceProviderTest.java | 52 ++++++++++++++++++ .../ServiceInstanceIdResourceProvider.java | 4 ++ ...ServiceInstanceIdResourceProviderTest.java | 1 + 8 files changed, 135 insertions(+), 12 deletions(-) create mode 100644 sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/resources/ServiceInstanceIdResourceProvider.java create mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/resources/ServiceInstanceIdResourceProviderTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e1687e75c4..047a9f462c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## Unreleased +### Extensions + +* Stabilize `ServiceInstanceIdResourceProvider` by moving from incubator to autoconfigure module + ([#8410](https://github.com/open-telemetry/opentelemetry-java/issues/8410)) + ## Version 1.65.0 (2026-08-07) **NOTE:** The `opentelemetry-exporter-zipkin` artifact has stopped being published. It was diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResourceProvider.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResourceProvider.java index 231967c833c..9b9c7a54803 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResourceProvider.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResourceProvider.java @@ -24,7 +24,7 @@ public Resource createResource(ConfigProperties config) { @Override public int order() { // Environment resource takes precedent over all other ResourceProviders except - // ServiceInstanceIdResourceProvider. + // ServiceInstanceIdResourceProvider (which runs at Integer.MAX_VALUE). return Integer.MAX_VALUE - 1; } } diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/resources/ServiceInstanceIdResourceProvider.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/resources/ServiceInstanceIdResourceProvider.java new file mode 100644 index 00000000000..3d5a16753bd --- /dev/null +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/resources/ServiceInstanceIdResourceProvider.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.autoconfigure.resources; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +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 java.util.UUID; + +/** + * A {@link ConditionalResourceProvider} for {@code service.instance.id}. It implements {@link + * ConditionalResourceProvider} rather than a plain {@link ResourceProvider} because it depends on + * the attributes discovered by the other providers. + * + *

This provider generates a random UUID for {@code service.instance.id} if not already set by + * the user or another resource provider. The value is stable across calls to this provider within + * the same JVM instance. + * + * @since 1.47.0 + */ +public final class ServiceInstanceIdResourceProvider implements ConditionalResourceProvider { + + public static final AttributeKey SERVICE_INSTANCE_ID = + AttributeKey.stringKey("service.instance.id"); + + // multiple calls to this resource provider should return the same value + private static final Resource RANDOM = + Resource.create(Attributes.of(SERVICE_INSTANCE_ID, UUID.randomUUID().toString())); + + static final int ORDER = Integer.MAX_VALUE; + + @Override + public Resource createResource(ConfigProperties config) { + return RANDOM; + } + + @Override + public boolean shouldApply(ConfigProperties config, Resource existing) { + return existing.getAttribute(SERVICE_INSTANCE_ID) == null; + } + + @Override + public int order() { + // Run after environment resource provider - only set the service instance ID if it + // hasn't been set by any other provider or the user. + return ORDER; + } +} diff --git a/sdk-extensions/autoconfigure/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider b/sdk-extensions/autoconfigure/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider index f9bd3554d79..f1f830c9554 100644 --- a/sdk-extensions/autoconfigure/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider +++ b/sdk-extensions/autoconfigure/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider @@ -1 +1,2 @@ io.opentelemetry.sdk.autoconfigure.EnvironmentResourceProvider +io.opentelemetry.sdk.autoconfigure.resources.ServiceInstanceIdResourceProvider diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/ResourceConfigurationTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/ResourceConfigurationTest.java index d8e97e382ca..1b87bbd2072 100644 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/ResourceConfigurationTest.java +++ b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/ResourceConfigurationTest.java @@ -41,17 +41,23 @@ void customConfigResourceWithDisabledKeys() { "otel.resource.attributes", "food=cheesecake,drink=juice,animal= ,color=,shape=square"); props.put("otel.resource.disabled-keys", "drink"); - assertThat( - ResourceConfiguration.configureResource( - DefaultConfigProperties.create(props, componentLoader), - SpiHelper.create(ResourceConfigurationTest.class.getClassLoader()), - (r, c) -> r)) - .isEqualTo( - Resource.getDefault().toBuilder() - .put(stringKey("service.name"), "test-service") - .put("food", "cheesecake") - .put("shape", "square") - .build()); + Resource result = + ResourceConfiguration.configureResource( + DefaultConfigProperties.create(props, componentLoader), + SpiHelper.create(ResourceConfigurationTest.class.getClassLoader()), + (r, c) -> r); + + // Verify expected attributes are present + assertThat(result.getAttribute(stringKey("service.name"))).isEqualTo("test-service"); + assertThat(result.getAttribute(stringKey("food"))).isEqualTo("cheesecake"); + assertThat(result.getAttribute(stringKey("shape"))).isEqualTo("square"); + // Verify disabled attribute is not present + assertThat(result.getAttribute(stringKey("drink"))).isNull(); + // Verify telemetry SDK attributes are present + assertThat(result.getAttribute(stringKey("telemetry.sdk.language"))).isEqualTo("java"); + assertThat(result.getAttribute(stringKey("telemetry.sdk.name"))).isEqualTo("opentelemetry"); + // Verify service.instance.id is now added by default via ServiceInstanceIdResourceProvider + assertThat(result.getAttribute(stringKey("service.instance.id"))).isNotNull(); } @ParameterizedTest diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/resources/ServiceInstanceIdResourceProviderTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/resources/ServiceInstanceIdResourceProviderTest.java new file mode 100644 index 00000000000..5f925921ab8 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/resources/ServiceInstanceIdResourceProviderTest.java @@ -0,0 +1,52 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.autoconfigure.resources; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.google.common.collect.ImmutableMap; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; +import io.opentelemetry.sdk.resources.Resource; +import java.util.Collections; +import java.util.Map; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class ServiceInstanceIdResourceProviderTest { + + @ParameterizedTest + @MethodSource("createResourceTestCases") + void createResource(String expectedValue, Map attributes) { + ServiceInstanceIdResourceProvider provider = new ServiceInstanceIdResourceProvider(); + DefaultConfigProperties config = DefaultConfigProperties.createFromMap(Collections.emptyMap()); + AttributesBuilder builder = Attributes.builder(); + attributes.forEach(builder::put); + Resource existing = Resource.create(builder.build()); + Resource resource = + provider.shouldApply(config, existing) ? provider.createResource(config) : Resource.empty(); + + String actual = + resource.getAttributes().get(ServiceInstanceIdResourceProvider.SERVICE_INSTANCE_ID); + if ("random".equals(expectedValue)) { + assertThat(actual).isNotNull(); + } else { + assertThat(actual).isEqualTo(expectedValue); + } + } + + static Stream createResourceTestCases() { + return Stream.of( + Arguments.argumentSet( + "user provided service.instance.id", + null, + ImmutableMap.of("service.instance.id", "custom")), + Arguments.argumentSet("random value", "random", Collections.emptyMap())); + } +} diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/resources/ServiceInstanceIdResourceProvider.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/resources/ServiceInstanceIdResourceProvider.java index d3cb764c512..030bc6ec6b7 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/resources/ServiceInstanceIdResourceProvider.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/resources/ServiceInstanceIdResourceProvider.java @@ -17,7 +17,11 @@ * A {@link ConditionalResourceProvider} for {@code service.instance.id}. It implements {@link * ConditionalResourceProvider} rather than a plain {@link ResourceProvider} because it depends on * the attributes discovered by the other providers. + * + * @deprecated Use {@link io.opentelemetry.sdk.autoconfigure.resources.ServiceInstanceIdResourceProvider} + * instead. This class will be removed in a future release. */ +@Deprecated public final class ServiceInstanceIdResourceProvider implements ConditionalResourceProvider { public static final AttributeKey SERVICE_INSTANCE_ID = diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/resources/ServiceInstanceIdResourceProviderTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/resources/ServiceInstanceIdResourceProviderTest.java index b359b9fbcf0..9f442606ab8 100644 --- a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/resources/ServiceInstanceIdResourceProviderTest.java +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/resources/ServiceInstanceIdResourceProviderTest.java @@ -23,6 +23,7 @@ class ServiceInstanceIdResourceProviderTest { @ParameterizedTest @MethodSource("createResourceTestCases") + @SuppressWarnings("OtelDeprecatedApiUsage") void createResource(String expectedValue, Map attributes) { ServiceInstanceIdResourceProvider provider = new ServiceInstanceIdResourceProvider(); DefaultConfigProperties config = DefaultConfigProperties.createFromMap(Collections.emptyMap()); From ae2c861d66fd9251ec0e789d82bbc0511756f7c1 Mon Sep 17 00:00:00 2001 From: Rajkaran Yadav Date: Thu, 3 Sep 2026 16:14:34 +0530 Subject: [PATCH 2/2] fix: correct spotless formatting in deprecation comment --- .../resources/ServiceInstanceIdResourceProvider.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/resources/ServiceInstanceIdResourceProvider.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/resources/ServiceInstanceIdResourceProvider.java index 030bc6ec6b7..dd7fc3fe7d9 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/resources/ServiceInstanceIdResourceProvider.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/resources/ServiceInstanceIdResourceProvider.java @@ -18,8 +18,9 @@ * ConditionalResourceProvider} rather than a plain {@link ResourceProvider} because it depends on * the attributes discovered by the other providers. * - * @deprecated Use {@link io.opentelemetry.sdk.autoconfigure.resources.ServiceInstanceIdResourceProvider} - * instead. This class will be removed in a future release. + * @deprecated Use {@link + * io.opentelemetry.sdk.autoconfigure.resources.ServiceInstanceIdResourceProvider} instead. This + * class will be removed in a future release. */ @Deprecated public final class ServiceInstanceIdResourceProvider implements ConditionalResourceProvider {