From a21685fe6993ffb3ecfadd18965f9f394b6ad240 Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Thu, 12 Feb 2026 14:48:35 +0000 Subject: [PATCH 1/4] Adding a callback to ConfigProvider for runtime instrumentation option changes --- .../api/incubator/config/ConfigProvider.java | 14 ++++++++++++++ .../InstrumentationConfigChangeListener.java | 18 ++++++++++++++++++ .../api/incubator/ConfigProviderTest.java | 4 ++++ 3 files changed, 36 insertions(+) create mode 100644 api/incubator/src/main/java/io/opentelemetry/api/incubator/config/InstrumentationConfigChangeListener.java diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigProvider.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigProvider.java index dcf6c7bd082..9205e9b1354 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigProvider.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigProvider.java @@ -65,6 +65,20 @@ default DeclarativeConfigProperties getGeneralInstrumentationConfig() { return getInstrumentationConfig().get("general"); } + /** + * Registers an {@link InstrumentationConfigChangeListener} to receive updates when instrumentation + * configuration changes. + * + *

The default implementation performs no registration and returns a no-op handle. + * + * @param listener the listener to notify when instrumentation configuration changes + * @return an {@link AutoCloseable} handle that can be closed to unregister the listener + */ + default AutoCloseable addInstrumentationConfigChangeListener( + InstrumentationConfigChangeListener listener) { + return () -> {}; + } + /** Returns a no-op {@link ConfigProvider}. */ static ConfigProvider noop() { return DeclarativeConfigProperties::empty; diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/InstrumentationConfigChangeListener.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/InstrumentationConfigChangeListener.java new file mode 100644 index 00000000000..c80cd18cdaf --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/InstrumentationConfigChangeListener.java @@ -0,0 +1,18 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.config; + +/** Listener notified when instrumentation configuration changes. */ +@FunctionalInterface +public interface InstrumentationConfigChangeListener { + + /** + * Called when instrumentation configuration changes. + * + * @param instrumentationConfig the updated instrumentation configuration + */ + void onChange(DeclarativeConfigProperties instrumentationConfig); +} diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/ConfigProviderTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/ConfigProviderTest.java index b5fdca1cdf6..ce7eab7076e 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/ConfigProviderTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/ConfigProviderTest.java @@ -6,6 +6,7 @@ package io.opentelemetry.api.incubator; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; import io.opentelemetry.api.incubator.config.ConfigProvider; import org.junit.jupiter.api.Test; @@ -24,5 +25,8 @@ void instrumentationConfigFallback() { assertThat(configProvider.getInstrumentationConfig()).isNotNull(); assertThat(configProvider.getInstrumentationConfig("servlet")).isNotNull(); assertThat(configProvider.getGeneralInstrumentationConfig()).isNotNull(); + AutoCloseable listenerRegistration = + configProvider.addInstrumentationConfigChangeListener(config -> {}); + assertThatCode(listenerRegistration::close).doesNotThrowAnyException(); } } From 1b4d51bad13a25b207a168b9ace7956451613663 Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Thu, 12 Feb 2026 15:06:51 +0000 Subject: [PATCH 2/4] correct listener interface --- .../InstrumentationConfigChangeListener.java | 19 ++++++++++++++++--- .../api/incubator/ConfigProviderTest.java | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/InstrumentationConfigChangeListener.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/InstrumentationConfigChangeListener.java index c80cd18cdaf..1e1726722b6 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/InstrumentationConfigChangeListener.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/InstrumentationConfigChangeListener.java @@ -5,14 +5,27 @@ package io.opentelemetry.api.incubator.config; +import javax.annotation.Nullable; + /** Listener notified when instrumentation configuration changes. */ @FunctionalInterface public interface InstrumentationConfigChangeListener { /** - * Called when instrumentation configuration changes. + * Called when the effective config for one top-level instrumentation node changes (for example + * {@code methods}, {@code kafka}, or {@code grpc}). + * + *

Both config arguments are scoped to {@code instrumentationName}. + * + *

{@code newConfig} is never null. If the node is unset or cleared, {@code newConfig} is + * {@link DeclarativeConfigProperties#empty()}. * - * @param instrumentationConfig the updated instrumentation configuration + * @param instrumentationName the top-level instrumentation name that changed + * @param previousConfig the previous effective configuration, or {@code null} if unavailable + * @param newConfig the updated effective configuration for {@code instrumentationName} */ - void onChange(DeclarativeConfigProperties instrumentationConfig); + void onChange( + String instrumentationName, + @Nullable DeclarativeConfigProperties previousConfig, + DeclarativeConfigProperties newConfig); } diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/ConfigProviderTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/ConfigProviderTest.java index ce7eab7076e..de73d93a85c 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/ConfigProviderTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/ConfigProviderTest.java @@ -26,7 +26,7 @@ void instrumentationConfigFallback() { assertThat(configProvider.getInstrumentationConfig("servlet")).isNotNull(); assertThat(configProvider.getGeneralInstrumentationConfig()).isNotNull(); AutoCloseable listenerRegistration = - configProvider.addInstrumentationConfigChangeListener(config -> {}); + configProvider.addInstrumentationConfigChangeListener((name, previous, current) -> {}); assertThatCode(listenerRegistration::close).doesNotThrowAnyException(); } } From 164ea5579dcad6b696bc250983f6def8d74e661b Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Thu, 12 Feb 2026 15:24:33 +0000 Subject: [PATCH 3/4] spotless --- .../io/opentelemetry/api/incubator/config/ConfigProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigProvider.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigProvider.java index 9205e9b1354..0675817ea06 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigProvider.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigProvider.java @@ -66,8 +66,8 @@ default DeclarativeConfigProperties getGeneralInstrumentationConfig() { } /** - * Registers an {@link InstrumentationConfigChangeListener} to receive updates when instrumentation - * configuration changes. + * Registers an {@link InstrumentationConfigChangeListener} to receive updates when + * instrumentation configuration changes. * *

The default implementation performs no registration and returns a no-op handle. * From 39b9c6372420fd02304cb541904d1c51caaaa3df Mon Sep 17 00:00:00 2001 From: Jack Shirazi Date: Mon, 16 Feb 2026 14:08:30 +0000 Subject: [PATCH 4/4] feedback changes --- .../config/ConfigChangeListener.java | 26 ++++++++++++++++ .../config/ConfigChangeRegistration.java | 18 +++++++++++ .../api/incubator/config/ConfigProvider.java | 20 ++++++++---- .../InstrumentationConfigChangeListener.java | 31 ------------------- .../api/incubator/ConfigProviderTest.java | 6 ++-- 5 files changed, 62 insertions(+), 39 deletions(-) create mode 100644 api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigChangeListener.java create mode 100644 api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigChangeRegistration.java delete mode 100644 api/incubator/src/main/java/io/opentelemetry/api/incubator/config/InstrumentationConfigChangeListener.java diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigChangeListener.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigChangeListener.java new file mode 100644 index 00000000000..44833713f8a --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigChangeListener.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.config; + +/** Listener notified when declarative configuration changes. */ +@FunctionalInterface +public interface ConfigChangeListener { + + /** + * Called when the watched path changes. + * + *

{@code path} is the changed declarative configuration path, for example {@code + * .instrumentation/development.general.http} or {@code + * .instrumentation/development.java.methods}. + * + *

{@code newConfig} is never null. If the watched node is unset or cleared, {@code newConfig} + * is {@link DeclarativeConfigProperties#empty()}. + * + * @param path the declarative configuration path that changed + * @param newConfig the updated configuration for the changed path + */ + void onChange(String path, DeclarativeConfigProperties newConfig); +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigChangeRegistration.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigChangeRegistration.java new file mode 100644 index 00000000000..6e499ba11ad --- /dev/null +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigChangeRegistration.java @@ -0,0 +1,18 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.incubator.config; + +/** Registration handle returned by {@link ConfigProvider#addConfigChangeListener}. */ +@FunctionalInterface +public interface ConfigChangeRegistration { + + /** + * Unregister the listener associated with this registration. + * + *

Subsequent calls have no effect. + */ + void close(); +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigProvider.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigProvider.java index 0675817ea06..8617ce6f7ca 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigProvider.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/ConfigProvider.java @@ -66,16 +66,24 @@ default DeclarativeConfigProperties getGeneralInstrumentationConfig() { } /** - * Registers an {@link InstrumentationConfigChangeListener} to receive updates when - * instrumentation configuration changes. + * Registers a {@link ConfigChangeListener} for changes to a specific declarative configuration + * path. + * + *

Example paths include {@code .instrumentation/development.general.http} and {@code + * .instrumentation/development.java.methods}. + * + *

When a watched path changes, {@link ConfigChangeListener#onChange(String, + * DeclarativeConfigProperties)} is invoked with the changed path and updated configuration for + * that path. * *

The default implementation performs no registration and returns a no-op handle. * - * @param listener the listener to notify when instrumentation configuration changes - * @return an {@link AutoCloseable} handle that can be closed to unregister the listener + * @param path the declarative configuration path to watch + * @param listener the listener to notify when the watched path changes + * @return a {@link ConfigChangeRegistration} that can be closed to unregister the listener */ - default AutoCloseable addInstrumentationConfigChangeListener( - InstrumentationConfigChangeListener listener) { + default ConfigChangeRegistration addConfigChangeListener( + String path, ConfigChangeListener listener) { return () -> {}; } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/InstrumentationConfigChangeListener.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/InstrumentationConfigChangeListener.java deleted file mode 100644 index 1e1726722b6..00000000000 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/config/InstrumentationConfigChangeListener.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.api.incubator.config; - -import javax.annotation.Nullable; - -/** Listener notified when instrumentation configuration changes. */ -@FunctionalInterface -public interface InstrumentationConfigChangeListener { - - /** - * Called when the effective config for one top-level instrumentation node changes (for example - * {@code methods}, {@code kafka}, or {@code grpc}). - * - *

Both config arguments are scoped to {@code instrumentationName}. - * - *

{@code newConfig} is never null. If the node is unset or cleared, {@code newConfig} is - * {@link DeclarativeConfigProperties#empty()}. - * - * @param instrumentationName the top-level instrumentation name that changed - * @param previousConfig the previous effective configuration, or {@code null} if unavailable - * @param newConfig the updated effective configuration for {@code instrumentationName} - */ - void onChange( - String instrumentationName, - @Nullable DeclarativeConfigProperties previousConfig, - DeclarativeConfigProperties newConfig); -} diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/ConfigProviderTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/ConfigProviderTest.java index de73d93a85c..43aa3fd0ba0 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/ConfigProviderTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/ConfigProviderTest.java @@ -8,6 +8,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; +import io.opentelemetry.api.incubator.config.ConfigChangeRegistration; import io.opentelemetry.api.incubator.config.ConfigProvider; import org.junit.jupiter.api.Test; @@ -25,8 +26,9 @@ void instrumentationConfigFallback() { assertThat(configProvider.getInstrumentationConfig()).isNotNull(); assertThat(configProvider.getInstrumentationConfig("servlet")).isNotNull(); assertThat(configProvider.getGeneralInstrumentationConfig()).isNotNull(); - AutoCloseable listenerRegistration = - configProvider.addInstrumentationConfigChangeListener((name, previous, current) -> {}); + ConfigChangeRegistration listenerRegistration = + configProvider.addConfigChangeListener( + ".instrumentation/development.java.servlet", (path, newConfig) -> {}); assertThatCode(listenerRegistration::close).doesNotThrowAnyException(); } }