diff --git a/CHANGELOG.md b/CHANGELOG.md index ccb7a7d3abc5..87b50ea01989 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ ### ⚠️ Breaking Changes +- Rename `otel.experimental.javascript-snippet` to + `otel.instrumentation.servlet.experimental.javascript-snippet` to follow naming conventions + ([#15339](https://github.com/open-telemetry/opentelemetry-java-instrumentation/pull/15339)) + +### ⚠️ Breaking Changes + - ActiveMQ Classic JMX metrics: rename attributes and metrics to align with semantic conventions (see PR description for specifics) ([#14996](https://github.com/open-telemetry/opentelemetry-java-instrumentation/pull/14996)) diff --git a/declarative-config-bridge/build.gradle.kts b/declarative-config-bridge/build.gradle.kts index b5ac9ec9c1c3..e02d15f1c081 100644 --- a/declarative-config-bridge/build.gradle.kts +++ b/declarative-config-bridge/build.gradle.kts @@ -8,6 +8,7 @@ group = "io.opentelemetry.instrumentation" dependencies { compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") + implementation(project(":instrumentation-api")) implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi") implementation("io.opentelemetry:opentelemetry-api-incubator") diff --git a/declarative-config-bridge/src/main/java/io/opentelemetry/instrumentation/config/bridge/ConfigPropertiesDeclarativeConfigProperties.java b/declarative-config-bridge/src/main/java/io/opentelemetry/instrumentation/config/bridge/ConfigPropertiesDeclarativeConfigProperties.java new file mode 100644 index 000000000000..3626bb8de17c --- /dev/null +++ b/declarative-config-bridge/src/main/java/io/opentelemetry/instrumentation/config/bridge/ConfigPropertiesDeclarativeConfigProperties.java @@ -0,0 +1,19 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.config.bridge; + +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.instrumentation.api.internal.BridgedConfigProvider; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; + +public final class ConfigPropertiesDeclarativeConfigProperties { + + private ConfigPropertiesDeclarativeConfigProperties() {} + + public static ConfigProvider create(ConfigProperties configProperties) { + return new BridgedConfigProvider(configProperties::getString); + } +} diff --git a/declarative-config-bridge/src/test/java/io/opentelemetry/instrumentation/config/bridge/ConfigPropertiesDeclarativeConfigPropertiesTest.java b/declarative-config-bridge/src/test/java/io/opentelemetry/instrumentation/config/bridge/ConfigPropertiesDeclarativeConfigPropertiesTest.java new file mode 100644 index 000000000000..238d89fe5aa0 --- /dev/null +++ b/declarative-config-bridge/src/test/java/io/opentelemetry/instrumentation/config/bridge/ConfigPropertiesDeclarativeConfigPropertiesTest.java @@ -0,0 +1,34 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.config.bridge; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import org.junit.jupiter.api.Test; + +class ConfigPropertiesDeclarativeConfigPropertiesTest { + + @Test + void shouldBridgeConfigProperties() { + ConfigProperties configProperties = mock(ConfigProperties.class); + when(configProperties.getString("otel.instrumentation.foo.bar")).thenReturn("baz"); + when(configProperties.getString("otel.instrumentation.experimental.foo.bar")).thenReturn("qux"); + + ConfigProvider configProvider = + ConfigPropertiesDeclarativeConfigProperties.create(configProperties); + DeclarativeConfigProperties properties = configProvider.getInstrumentationConfig(); + + assertThat(properties.getStructured("java").getStructured("foo").getString("bar")) + .isEqualTo("baz"); + assertThat(properties.getStructured("java").getStructured("foo/development").getString("bar")) + .isEqualTo("qux"); + } +} diff --git a/docs/advanced-configuration-options.md b/docs/advanced-configuration-options.md index 537253406497..4ae0e075c5d1 100644 --- a/docs/advanced-configuration-options.md +++ b/docs/advanced-configuration-options.md @@ -45,9 +45,9 @@ This feature is designed for integrating client-side monitoring. We plan to integrate OpenTelemetry's own client-side monitoring solution by default once it's available (see the [browser instrumentation proposal](https://github.com/open-telemetry/community/blob/main/projects/browser-phase-1.md)). -| System property | Environment variable | Purpose | -|--------------------------------------|--------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| otel.experimental.javascript-snippet | OTEL_EXPERIMENTAL_JAVASCRIPT_SNIPPET | Experimental setting to inject a JavaScript snippet into HTML responses after the opening `` tag. The value should be a complete JavaScript snippet including `"` | +| System property | Environment variable | Purpose | +|----------------------------------------------------------------|----------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `otel.instrumentation.servlet.experimental.javascript-snippet` | `OTEL_INSTRUMENTATION_SERVLET_EXPERIMENTAL_JAVASCRIPT_SNIPPET` | Experimental setting to inject a JavaScript snippet into HTML responses after the opening `` tag. The value should be a complete JavaScript snippet including `"` | **Important notes:** diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-api.txt b/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-api.txt index dda7a3ca5e05..787b54ffc48a 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-api.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-instrumentation-api.txt @@ -1,2 +1,5 @@ Comparing source compatibility of opentelemetry-instrumentation-api-2.24.0-SNAPSHOT.jar against opentelemetry-instrumentation-api-2.23.0.jar -No changes. \ No newline at end of file +*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + GENERIC TEMPLATES: === REQUEST:java.lang.Object, === RESPONSE:java.lang.Object + +++ NEW METHOD: PUBLIC(+) STATIC(+) boolean isDeclarativeConfig(io.opentelemetry.api.OpenTelemetry) diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/CommonConfig.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/CommonConfig.java index abf1485fd3c4..4bbdd9335a5a 100644 --- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/CommonConfig.java +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/CommonConfig.java @@ -175,9 +175,8 @@ private static T getFromConfigProviderOrFallback( ValueProvider getFromConfigProvider, T defaultValue, Supplier fallback) { - ConfigProvider configProvider = config.getConfigProvider(); - if (configProvider != null) { - T value = getFromConfigProvider.get(configProvider); + if (config.isDeclarative()) { + T value = getFromConfigProvider.get(config.getConfigProvider()); return value != null ? value : defaultValue; } // fallback doesn't return null, so we can safely call it diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/InstrumentationConfig.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/InstrumentationConfig.java index ab1bb761aa22..3a70371cd393 100644 --- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/InstrumentationConfig.java +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/InstrumentationConfig.java @@ -5,10 +5,13 @@ package io.opentelemetry.instrumentation.api.incubator.config.internal; +import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; import static java.util.Collections.emptyList; import io.opentelemetry.api.incubator.config.ConfigProvider; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; +import io.opentelemetry.instrumentation.api.internal.BridgedConfigProvider; import java.time.Duration; import java.util.List; import java.util.Map; @@ -111,13 +114,13 @@ default List getList(String name) { Map getMap(String name, Map defaultValue); /** Returns {@code true} if declarative configuration is used in this configuration. */ - boolean isDeclarative(); + default boolean isDeclarative() { + return !(getConfigProvider() instanceof BridgedConfigProvider); + } /** * Returns a {@link DeclarativeConfigProperties} for the given node name, which is usually an - * instrumentation name - * - *

Call {@link #isDeclarative()} first to check if declarative configuration is used. + * instrumentation name. If declarative configuration is not used, a bridge to ConfigProperties is * *

Declarative configuration is used to configure instrumentation properties in a declarative * way, such as through YAML or JSON files. @@ -125,15 +128,20 @@ default List getList(String name) { * @param node the name of the instrumentation (e.g. "log4j"), the vendor name (e.g. "google"), or * "common" for common Java settings that don't apply to other languages. * @return the declarative configuration properties for the given node name - * @throws IllegalStateException if {@link #isDeclarative()} returns {@code false} */ - DeclarativeConfigProperties getDeclarativeConfig(String node); + default DeclarativeConfigProperties getDeclarativeConfig(String node) { + DeclarativeConfigProperties config = + InstrumentationConfigUtil.javaInstrumentationConfig(getConfigProvider(), node); + if (config == null) { + // there is no declarative config for this node + return empty(); + } + return config; + } /** - * Returns the {@link ConfigProvider} if declarative configuration is used. - * - * @return the {@link ConfigProvider} or {@code null} if no provider is available + * Returns the {@link ConfigProvider}, which is a bridge to ConfigProperties if declarative + * configuration is not used */ - @Nullable ConfigProvider getConfigProvider(); } diff --git a/instrumentation-api/build.gradle.kts b/instrumentation-api/build.gradle.kts index 3b798b826de2..38dfcbf8a6a5 100644 --- a/instrumentation-api/build.gradle.kts +++ b/instrumentation-api/build.gradle.kts @@ -22,6 +22,7 @@ dependencies { testImplementation("io.opentelemetry.javaagent:opentelemetry-testing-common") testImplementation("io.opentelemetry:opentelemetry-sdk-testing") testImplementation("io.opentelemetry:opentelemetry-exporter-common") + testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") testImplementation("org.junit-pioneer:junit-pioneer") jmhImplementation(project(":instrumentation-api-incubator")) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/InstrumenterBuilder.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/InstrumenterBuilder.java index 422d357349a3..bd0cf9c1570e 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/InstrumenterBuilder.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/InstrumenterBuilder.java @@ -9,7 +9,10 @@ import static java.util.logging.Level.WARNING; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.incubator.ExtendedOpenTelemetry; +import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.api.metrics.MeterBuilder; import io.opentelemetry.api.trace.SpanKind; @@ -20,6 +23,7 @@ import io.opentelemetry.context.propagation.TextMapGetter; import io.opentelemetry.context.propagation.TextMapSetter; import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil; +import io.opentelemetry.instrumentation.api.internal.ConfigProviderUtil; import io.opentelemetry.instrumentation.api.internal.EmbeddedInstrumentationProperties; import io.opentelemetry.instrumentation.api.internal.Experimental; import io.opentelemetry.instrumentation.api.internal.InstrumenterBuilderAccess; @@ -48,11 +52,7 @@ public final class InstrumenterBuilder { private static final Logger logger = Logger.getLogger(InstrumenterBuilder.class.getName()); - - private static final SpanSuppressionStrategy spanSuppressionStrategy = - SpanSuppressionStrategy.fromConfig( - ConfigPropertiesUtil.getString( - "otel.instrumentation.experimental.span-suppression-strategy")); + private static final boolean supportsDeclarativeConfig = supportsDeclarativeConfig(); final OpenTelemetry openTelemetry; final String instrumentationName; @@ -76,6 +76,20 @@ public final class InstrumenterBuilder { boolean propagateOperationListenersToOnEnd = false; boolean enabled = true; + private static boolean supportsDeclarativeConfig() { + try { + Class.forName("io.opentelemetry.api.incubator.ExtendedOpenTelemetry"); + return true; + } catch (ClassNotFoundException e) { + // The incubator module is not available. + // This only happens in OpenTelemetry API instrumentation tests, where an older version of + // OpenTelemetry API is used that does not have ExtendedOpenTelemetry. + // Having the incubator module without ExtendedOpenTelemetry class should still return false + // for those tests to avoid a ClassNotFoundException. + return false; + } + } + static { Experimental.internalAddOperationListenerAttributesExtractor( (builder, operationListenerAttributesExtractor) -> @@ -373,8 +387,19 @@ private String getSchemaUrl() { } SpanSuppressor buildSpanSuppressor() { + // otel.instrumentation.experimental.* doesn't fit the usual pattern of configuration properties + // for instrumentations, so we need to handle both declarative and non-declarative configs here + String value = + isDeclarativeConfig(openTelemetry) + ? InstrumentationConfigUtil.getOrNull( + ConfigProviderUtil.getConfigProvider(GlobalOpenTelemetry.get()), + config -> config.getString("span_suppression_strategy/development"), + "java", + "common") + : ConfigPropertiesUtil.getString( + "otel.instrumentation.experimental.span-suppression-strategy"); return new SpanSuppressors.ByContextKey( - spanSuppressionStrategy.create(getSpanKeysFromAttributesExtractors())); + SpanSuppressionStrategy.fromConfig(value).create(getSpanKeysFromAttributesExtractors())); } private Set getSpanKeysFromAttributesExtractors() { @@ -454,6 +479,11 @@ public void setSpanStatusExtractorCustomizer( } } + /** Returns true if the given OpenTelemetry instance supports Declarative Config. */ + public static boolean isDeclarativeConfig(OpenTelemetry openTelemetry) { + return supportsDeclarativeConfig && openTelemetry instanceof ExtendedOpenTelemetry; + } + private interface InstrumenterConstructor { Instrumenter create(InstrumenterBuilder builder); diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/BridgedConfigProvider.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/BridgedConfigProvider.java new file mode 100644 index 000000000000..675bc803aa09 --- /dev/null +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/BridgedConfigProvider.java @@ -0,0 +1,122 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.internal; + +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.common.ComponentLoader; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import javax.annotation.Nullable; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public final class BridgedConfigProvider implements ConfigProvider { + + private final Function propertySource; + + public BridgedConfigProvider(Function propertySource) { + this.propertySource = propertySource; + } + + @Nullable + @Override + public DeclarativeConfigProperties getInstrumentationConfig() { + return createEmptyDeclarativeConfigProperties( + java -> { + if (java.equals("java")) { + return createEmptyDeclarativeConfigProperties( + name -> new BridgedDeclarativeConfigProperties(name, null, propertySource)); + } + throw new UnsupportedOperationException(); + }); + } + + private static DeclarativeConfigProperties createEmptyDeclarativeConfigProperties( + Function getStructuredFunc) { + return EmptyDeclarativeConfigPropertiesFactory.create(getStructuredFunc); + } + + private static final class EmptyDeclarativeConfigPropertiesFactory { + private EmptyDeclarativeConfigPropertiesFactory() {} + + static DeclarativeConfigProperties create( + Function getStructuredFunc) { + return new InnerDeclarativeConfigProperties(getStructuredFunc); + } + } + + private static final class InnerDeclarativeConfigProperties + implements DeclarativeConfigProperties { + private final Function getStructuredFunc; + + InnerDeclarativeConfigProperties( + Function getStructuredFunc) { + this.getStructuredFunc = getStructuredFunc; + } + + @Nullable + @Override + public String getString(String name) { + throw new UnsupportedOperationException(); + } + + @Nullable + @Override + public Boolean getBoolean(String name) { + throw new UnsupportedOperationException(); + } + + @Nullable + @Override + public Integer getInt(String name) { + throw new UnsupportedOperationException(); + } + + @Nullable + @Override + public Long getLong(String name) { + throw new UnsupportedOperationException(); + } + + @Nullable + @Override + public Double getDouble(String name) { + throw new UnsupportedOperationException(); + } + + @Nullable + @Override + public List getScalarList(String name, Class scalarType) { + throw new UnsupportedOperationException(); + } + + @Nullable + @Override + public DeclarativeConfigProperties getStructured(String name) { + return getStructuredFunc.apply(name); + } + + @Nullable + @Override + public List getStructuredList(String name) { + throw new UnsupportedOperationException(); + } + + @Override + public Set getPropertyKeys() { + throw new UnsupportedOperationException(); + } + + @Override + public ComponentLoader getComponentLoader() { + throw new UnsupportedOperationException(); + } + } +} diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/BridgedDeclarativeConfigProperties.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/BridgedDeclarativeConfigProperties.java new file mode 100644 index 000000000000..08b79e0c79eb --- /dev/null +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/BridgedDeclarativeConfigProperties.java @@ -0,0 +1,158 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.internal; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.common.ComponentLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import javax.annotation.Nullable; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public final class BridgedDeclarativeConfigProperties implements DeclarativeConfigProperties { + private final String node; + @Nullable private final BridgedDeclarativeConfigProperties parent; + private final Function propertySource; + + public BridgedDeclarativeConfigProperties( + String node, + @Nullable BridgedDeclarativeConfigProperties parent, + Function propertySource) { + this.node = node; + this.parent = parent; + this.propertySource = propertySource; + } + + private static List filterBlanksAndNulls(String[] values) { + return Arrays.stream(values) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .collect(Collectors.toList()); + } + + @Nullable + @Override + public String getString(String name) { + return propertySource.apply(getSystemProperty(name)); + } + + @Nullable + @Override + public Boolean getBoolean(String name) { + String value = getString(name); + return value == null ? null : Boolean.parseBoolean(value); + } + + @Nullable + @Override + public Integer getInt(String name) { + String strValue = getString(name); + if (strValue == null) { + return null; + } + try { + return Integer.parseInt(strValue); + } catch (NumberFormatException ignored) { + return null; + } + } + + @Nullable + @Override + public Long getLong(String name) { + String strValue = getString(name); + if (strValue == null) { + return null; + } + try { + return Long.getLong(strValue); + } catch (NumberFormatException ignored) { + return null; + } + } + + @Nullable + @Override + public Double getDouble(String name) { + String strValue = getString(name); + if (strValue == null) { + return null; + } + try { + return Double.parseDouble(strValue); + } catch (NumberFormatException ignored) { + return null; + } + } + + @SuppressWarnings("unchecked") // only String scalar type is supported + @Nullable + @Override + public List getScalarList(String name, Class scalarType) { + if (scalarType != String.class) { + throw new UnsupportedOperationException("Only String scalar type is supported"); + } + + String value = getString(name); + return value == null + ? null + : (List) BridgedDeclarativeConfigProperties.filterBlanksAndNulls(value.split(",")); + } + + @Nullable + @Override + public DeclarativeConfigProperties getStructured(String name) { + return new BridgedDeclarativeConfigProperties(name, this, propertySource); + } + + @Nullable + @Override + public List getStructuredList(String name) { + throw new UnsupportedOperationException(); + } + + @Override + public Set getPropertyKeys() { + throw new UnsupportedOperationException(); + } + + @Override + public ComponentLoader getComponentLoader() { + throw new UnsupportedOperationException(); + } + + private String getSystemProperty(String name) { + List nodes = new ArrayList<>(); + addSystemPropertyPathNodes(nodes); + nodes.add(name); + return toSystemProperty(nodes); + } + + private void addSystemPropertyPathNodes(List parts) { + if (parent != null) { + parent.addSystemPropertyPathNodes(parts); + } + parts.add(node); + } + + static String toSystemProperty(List nodes) { + for (int i = 0; i < nodes.size(); i++) { + String node = nodes.get(i); + if (node.endsWith("/development")) { + String prefix = node.contains("experimental") ? "" : "experimental."; + nodes.set(i, prefix + node.substring(0, node.length() - 12)); + } + } + return "otel.instrumentation." + String.join(".", nodes).replace('_', '-'); + } +} diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ConfigPropertiesUtil.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ConfigPropertiesUtil.java index 862cd6b13588..1a7f3b383031 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ConfigPropertiesUtil.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ConfigPropertiesUtil.java @@ -5,10 +5,7 @@ package io.opentelemetry.instrumentation.api.internal; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.stream.Collectors; +import io.opentelemetry.api.OpenTelemetry; import javax.annotation.Nullable; /** @@ -17,11 +14,25 @@ */ public final class ConfigPropertiesUtil { + /** + * Returns the boolean value of the given property name from system properties and environment + * variables. + * + *

It's recommended to use {@link ConfigProviderUtil#getConfigProvider(OpenTelemetry)} instead + * to support Declarative Config. + */ public static boolean getBoolean(String propertyName, boolean defaultValue) { String strValue = getString(propertyName); return strValue == null ? defaultValue : Boolean.parseBoolean(strValue); } + /** + * Returns the int value of the given property name from system properties and environment + * variables. + * + *

It's recommended to use {@link ConfigProviderUtil#getConfigProvider(OpenTelemetry)} instead + * to support Declarative Config. + */ public static int getInt(String propertyName, int defaultValue) { String strValue = getString(propertyName); if (strValue == null) { @@ -34,37 +45,16 @@ public static int getInt(String propertyName, int defaultValue) { } } + /** + * Returns the string value of the given property name from system properties and environment + * variables. + * + *

It's recommended to use {@link ConfigProviderUtil#getConfigProvider(OpenTelemetry)} instead + * to support Declarative Config. + */ @Nullable public static String getString(String propertyName) { - String value = System.getProperty(propertyName); - if (value != null) { - return value; - } - return System.getenv(toEnvVarName(propertyName)); - } - - public static String getString(String propertyName, String defaultValue) { - String strValue = getString(propertyName); - return strValue == null ? defaultValue : strValue; - } - - public static List getList(String propertyName, List defaultValue) { - String value = getString(propertyName); - if (value == null) { - return defaultValue; - } - return filterBlanksAndNulls(value.split(",")); - } - - private static List filterBlanksAndNulls(String[] values) { - return Arrays.stream(values) - .map(String::trim) - .filter(s -> !s.isEmpty()) - .collect(Collectors.toList()); - } - - private static String toEnvVarName(String propertyName) { - return propertyName.toUpperCase(Locale.ROOT).replace('-', '_').replace('.', '_'); + return ConfigUtil.getString(ConfigUtil.normalizePropertyKey(propertyName)); } private ConfigPropertiesUtil() {} diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ConfigProviderUtil.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ConfigProviderUtil.java new file mode 100644 index 000000000000..9c2fbf2680a5 --- /dev/null +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ConfigProviderUtil.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.internal; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.incubator.ExtendedOpenTelemetry; +import io.opentelemetry.api.incubator.config.ConfigProvider; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public class ConfigProviderUtil { + + static final BridgedConfigProvider BRIDGED_CONFIG_PROVIDER = + new BridgedConfigProvider(ConfigPropertiesUtil::getString); + + /** + * Returns the ConfigProvider from declarative config if supported, otherwise returns a bridged + * ConfigProvider that reads from system properties or environment variables. + */ + public static ConfigProvider getConfigProvider(OpenTelemetry openTelemetry) { + if (openTelemetry instanceof ExtendedOpenTelemetry) { + return ((ExtendedOpenTelemetry) openTelemetry).getConfigProvider(); + } + return BRIDGED_CONFIG_PROVIDER; + } + + private ConfigProviderUtil() {} +} diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ConfigUtil.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ConfigUtil.java new file mode 100644 index 000000000000..701545845fba --- /dev/null +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ConfigUtil.java @@ -0,0 +1,81 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.internal; + +import java.util.ConcurrentModificationException; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; +import javax.annotation.Nullable; + +/** + * Configuration utilities. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + * + *

Copied from SDK + * because some tests target an SDK version where this class does not exist. + */ +final class ConfigUtil { + + private ConfigUtil() {} + + /** + * Returns a copy of system properties which is safe to iterate over. + * + *

In java 8 and android environments, iterating through system properties may trigger {@link + * ConcurrentModificationException}. This method ensures callers can iterate safely without risk + * of exception. See https://github.com/open-telemetry/opentelemetry-java/issues/6732 for details. + */ + public static Properties safeSystemProperties() { + return (Properties) System.getProperties().clone(); + } + + /** + * Return the system property or environment variable for the {@code key}. + * + *

Normalize the {@code key} using {@link #normalizePropertyKey(String)}. Match to system + * property keys also normalized with {@link #normalizePropertyKey(String)}. Match to environment + * variable keys normalized with {@link #normalizeEnvironmentVariableKey(String)}. System + * properties take priority over environment variables. + * + * @param key the property key + * @return the system property if not null, or the environment variable if not null, or {@code + * null} + */ + @Nullable + public static String getString(String key) { + String normalizedKey = normalizePropertyKey(key); + + for (Map.Entry entry : safeSystemProperties().entrySet()) { + if (normalizedKey.equals(normalizePropertyKey(entry.getKey().toString()))) { + return entry.getValue().toString(); + } + } + + for (Map.Entry entry : System.getenv().entrySet()) { + if (normalizedKey.equals(normalizeEnvironmentVariableKey(entry.getKey()))) { + return entry.getValue(); + } + } + + return null; + } + + /** + * Normalize an environment variable key by converting to lower case and replacing "_" with ".". + */ + public static String normalizeEnvironmentVariableKey(String key) { + return key.toLowerCase(Locale.ROOT).replace("_", "."); + } + + /** Normalize a property key by converting to lower case and replacing "-" with ".". */ + public static String normalizePropertyKey(String key) { + return key.toLowerCase(Locale.ROOT).replace("-", "."); + } +} diff --git a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/internal/BridgedDeclarativeConfigPropertiesTest.java b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/internal/BridgedDeclarativeConfigPropertiesTest.java new file mode 100644 index 000000000000..683791c1d888 --- /dev/null +++ b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/internal/BridgedDeclarativeConfigPropertiesTest.java @@ -0,0 +1,27 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.internal; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import org.junit.jupiter.api.Test; + +class BridgedDeclarativeConfigPropertiesTest { + @Test + void toSystemProperty() { + assertThat(BridgedDeclarativeConfigProperties.toSystemProperty(Arrays.asList("a_b", "c", "d"))) + .isEqualTo("otel.instrumentation.a-b.c.d"); + assertThat( + BridgedDeclarativeConfigProperties.toSystemProperty( + Arrays.asList("a_b/development", "c", "d"))) + .isEqualTo("otel.instrumentation.experimental.a-b.c.d"); + assertThat( + BridgedDeclarativeConfigProperties.toSystemProperty( + Arrays.asList("a_experimental_b/development", "c", "d"))) + .isEqualTo("otel.instrumentation.a-experimental-b.c.d"); + } +} diff --git a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/internal/ConfigPropertiesUtilTest.java b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/internal/ConfigPropertiesUtilTest.java index 8a496322b6e0..29e5082fd009 100644 --- a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/internal/ConfigPropertiesUtilTest.java +++ b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/internal/ConfigPropertiesUtilTest.java @@ -55,21 +55,26 @@ void getInt_invalidNumber() { assertThat(ConfigPropertiesUtil.getInt("test.property.int", -1)).isEqualTo(-1); } - @SetEnvironmentVariable(key = "TEST_PROPERTY_BOOLEAN", value = "false") - @SetSystemProperty(key = "test.property.boolean", value = "true") + @SetEnvironmentVariable(key = "OTEL_INSTRUMENTATION_TEST_PROPERTY_BOOLEAN", value = "false") + @SetSystemProperty(key = "otel.instrumentation.test.property.boolean", value = "true") @Test void getBoolean_systemProperty() { - assertThat(ConfigPropertiesUtil.getBoolean("test.property.boolean", false)).isTrue(); + assertBoolean(true); } - @SetEnvironmentVariable(key = "TEST_PROPERTY_BOOLEAN", value = "true") + @SetEnvironmentVariable(key = "OTEL_INSTRUMENTATION_TEST_PROPERTY_BOOLEAN", value = "true") @Test void getBoolean_environmentVariable() { - assertThat(ConfigPropertiesUtil.getBoolean("test.property.boolean", false)).isTrue(); + assertBoolean(true); } @Test void getBoolean_none() { - assertThat(ConfigPropertiesUtil.getBoolean("test.property.boolean", false)).isFalse(); + assertBoolean(false); + } + + private static void assertBoolean(boolean expected) { + assertThat(ConfigPropertiesUtil.getBoolean("otel.instrumentation.test.property.boolean", false)) + .isEqualTo(expected); } } diff --git a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/internal/ConfigProviderUtilTest.java b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/internal/ConfigProviderUtilTest.java new file mode 100644 index 000000000000..d1166cff812c --- /dev/null +++ b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/internal/ConfigProviderUtilTest.java @@ -0,0 +1,201 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.internal; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationBuilder; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLanguageSpecificInstrumentationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.InstrumentationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; +import javax.annotation.Nullable; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junitpioneer.jupiter.SetEnvironmentVariable; +import org.junitpioneer.jupiter.SetSystemProperty; + +class ConfigProviderUtilTest { + @SetEnvironmentVariable(key = "OTEL_INSTRUMENTATION_TEST_PROPERTY_STRING", value = "env_value") + @SetSystemProperty(key = "otel.instrumentation.test.property.string", value = "sys_value") + @Test + void getString_withOpenTelemetry_systemProperty() { + assertString("sys_value"); + } + + @SetEnvironmentVariable(key = "OTEL_INSTRUMENTATION_TEST_PROPERTY_STRING", value = "env_value") + @Test + void getString_withOpenTelemetry_environmentVariable() { + assertString("env_value"); + } + + @Test + void getString_withOpenTelemetry_none() { + assertString(null); + } + + private static void assertString(@Nullable String expected) { + assertThat( + InstrumentationConfigUtil.getOrNull( + ConfigProviderUtil.getConfigProvider(GlobalOpenTelemetry.get()), + config -> config.getString("string"), + "java", + "test", + "property")) + .isEqualTo(expected); + } + + public static Stream stringValuesProvider() { + return Stream.of( + Arguments.of("value1", "value1"), + Arguments.of("", ""), + Arguments.of(null, null), + Arguments.of(123, null), // no type coercion in declarative config + Arguments.of(true, null)); // no type coercion in declarative config + } + + @ParameterizedTest + @MethodSource("stringValuesProvider") + void getString_declarativeConfig(Object property, String expected) { + assertThat( + InstrumentationConfigUtil.getOrNull( + ConfigProviderUtil.getConfigProvider( + DeclarativeConfiguration.create(model(property))), + config -> config.getString("bar"), + "java", + "foo")) + .isEqualTo(expected); + } + + @SetEnvironmentVariable(key = "OTEL_INSTRUMENTATION_TEST_PROPERTY_BOOLEAN", value = "false") + @SetSystemProperty(key = "otel.instrumentation.test.property.boolean", value = "true") + @Test + void getBoolean_systemProperty() { + assertBoolean(true); + } + + @SetEnvironmentVariable(key = "OTEL_INSTRUMENTATION_TEST_PROPERTY_BOOLEAN", value = "true") + @Test + void getBoolean_environmentVariable() { + assertBoolean(true); + } + + @Test + void getBoolean_none() { + assertBoolean(false); + } + + private static void assertBoolean(boolean expected) { + assertThat( + Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + ConfigProviderUtil.getConfigProvider(GlobalOpenTelemetry.get()), + config -> config.getBoolean("boolean"), + "java", + "test", + "property")) + .orElse(false)) + .isEqualTo(expected); + } + + public static Stream booleanValuesProvider() { + return Stream.of( + Arguments.of(true, true), + Arguments.of(false, false), + Arguments.of("invalid", null), + Arguments.of("true", null), // no type coercion in declarative config + Arguments.of(null, null)); + } + + @ParameterizedTest + @MethodSource("booleanValuesProvider") + void getBoolean_declarativeConfig(@Nullable Object property, @Nullable Boolean expected) { + assertThat( + InstrumentationConfigUtil.getOrNull( + ConfigProviderUtil.getConfigProvider( + DeclarativeConfiguration.create(model(property))), + config -> config.getBoolean("bar"), + "java", + "foo")) + .isEqualTo(expected); + } + + @SetEnvironmentVariable(key = "OTEL_INSTRUMENTATION_TEST_PROPERTY_LIST", value = "a,b,c") + @SetSystemProperty(key = "otel.instrumentation.test.property.list", value = "x,y,z") + @Test + void getList_systemProperty() { + assertList(asList("x", "y", "z")); + } + + @SetEnvironmentVariable(key = "OTEL_INSTRUMENTATION_TEST_PROPERTY_LIST", value = "a,b,c") + @Test + void getList_environmentVariable() { + assertList(asList("a", "b", "c")); + } + + @Test + void getList_none() { + assertList(null); + } + + private static void assertList(@Nullable List expected) { + assertThat( + InstrumentationConfigUtil.>getOrNull( + ConfigProviderUtil.getConfigProvider(OpenTelemetry.noop()), + config -> config.getScalarList("list", String.class), + "java", + "test", + "property")) + .isEqualTo(expected); + } + + public static Stream listValuesProvider() { + return Stream.of( + Arguments.of(asList("a", "b", "c"), asList("a", "b", "c")), + Arguments.of(singletonList("single"), singletonList("single")), + Arguments.of(emptyList(), emptyList()), + Arguments.of("invalid", null), + Arguments.of(null, null)); + } + + @ParameterizedTest + @MethodSource("listValuesProvider") + void getList_declarativeConfig(@Nullable Object property, @Nullable List expected) { + assertThat( + InstrumentationConfigUtil.>getOrNull( + ConfigProviderUtil.getConfigProvider( + DeclarativeConfiguration.create(model(property))), + config -> config.getScalarList("bar", String.class), + "java", + "foo")) + .isEqualTo(expected); + } + + private static OpenTelemetryConfigurationModel model(@Nullable Object value) { + return new DeclarativeConfigurationBuilder() + .customizeModel( + new OpenTelemetryConfigurationModel() + .withFileFormat("1.0-rc.1") + .withInstrumentationDevelopment( + new InstrumentationModel() + .withJava( + new ExperimentalLanguageSpecificInstrumentationModel() + .withAdditionalProperty( + "foo", Collections.singletonMap("bar", value))))); + } +} diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/autoconfigure/TracingRequestHandler.java b/instrumentation/aws-sdk/aws-sdk-1.11/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/autoconfigure/TracingRequestHandler.java index 2d92c041c0be..6a1050eaa46d 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/autoconfigure/TracingRequestHandler.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/autoconfigure/TracingRequestHandler.java @@ -12,27 +12,50 @@ import com.amazonaws.Response; import com.amazonaws.handlers.RequestHandler2; import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; +import io.opentelemetry.instrumentation.api.internal.ConfigProviderUtil; import io.opentelemetry.instrumentation.awssdk.v1_11.AwsSdkTelemetry; +import java.util.Optional; /** * A {@link RequestHandler2} for use as an SPI by the AWS SDK to automatically trace all requests. */ public class TracingRequestHandler extends RequestHandler2 { - private static final RequestHandler2 DELEGATE = - AwsSdkTelemetry.builder(GlobalOpenTelemetry.get()) - .setCaptureExperimentalSpanAttributes( - ConfigPropertiesUtil.getBoolean( - "otel.instrumentation.aws-sdk.experimental-span-attributes", false)) - .setMessagingReceiveInstrumentationEnabled( - ConfigPropertiesUtil.getBoolean( - "otel.instrumentation.messaging.experimental.receive-telemetry.enabled", false)) - .setCapturedHeaders( - ConfigPropertiesUtil.getList( - "otel.instrumentation.messaging.experimental.capture-headers", emptyList())) - .build() - .newRequestHandler(); + private static final RequestHandler2 DELEGATE = buildDelegate(GlobalOpenTelemetry.get()); + + private static RequestHandler2 buildDelegate(OpenTelemetry openTelemetry) { + ConfigProvider configProvider = ConfigProviderUtil.getConfigProvider(openTelemetry); + return AwsSdkTelemetry.builder(openTelemetry) + .setCaptureExperimentalSpanAttributes( + Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + configProvider, + config -> config.getBoolean("span_attributes/development"), + "java", + "aws_sdk")) + .orElse(false)) + .setMessagingReceiveInstrumentationEnabled( + Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + configProvider, + config -> config.getBoolean("messaging.receive_telemetry/development"), + "java", + "aws_sdk")) + .orElse(false)) + .setCapturedHeaders( + Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + configProvider, + config -> config.getScalarList("capture_headers/development", String.class), + "java", + "messaging")) + .orElse(emptyList())) + .build() + .newRequestHandler(); + } @Override public void beforeRequest(Request request) { diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v2_2/AwsSdkSingletons.java b/instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v2_2/AwsSdkSingletons.java index f84cd5590e99..71515697275e 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v2_2/AwsSdkSingletons.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/awssdk/v2_2/AwsSdkSingletons.java @@ -5,6 +5,7 @@ package io.opentelemetry.javaagent.instrumentation.awssdk.v2_2; +import io.opentelemetry.api.incubator.config.ConfigProvider; import io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkTelemetry; import io.opentelemetry.instrumentation.awssdk.v2_2.internal.AbstractAwsSdkTelemetryFactory; import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; @@ -20,7 +21,6 @@ public static AwsSdkTelemetry telemetry() { } private static class AwsSdkTelemetryFactory extends AbstractAwsSdkTelemetryFactory { - @Override protected List getCapturedHeaders() { return ExperimentalConfig.get().getMessagingHeaders(); @@ -32,8 +32,8 @@ protected boolean messagingReceiveInstrumentationEnabled() { } @Override - protected boolean getBoolean(String name, boolean defaultValue) { - return AgentInstrumentationConfig.get().getBoolean(name, defaultValue); + protected ConfigProvider getConfigProvider() { + return AgentInstrumentationConfig.get().getConfigProvider(); } } diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/autoconfigure/AwsSdkSingletons.java b/instrumentation/aws-sdk/aws-sdk-2.2/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/autoconfigure/AwsSdkSingletons.java index 089757bea505..b3a01c7ed343 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/autoconfigure/AwsSdkSingletons.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/autoconfigure/AwsSdkSingletons.java @@ -7,10 +7,14 @@ import static java.util.Collections.emptyList; -import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; +import io.opentelemetry.instrumentation.api.internal.ConfigProviderUtil; import io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkTelemetry; import io.opentelemetry.instrumentation.awssdk.v2_2.internal.AbstractAwsSdkTelemetryFactory; import java.util.List; +import java.util.Optional; public final class AwsSdkSingletons { @@ -24,19 +28,29 @@ private static class AwsSdkTelemetryFactory extends AbstractAwsSdkTelemetryFacto @Override protected List getCapturedHeaders() { - return ConfigPropertiesUtil.getList( - "otel.instrumentation.messaging.experimental.capture-headers", emptyList()); + return Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + ConfigProviderUtil.getConfigProvider(GlobalOpenTelemetry.get()), + config -> config.getScalarList("capture_headers/development", String.class), + "java", + "messaging")) + .orElse(emptyList()); } @Override protected boolean messagingReceiveInstrumentationEnabled() { - return ConfigPropertiesUtil.getBoolean( - "otel.instrumentation.messaging.experimental.receive-telemetry.enabled", false); + return Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + getConfigProvider(), + config -> config.getBoolean("messaging.receive_telemetry/development"), + "java", + "aws_sdk")) + .orElse(false); } @Override - protected boolean getBoolean(String name, boolean defaultValue) { - return ConfigPropertiesUtil.getBoolean(name, defaultValue); + protected ConfigProvider getConfigProvider() { + return ConfigProviderUtil.getConfigProvider(GlobalOpenTelemetry.get()); } } diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AbstractAwsSdkTelemetryFactory.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AbstractAwsSdkTelemetryFactory.java index 574c8e214ef9..bbb388640dc5 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AbstractAwsSdkTelemetryFactory.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AbstractAwsSdkTelemetryFactory.java @@ -6,8 +6,11 @@ package io.opentelemetry.instrumentation.awssdk.v2_2.internal; import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; import io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkTelemetry; import java.util.List; +import java.util.Optional; /** * This class is internal and is hence not for public use. Its APIs are unstable and can change at @@ -17,26 +20,48 @@ public abstract class AbstractAwsSdkTelemetryFactory { protected abstract List getCapturedHeaders(); private boolean captureExperimentalSpanAttributes() { - return getBoolean("otel.instrumentation.aws-sdk.experimental-span-attributes", false); + return Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + getConfigProvider(), + config -> config.getBoolean("span_attributes/development"), + "java", + "aws_sdk")) + .orElse(false); } protected abstract boolean messagingReceiveInstrumentationEnabled(); private boolean useMessagingPropagator() { - return getBoolean( - "otel.instrumentation.aws-sdk.experimental-use-propagator-for-messaging", false); + return Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + getConfigProvider(), + config -> config.getBoolean("use_propagator_for_messaging/development"), + "java", + "aws_sdk")) + .orElse(false); } private boolean recordIndividualHttpError() { - return getBoolean( - "otel.instrumentation.aws-sdk.experimental-record-individual-http-error", false); + return Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + getConfigProvider(), + config -> config.getBoolean("record_individual_http_error/development"), + "java", + "aws_sdk")) + .orElse(false); } private boolean genaiCaptureMessageContent() { - return getBoolean("otel.instrumentation.genai.capture-message-content", false); + return Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + getConfigProvider(), + config -> config.getBoolean("capture_message_content"), + "java", + "genai")) + .orElse(false); } - protected abstract boolean getBoolean(String name, boolean defaultValue); + protected abstract ConfigProvider getConfigProvider(); public AwsSdkTelemetry telemetry() { return AwsSdkTelemetry.builder(GlobalOpenTelemetry.get()) diff --git a/instrumentation/external-annotations/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/extannotations/IncludeTest.java b/instrumentation/external-annotations/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/extannotations/IncludeTest.java index 9f717b107392..7a20e8f1957b 100644 --- a/instrumentation/external-annotations/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/extannotations/IncludeTest.java +++ b/instrumentation/external-annotations/javaagent-unit-tests/src/test/java/io/opentelemetry/javaagent/instrumentation/extannotations/IncludeTest.java @@ -9,6 +9,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import java.util.Arrays; import java.util.Collections; @@ -27,10 +28,13 @@ class IncludeTest { @Mock InstrumentationConfig config; + @Mock DeclarativeConfigProperties externalAnnotationsConfig; + @ParameterizedTest @MethodSource("provideArguments") void testConfiguration(String value, List expected) { - when(config.getString("otel.instrumentation.external-annotations.include")).thenReturn(value); + when(config.getDeclarativeConfig("external-annotations")).thenReturn(externalAnnotationsConfig); + when(externalAnnotationsConfig.getString("include")).thenReturn(value); assertThat(ExternalAnnotationInstrumentation.configureAdditionalTraceAnnotations(config)) .isEqualTo(new HashSet<>(expected)); diff --git a/instrumentation/external-annotations/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extannotations/ExternalAnnotationInstrumentation.java b/instrumentation/external-annotations/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extannotations/ExternalAnnotationInstrumentation.java index 5c39fc2bcbb2..0386a4865c1e 100644 --- a/instrumentation/external-annotations/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extannotations/ExternalAnnotationInstrumentation.java +++ b/instrumentation/external-annotations/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/extannotations/ExternalAnnotationInstrumentation.java @@ -67,11 +67,6 @@ public class ExternalAnnotationInstrumentation implements TypeInstrumentation { "kamon.annotation.api.Trace", "org.springframework.cloud.sleuth.annotation.NewSpan"); - private static final String TRACE_ANNOTATIONS_CONFIG = - "otel.instrumentation.external-annotations.include"; - private static final String TRACE_ANNOTATED_METHODS_EXCLUDE_CONFIG = - "otel.instrumentation.external-annotations.exclude-methods"; - private final ElementMatcher.Junction classLoaderOptimization; private final ElementMatcher.Junction traceAnnotationMatcher; @@ -116,7 +111,7 @@ public void transform(TypeTransformer transformer) { // visible for testing static Set configureAdditionalTraceAnnotations(InstrumentationConfig config) { - String configString = config.getString(TRACE_ANNOTATIONS_CONFIG); + String configString = config.getDeclarativeConfig("external-annotations").getString("include"); if (configString == null) { return Collections.unmodifiableSet(new HashSet<>(DEFAULT_ANNOTATIONS)); } else if (configString.isEmpty()) { @@ -148,7 +143,9 @@ private static ElementMatcher.Junction configureExcludedMetho Map> excludedMethods = MethodsConfigurationParser.parse( - AgentInstrumentationConfig.get().getString(TRACE_ANNOTATED_METHODS_EXCLUDE_CONFIG)); + AgentInstrumentationConfig.get() + .getDeclarativeConfig("external-annotations") + .getString("exclude-methods")); for (Map.Entry> entry : excludedMethods.entrySet()) { String className = entry.getKey(); ElementMatcher.Junction classMather = diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriver.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriver.java index 617da2b99f03..ea947fd4a679 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriver.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/OpenTelemetryDriver.java @@ -23,9 +23,11 @@ import static io.opentelemetry.instrumentation.jdbc.internal.JdbcInstrumenterFactory.INSTRUMENTATION_NAME; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; import io.opentelemetry.instrumentation.api.incubator.semconv.db.internal.SqlCommenter; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; -import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil; +import io.opentelemetry.instrumentation.api.internal.ConfigProviderUtil; import io.opentelemetry.instrumentation.api.internal.EmbeddedInstrumentationProperties; import io.opentelemetry.instrumentation.jdbc.internal.DbRequest; import io.opentelemetry.instrumentation.jdbc.internal.JdbcConnectionUrlParser; @@ -42,6 +44,7 @@ import java.util.Collections; import java.util.Enumeration; import java.util.List; +import java.util.Optional; import java.util.Properties; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicBoolean; @@ -63,14 +66,29 @@ public final class OpenTelemetryDriver implements Driver { private static final AtomicBoolean REGISTERED = new AtomicBoolean(); private static final List DRIVER_CANDIDATES = new CopyOnWriteArrayList<>(); - private static final SqlCommenter sqlCommenter = - SqlCommenter.builder() - .setEnabled( - ConfigPropertiesUtil.getBoolean( - "otel.instrumentation.jdbc.experimental.sqlcommenter.enabled", - ConfigPropertiesUtil.getBoolean( - "otel.instrumentation.common.experimental.db-sqlcommenter.enabled", false))) - .build(); + private static SqlCommenter getSqlCommenter(OpenTelemetry openTelemetry) { + ConfigProvider configProvider = ConfigProviderUtil.getConfigProvider(openTelemetry); + boolean defaultValue = + Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + configProvider, + config -> config.getBoolean("enabled"), + "java", + "common", + "db_sqlcommenter/development")) + .orElse(false); + return SqlCommenter.builder() + .setEnabled( + Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + configProvider, + config -> config.getBoolean("enabled"), + "java", + "jdbc", + "sqlcommenter/development")) + .orElse(defaultValue)) + .build(); + } static { try { @@ -256,7 +274,7 @@ public Connection connect(String url, Properties info) throws SQLException { Instrumenter statementInstrumenter = JdbcInstrumenterFactory.createStatementInstrumenter(openTelemetry); - boolean captureQueryParameters = JdbcInstrumenterFactory.captureQueryParameters(); + boolean captureQueryParameters = JdbcInstrumenterFactory.captureQueryParameters(openTelemetry); Instrumenter transactionInstrumenter = JdbcInstrumenterFactory.createTransactionInstrumenter(openTelemetry); @@ -266,7 +284,7 @@ public Connection connect(String url, Properties info) throws SQLException { statementInstrumenter, transactionInstrumenter, captureQueryParameters, - sqlCommenter); + getSqlCommenter(openTelemetry)); } @Override diff --git a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/JdbcInstrumenterFactory.java b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/JdbcInstrumenterFactory.java index 9748181d713e..a77f8d912041 100644 --- a/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/JdbcInstrumenterFactory.java +++ b/instrumentation/jdbc/library/src/main/java/io/opentelemetry/instrumentation/jdbc/internal/JdbcInstrumenterFactory.java @@ -8,6 +8,7 @@ import static java.util.Collections.emptyList; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesExtractor; import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeSpanNameExtractor; import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientMetrics; @@ -16,9 +17,10 @@ import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor; -import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil; +import io.opentelemetry.instrumentation.api.internal.ConfigProviderUtil; import io.opentelemetry.instrumentation.jdbc.internal.dbinfo.DbInfo; import java.util.List; +import java.util.Optional; import javax.sql.DataSource; /** @@ -28,14 +30,19 @@ public final class JdbcInstrumenterFactory { public static final String INSTRUMENTATION_NAME = "io.opentelemetry.jdbc"; - public static boolean captureQueryParameters() { - return ConfigPropertiesUtil.getBoolean( - "otel.instrumentation.jdbc.experimental.capture-query-parameters", false); + public static boolean captureQueryParameters(OpenTelemetry openTelemetry) { + return Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + ConfigProviderUtil.getConfigProvider(openTelemetry), + config -> config.getBoolean("capture_query_parameters/development"), + "java", + "jdbc")) + .orElse(false); } public static Instrumenter createStatementInstrumenter( OpenTelemetry openTelemetry) { - return createStatementInstrumenter(openTelemetry, captureQueryParameters()); + return createStatementInstrumenter(openTelemetry, captureQueryParameters(openTelemetry)); } static Instrumenter createStatementInstrumenter( @@ -44,8 +51,14 @@ static Instrumenter createStatementInstrumenter( openTelemetry, emptyList(), true, - ConfigPropertiesUtil.getBoolean( - "otel.instrumentation.common.db-statement-sanitizer.enabled", true), + Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + ConfigProviderUtil.getConfigProvider(openTelemetry), + config -> config.getBoolean("enabled"), + "java", + "common", + "db_statement_sanitizer")) + .orElse(true), captureQueryParameters); } @@ -94,8 +107,14 @@ public static Instrumenter createTransactionInstrumenter( OpenTelemetry openTelemetry) { return createTransactionInstrumenter( openTelemetry, - ConfigPropertiesUtil.getBoolean( - "otel.instrumentation.jdbc.experimental.transaction.enabled", false)); + Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + ConfigProviderUtil.getConfigProvider(openTelemetry), + config -> config.getBoolean("enabled"), + "java", + "jdbc", + "transaction/development")) + .orElse(false)); } public static Instrumenter createTransactionInstrumenter( diff --git a/instrumentation/kafka/kafka-clients/kafka-clients-2.6/library/src/main/java/io/opentelemetry/instrumentation/kafkaclients/v2_6/TracingConsumerInterceptor.java b/instrumentation/kafka/kafka-clients/kafka-clients-2.6/library/src/main/java/io/opentelemetry/instrumentation/kafkaclients/v2_6/TracingConsumerInterceptor.java index 96c040074088..15f1d309a7b7 100644 --- a/instrumentation/kafka/kafka-clients/kafka-clients-2.6/library/src/main/java/io/opentelemetry/instrumentation/kafkaclients/v2_6/TracingConsumerInterceptor.java +++ b/instrumentation/kafka/kafka-clients/kafka-clients-2.6/library/src/main/java/io/opentelemetry/instrumentation/kafkaclients/v2_6/TracingConsumerInterceptor.java @@ -9,13 +9,17 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; import io.opentelemetry.context.Context; -import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil; +import io.opentelemetry.instrumentation.api.internal.ConfigProviderUtil; import io.opentelemetry.instrumentation.api.internal.Timer; import io.opentelemetry.instrumentation.kafkaclients.common.v0_11.internal.KafkaConsumerContext; import io.opentelemetry.instrumentation.kafkaclients.common.v0_11.internal.KafkaConsumerContextUtil; import java.util.Map; import java.util.Objects; +import java.util.Optional; import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.clients.consumer.ConsumerInterceptor; import org.apache.kafka.clients.consumer.ConsumerRecords; @@ -32,15 +36,33 @@ @Deprecated public class TracingConsumerInterceptor implements ConsumerInterceptor { - private static final KafkaTelemetry telemetry = - KafkaTelemetry.builder(GlobalOpenTelemetry.get()) - .setMessagingReceiveInstrumentationEnabled( - ConfigPropertiesUtil.getBoolean( - "otel.instrumentation.messaging.experimental.receive-telemetry.enabled", false)) - .setCapturedHeaders( - ConfigPropertiesUtil.getList( - "otel.instrumentation.messaging.experimental.capture-headers", emptyList())) - .build(); + private static final KafkaTelemetry telemetry; + + static { + OpenTelemetry openTelemetry = GlobalOpenTelemetry.get(); + ConfigProvider configProvider = ConfigProviderUtil.getConfigProvider(openTelemetry); + telemetry = + KafkaTelemetry.builder(openTelemetry) + .setMessagingReceiveInstrumentationEnabled( + Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + configProvider, + config -> config.getBoolean("enabled"), + "java", + "messaging", + "receive_telemetry/development")) + .orElse(false)) + .setCapturedHeaders( + Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + configProvider, + config -> + config.getScalarList("capture_headers/development", String.class), + "java", + "messaging")) + .orElse(emptyList())) + .build(); + } private String consumerGroup; private String clientId; diff --git a/instrumentation/kafka/kafka-clients/kafka-clients-2.6/library/src/main/java/io/opentelemetry/instrumentation/kafkaclients/v2_6/TracingProducerInterceptor.java b/instrumentation/kafka/kafka-clients/kafka-clients-2.6/library/src/main/java/io/opentelemetry/instrumentation/kafkaclients/v2_6/TracingProducerInterceptor.java index 007e1df51d4b..503124bb16fe 100644 --- a/instrumentation/kafka/kafka-clients/kafka-clients-2.6/library/src/main/java/io/opentelemetry/instrumentation/kafkaclients/v2_6/TracingProducerInterceptor.java +++ b/instrumentation/kafka/kafka-clients/kafka-clients-2.6/library/src/main/java/io/opentelemetry/instrumentation/kafkaclients/v2_6/TracingProducerInterceptor.java @@ -9,9 +9,12 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; +import io.opentelemetry.instrumentation.api.internal.ConfigProviderUtil; import java.util.Map; import java.util.Objects; +import java.util.Optional; import javax.annotation.Nullable; import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.clients.producer.ProducerInterceptor; @@ -28,12 +31,24 @@ @Deprecated public class TracingProducerInterceptor implements ProducerInterceptor { - private static final KafkaTelemetry telemetry = - KafkaTelemetry.builder(GlobalOpenTelemetry.get()) - .setCapturedHeaders( - ConfigPropertiesUtil.getList( - "otel.instrumentation.messaging.experimental.capture-headers", emptyList())) - .build(); + private static final KafkaTelemetry telemetry; + + static { + OpenTelemetry openTelemetry = GlobalOpenTelemetry.get(); + telemetry = + KafkaTelemetry.builder(openTelemetry) + .setCapturedHeaders( + Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + ConfigProviderUtil.getConfigProvider(openTelemetry), + config -> + config.getScalarList("capture_headers/development", String.class), + "java", + "messaging")) + .orElse(emptyList())) + .build(); + ; + } @Nullable private String clientId; diff --git a/instrumentation/log4j/log4j-context-data/log4j-context-data-2.17/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/log4j/contextdata/v2_17/OpenTelemetryContextDataProvider.java b/instrumentation/log4j/log4j-context-data/log4j-context-data-2.17/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/log4j/contextdata/v2_17/OpenTelemetryContextDataProvider.java index 57024ded7c3c..3421afe3e291 100644 --- a/instrumentation/log4j/log4j-context-data/log4j-context-data-2.17/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/log4j/contextdata/v2_17/OpenTelemetryContextDataProvider.java +++ b/instrumentation/log4j/log4j-context-data/log4j-context-data-2.17/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/log4j/contextdata/v2_17/OpenTelemetryContextDataProvider.java @@ -5,17 +5,20 @@ package io.opentelemetry.instrumentation.log4j.contextdata.v2_17; +import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.baggage.Baggage; import io.opentelemetry.api.baggage.BaggageEntry; +import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.context.Context; -import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil; +import io.opentelemetry.instrumentation.api.internal.ConfigProviderUtil; import io.opentelemetry.instrumentation.log4j.contextdata.v2_17.internal.ContextDataKeys; import io.opentelemetry.javaagent.bootstrap.internal.ConfiguredResourceAttributesHolder; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.core.util.ContextDataProvider; @@ -25,7 +28,14 @@ */ public class OpenTelemetryContextDataProvider implements ContextDataProvider { private static final boolean BAGGAGE_ENABLED = - ConfigPropertiesUtil.getBoolean("otel.instrumentation.log4j-context-data.add-baggage", false); + Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + ConfigProviderUtil.getConfigProvider(GlobalOpenTelemetry.get()), + config -> config.getBoolean("add_baggage"), + "java", + "log4j_context_data")) + .orElse(false); + private static final boolean configuredResourceAttributeAccessible = isConfiguredResourceAttributeAccessible(); private static final Map staticContextData = getStaticContextData(); diff --git a/instrumentation/log4j/log4j-context-data/log4j-context-data-2.17/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/log4j/contextdata/v2_17/internal/ContextDataKeys.java b/instrumentation/log4j/log4j-context-data/log4j-context-data-2.17/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/log4j/contextdata/v2_17/internal/ContextDataKeys.java index a57da53ba61c..f75705e60112 100644 --- a/instrumentation/log4j/log4j-context-data/log4j-context-data-2.17/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/log4j/contextdata/v2_17/internal/ContextDataKeys.java +++ b/instrumentation/log4j/log4j-context-data/log4j-context-data-2.17/library-autoconfigure/src/main/java/io/opentelemetry/instrumentation/log4j/contextdata/v2_17/internal/ContextDataKeys.java @@ -5,23 +5,34 @@ package io.opentelemetry.instrumentation.log4j.contextdata.v2_17.internal; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; import io.opentelemetry.instrumentation.api.incubator.log.LoggingContextConstants; -import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil; +import io.opentelemetry.instrumentation.api.internal.ConfigProviderUtil; +import java.util.Optional; /** * This class is internal and is hence not for public use. Its APIs are unstable and can change at * any time. */ public final class ContextDataKeys { - public static final String TRACE_ID_KEY = - ConfigPropertiesUtil.getString( - "otel.instrumentation.common.logging.trace-id", LoggingContextConstants.TRACE_ID); - public static final String SPAN_ID_KEY = - ConfigPropertiesUtil.getString( - "otel.instrumentation.common.logging.span-id", LoggingContextConstants.SPAN_ID); + public static final String TRACE_ID_KEY = get("trace_id", LoggingContextConstants.TRACE_ID); + + public static final String SPAN_ID_KEY = get("span_id", LoggingContextConstants.SPAN_ID); + public static final String TRACE_FLAGS_KEY = - ConfigPropertiesUtil.getString( - "otel.instrumentation.common.logging.trace-flags", LoggingContextConstants.TRACE_FLAGS); + get("trace_flags", LoggingContextConstants.TRACE_FLAGS); + + private static String get(String traceId, String defaultValue) { + return Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + ConfigProviderUtil.getConfigProvider(GlobalOpenTelemetry.get()), + config -> config.getString(traceId), + "java", + "common", + "logging")) + .orElse(defaultValue); + } private ContextDataKeys() {} } diff --git a/instrumentation/servlet/servlet-common/bootstrap/build.gradle.kts b/instrumentation/servlet/servlet-common/bootstrap/build.gradle.kts index 072a96df450f..edd4ca6cf31c 100644 --- a/instrumentation/servlet/servlet-common/bootstrap/build.gradle.kts +++ b/instrumentation/servlet/servlet-common/bootstrap/build.gradle.kts @@ -1,3 +1,7 @@ plugins { id("otel.javaagent-bootstrap") } + +dependencies { + compileOnly("io.opentelemetry:opentelemetry-api-incubator") +} diff --git a/instrumentation/servlet/servlet-common/bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/servlet/ExperimentalSnippetHolder.java b/instrumentation/servlet/servlet-common/bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/servlet/ExperimentalSnippetHolder.java index ebfc41e7b72b..0d39a5d71563 100644 --- a/instrumentation/servlet/servlet-common/bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/servlet/ExperimentalSnippetHolder.java +++ b/instrumentation/servlet/servlet-common/bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/servlet/ExperimentalSnippetHolder.java @@ -5,15 +5,46 @@ package io.opentelemetry.javaagent.bootstrap.servlet; +import static java.util.logging.Level.WARNING; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil; +import io.opentelemetry.instrumentation.api.internal.ConfigProviderUtil; +import java.util.Optional; +import java.util.logging.Logger; public class ExperimentalSnippetHolder { + private static final Logger logger = Logger.getLogger(ExperimentalSnippetHolder.class.getName()); + + private static final String DEPRECATED_PROPERTY_NAME = "otel.experimental.javascript-snippet"; + private static final String NEW_PROPERTY_NAME = + "otel.instrumentation.servlet.experimental.javascript-snippet"; + private static volatile String snippet = getSnippetSetting(); private static String getSnippetSetting() { - String result = ConfigPropertiesUtil.getString("otel.experimental.javascript-snippet"); - return result == null ? "" : result; + Optional snippet = + Optional.ofNullable( + InstrumentationConfigUtil.getOrNull( + ConfigProviderUtil.getConfigProvider(GlobalOpenTelemetry.get()), + config -> config.getString("javascript-snippet/development"), + "java", + "servlet")); + // Can remove deprecated fallback in 2.24.0 + return snippet.orElseGet( + () -> { + String deprecatedValue = ConfigPropertiesUtil.getString(DEPRECATED_PROPERTY_NAME); + if (deprecatedValue != null) { + logger.log( + WARNING, + "Deprecated property \"{0}\" was used; use the \"{1}\" property instead", + new Object[] {DEPRECATED_PROPERTY_NAME, NEW_PROPERTY_NAME}); + return deprecatedValue; + } + return ""; + }); } public static void setSnippet(String newValue) { diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java index bbb40a59a2cb..7e6af32fdb9c 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/OpenTelemetryAutoConfiguration.java @@ -13,6 +13,7 @@ import io.opentelemetry.common.ComponentLoader; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.instrumentation.api.internal.EmbeddedInstrumentationProperties; +import io.opentelemetry.instrumentation.config.bridge.ConfigPropertiesDeclarativeConfigProperties; import io.opentelemetry.instrumentation.config.bridge.DeclarativeConfigPropertiesBridgeBuilder; import io.opentelemetry.instrumentation.spring.autoconfigure.internal.DeclarativeConfigDisabled; import io.opentelemetry.instrumentation.spring.autoconfigure.internal.DeclarativeConfigEnabled; @@ -130,11 +131,6 @@ public OpenTelemetry openTelemetry( return autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk(); } - @Bean - public InstrumentationConfig instrumentationConfig(ConfigProperties properties) { - return new ConfigPropertiesBridge(properties); - } - /** * Expose the {@link ConfigProperties} bean for use in other auto-configurations. * @@ -148,6 +144,17 @@ public ConfigProperties otelProperties( AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) { return requireNonNull(AutoConfigureUtil.getConfig(autoConfiguredOpenTelemetrySdk)); } + + @Bean + public ConfigProvider configProvider(ConfigProperties properties) { + return ConfigPropertiesDeclarativeConfigProperties.create(properties); + } + + @Bean + public InstrumentationConfig instrumentationConfig( + ConfigProperties properties, ConfigProvider configProvider) { + return new ConfigPropertiesBridge(properties, configProvider); + } } @Configuration @@ -231,8 +238,14 @@ public ConfigProperties otelProperties() { } @Bean - public InstrumentationConfig instrumentationConfig(ConfigProperties properties) { - return new ConfigPropertiesBridge(properties, null); + public ConfigProvider configProvider() { + return ConfigProvider.noop(); + } + + @Bean + public InstrumentationConfig instrumentationConfig( + ConfigProperties properties, ConfigProvider configProvider) { + return new ConfigPropertiesBridge(properties, configProvider); } @Configuration @@ -262,13 +275,24 @@ public ConfigProperties otelProperties(ApplicationContext applicationContext) { } } + @Configuration + @ConditionalOnBean(OpenTelemetry.class) + @ConditionalOnMissingBean({ConfigProvider.class}) + static class FallbackConfigProvider { + @Bean + public ConfigProvider configProvider() { + return ConfigProvider.noop(); + } + } + @Configuration @ConditionalOnBean(OpenTelemetry.class) @ConditionalOnMissingBean({InstrumentationConfig.class}) static class FallbackInstrumentationConfig { @Bean - public InstrumentationConfig instrumentationConfig(ConfigProperties properties) { - return new ConfigPropertiesBridge(properties, null); + public InstrumentationConfig instrumentationConfig( + ConfigProperties properties, ConfigProvider configProvider) { + return new ConfigPropertiesBridge(properties, configProvider); } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/ConfigPropertiesBridge.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/ConfigPropertiesBridge.java index dbabca731486..68486d677999 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/ConfigPropertiesBridge.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/properties/ConfigPropertiesBridge.java @@ -5,12 +5,7 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties; -import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; -import static java.util.Objects.requireNonNull; - import io.opentelemetry.api.incubator.config.ConfigProvider; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; @@ -28,14 +23,9 @@ public final class ConfigPropertiesBridge implements InstrumentationConfig { private final ConfigProperties configProperties; - @Nullable private final ConfigProvider configProvider; - - public ConfigPropertiesBridge(ConfigProperties configProperties) { - this(configProperties, null); - } + private final ConfigProvider configProvider; - public ConfigPropertiesBridge( - ConfigProperties configProperties, @Nullable ConfigProvider configProvider) { + public ConfigPropertiesBridge(ConfigProperties configProperties, ConfigProvider configProvider) { this.configProperties = configProperties; this.configProvider = configProvider; } @@ -122,24 +112,7 @@ public Map getMap(String name, Map defaultValue) } } - @Override - public boolean isDeclarative() { - return configProvider != null; - } - - @Override - public DeclarativeConfigProperties getDeclarativeConfig(String node) { - DeclarativeConfigProperties config = - InstrumentationConfigUtil.javaInstrumentationConfig(requireNonNull(configProvider), node); - if (config == null) { - // there is no declarative config for this node - return empty(); - } - return config; - } - - @Nullable - @Override + @Override public ConfigProvider getConfigProvider() { return configProvider; } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/scheduling/SchedulingInstrumentationAspectTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/scheduling/SchedulingInstrumentationAspectTest.java index 3306b280869c..6cc872c3b9b7 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/scheduling/SchedulingInstrumentationAspectTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/scheduling/SchedulingInstrumentationAspectTest.java @@ -6,6 +6,7 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.scheduling; import static io.opentelemetry.api.trace.SpanKind.INTERNAL; +import static io.opentelemetry.instrumentation.spring.autoconfigure.internal.AbstractKafkaInstrumentationAutoConfigurationTest.EMPTY_INSTRUMENTATION_CONFIG; import static org.assertj.core.api.Assertions.assertThatThrownBy; import io.opentelemetry.api.OpenTelemetry; @@ -14,13 +15,10 @@ import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; -import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.ConfigPropertiesBridge; import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.code.SemconvCodeStabilityUtil; -import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; import io.opentelemetry.sdk.trace.data.StatusData; -import java.util.Collections; import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -55,10 +53,7 @@ void setup() { factory.setTarget(unproxiedTester); SpringSchedulingInstrumentationAspect aspect = - newAspect( - testing.getOpenTelemetry(), - new ConfigPropertiesBridge( - DefaultConfigProperties.createFromMap(Collections.emptyMap()))); + newAspect(testing.getOpenTelemetry(), EMPTY_INSTRUMENTATION_CONFIG); factory.addAspect(aspect); schedulingTester = factory.getProxy(); diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/scheduling/SchedulingInstrumentationAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/scheduling/SchedulingInstrumentationAutoConfigurationTest.java index 5b631daf1434..43b5b911f421 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/scheduling/SchedulingInstrumentationAutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/scheduling/SchedulingInstrumentationAutoConfigurationTest.java @@ -5,13 +5,11 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.scheduling; +import static io.opentelemetry.instrumentation.spring.autoconfigure.internal.AbstractKafkaInstrumentationAutoConfigurationTest.EMPTY_INSTRUMENTATION_CONFIG; import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; -import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.ConfigPropertiesBridge; -import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; -import java.util.Collections; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -20,11 +18,7 @@ class SchedulingInstrumentationAutoConfigurationTest { private final ApplicationContextRunner runner = new ApplicationContextRunner() .withBean(OpenTelemetry.class, OpenTelemetry::noop) - .withBean( - InstrumentationConfig.class, - () -> - new ConfigPropertiesBridge( - DefaultConfigProperties.createFromMap(Collections.emptyMap()))) + .withBean(InstrumentationConfig.class, () -> EMPTY_INSTRUMENTATION_CONFIG) .withConfiguration( AutoConfigurations.of(SpringSchedulingInstrumentationAutoConfiguration.class)); diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/SpringWebfluxInstrumentationAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/SpringWebfluxInstrumentationAutoConfigurationTest.java index df6273d4686c..52ecd59e72b5 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/SpringWebfluxInstrumentationAutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/SpringWebfluxInstrumentationAutoConfigurationTest.java @@ -5,13 +5,11 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.webflux; +import static io.opentelemetry.instrumentation.spring.autoconfigure.internal.AbstractKafkaInstrumentationAutoConfigurationTest.EMPTY_INSTRUMENTATION_CONFIG; import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; -import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.ConfigPropertiesBridge; -import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; -import java.util.Collections; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -21,11 +19,7 @@ class SpringWebfluxInstrumentationAutoConfigurationTest { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withBean(OpenTelemetry.class, OpenTelemetry::noop) - .withBean( - InstrumentationConfig.class, - () -> - new ConfigPropertiesBridge( - DefaultConfigProperties.createFromMap(Collections.emptyMap()))) + .withBean(InstrumentationConfig.class, () -> EMPTY_INSTRUMENTATION_CONFIG) .withConfiguration( AutoConfigurations.of(SpringWebfluxInstrumentationAutoConfiguration.class)); diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/WebClientBeanPostProcessorTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/WebClientBeanPostProcessorTest.java index 4c25da12a112..feba92760a54 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/WebClientBeanPostProcessorTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webflux/WebClientBeanPostProcessorTest.java @@ -5,13 +5,11 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.webflux; +import static io.opentelemetry.instrumentation.spring.autoconfigure.internal.AbstractKafkaInstrumentationAutoConfigurationTest.EMPTY_INSTRUMENTATION_CONFIG; import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; -import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.ConfigPropertiesBridge; -import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; -import java.util.Collections; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.config.BeanPostProcessor; @@ -24,9 +22,7 @@ class WebClientBeanPostProcessorTest { static { beanFactory.registerSingleton("openTelemetry", OpenTelemetry.noop()); - beanFactory.registerSingleton( - "configProperties", - new ConfigPropertiesBridge(DefaultConfigProperties.createFromMap(Collections.emptyMap()))); + beanFactory.registerSingleton("instrumentationConfig", EMPTY_INSTRUMENTATION_CONFIG); } @Test diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webmvc/SpringWebMvcInstrumentation5AutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webmvc/SpringWebMvcInstrumentation5AutoConfigurationTest.java index 3c90a46fdfdc..296f4961a8af 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webmvc/SpringWebMvcInstrumentation5AutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webmvc/SpringWebMvcInstrumentation5AutoConfigurationTest.java @@ -5,14 +5,12 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.webmvc; +import static io.opentelemetry.instrumentation.spring.autoconfigure.internal.AbstractKafkaInstrumentationAutoConfigurationTest.EMPTY_INSTRUMENTATION_CONFIG; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assumptions.assumeFalse; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; -import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.ConfigPropertiesBridge; -import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; -import java.util.Collections; import javax.servlet.Filter; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -24,11 +22,7 @@ class SpringWebMvcInstrumentation5AutoConfigurationTest { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withBean(OpenTelemetry.class, OpenTelemetry::noop) - .withBean( - InstrumentationConfig.class, - () -> - new ConfigPropertiesBridge( - DefaultConfigProperties.createFromMap(Collections.emptyMap()))) + .withBean(InstrumentationConfig.class, () -> EMPTY_INSTRUMENTATION_CONFIG) .withConfiguration( AutoConfigurations.of(SpringWebMvc5InstrumentationAutoConfiguration.class)); diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/testSpring3/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/web/RestClientInstrumentationAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/testSpring3/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/web/RestClientInstrumentationAutoConfigurationTest.java index 3e16f15b23ef..8745c0830bc0 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/testSpring3/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/web/RestClientInstrumentationAutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/testSpring3/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/web/RestClientInstrumentationAutoConfigurationTest.java @@ -8,6 +8,7 @@ import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.incubator.config.ConfigProvider; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.ConfigPropertiesBridge; import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; @@ -26,7 +27,8 @@ class RestClientInstrumentationAutoConfigurationTest { InstrumentationConfig.class, () -> new ConfigPropertiesBridge( - DefaultConfigProperties.createFromMap(Collections.emptyMap()))) + DefaultConfigProperties.createFromMap(Collections.emptyMap()), + ConfigProvider.noop())) .withBean(RestClient.class, RestClient::create) .withConfiguration( AutoConfigurations.of(RestClientInstrumentationAutoConfiguration.class)); diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/testSpring3/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webmvc/SpringWebMvcInstrumentation6AutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/testSpring3/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webmvc/SpringWebMvcInstrumentation6AutoConfigurationTest.java index a96d6abc2f4e..13adaebb0eda 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/testSpring3/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webmvc/SpringWebMvcInstrumentation6AutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/testSpring3/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/webmvc/SpringWebMvcInstrumentation6AutoConfigurationTest.java @@ -9,6 +9,7 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.incubator.config.ConfigProvider; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.ConfigPropertiesBridge; import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; @@ -28,7 +29,8 @@ class SpringWebMvcInstrumentation6AutoConfigurationTest { InstrumentationConfig.class, () -> new ConfigPropertiesBridge( - DefaultConfigProperties.createFromMap(Collections.emptyMap()))) + DefaultConfigProperties.createFromMap(Collections.emptyMap()), + ConfigProvider.noop())) .withConfiguration( AutoConfigurations.of(SpringWebMvc6InstrumentationAutoConfiguration.class)); diff --git a/instrumentation/spring/spring-boot-autoconfigure/testing/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/AbstractJdbcInstrumentationAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/testing/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/AbstractJdbcInstrumentationAutoConfigurationTest.java index 8c7b05f14e96..c7f5af335012 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/testing/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/AbstractJdbcInstrumentationAutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/testing/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/AbstractJdbcInstrumentationAutoConfigurationTest.java @@ -5,16 +5,14 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.internal; +import static io.opentelemetry.instrumentation.spring.autoconfigure.internal.AbstractKafkaInstrumentationAutoConfigurationTest.EMPTY_INSTRUMENTATION_CONFIG; import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable; import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_STATEMENT; -import static java.util.Collections.emptyMap; import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; -import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.ConfigPropertiesBridge; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; -import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; import java.sql.Connection; import java.sql.Statement; import javax.sql.DataSource; @@ -32,9 +30,7 @@ public abstract class AbstractJdbcInstrumentationAutoConfigurationTest { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withBean( - InstrumentationConfig.class, - () -> new ConfigPropertiesBridge(DefaultConfigProperties.createFromMap(emptyMap()))) + .withBean(InstrumentationConfig.class, () -> EMPTY_INSTRUMENTATION_CONFIG) .withConfiguration(autoConfigurations()) .withBean("openTelemetry", OpenTelemetry.class, testing()::getOpenTelemetry); diff --git a/instrumentation/spring/spring-boot-autoconfigure/testing/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/AbstractKafkaInstrumentationAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/testing/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/AbstractKafkaInstrumentationAutoConfigurationTest.java index c4e0b40a127c..66dc6d35ddbb 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/testing/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/AbstractKafkaInstrumentationAutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/testing/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/AbstractKafkaInstrumentationAutoConfigurationTest.java @@ -5,13 +5,14 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.internal; -import static java.util.Collections.emptyMap; import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.incubator.config.ConfigProvider; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.ConfigPropertiesBridge; import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; +import java.util.Collections; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; @@ -19,15 +20,17 @@ public abstract class AbstractKafkaInstrumentationAutoConfigurationTest { + public static final ConfigPropertiesBridge EMPTY_INSTRUMENTATION_CONFIG = + new ConfigPropertiesBridge( + DefaultConfigProperties.createFromMap(Collections.emptyMap()), ConfigProvider.noop()); + protected abstract AutoConfigurations autoConfigurations(); protected abstract void factoryTestAssertion(AssertableApplicationContext context); protected final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withBean( - InstrumentationConfig.class, - () -> new ConfigPropertiesBridge(DefaultConfigProperties.createFromMap(emptyMap()))) + .withBean(InstrumentationConfig.class, () -> EMPTY_INSTRUMENTATION_CONFIG) .withConfiguration(autoConfigurations()) .withBean("openTelemetry", OpenTelemetry.class, OpenTelemetry::noop); diff --git a/instrumentation/spring/spring-boot-autoconfigure/testing/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/AbstractR2DbcInstrumentationAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/testing/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/AbstractR2DbcInstrumentationAutoConfigurationTest.java index a556d7e1f68c..fdad3a062197 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/testing/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/AbstractR2DbcInstrumentationAutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/testing/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/AbstractR2DbcInstrumentationAutoConfigurationTest.java @@ -5,15 +5,13 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.internal; +import static io.opentelemetry.instrumentation.spring.autoconfigure.internal.AbstractKafkaInstrumentationAutoConfigurationTest.EMPTY_INSTRUMENTATION_CONFIG; import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable; import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_STATEMENT; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; -import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.ConfigPropertiesBridge; import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension; -import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; -import java.util.Collections; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -27,11 +25,7 @@ public abstract class AbstractR2DbcInstrumentationAutoConfigurationTest { protected final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withBean( - InstrumentationConfig.class, - () -> - new ConfigPropertiesBridge( - DefaultConfigProperties.createFromMap(Collections.emptyMap()))) + .withBean(InstrumentationConfig.class, () -> EMPTY_INSTRUMENTATION_CONFIG) .withConfiguration(autoConfigurations()) .withBean("openTelemetry", OpenTelemetry.class, testing()::getOpenTelemetry); diff --git a/instrumentation/spring/spring-boot-autoconfigure/testing/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/AbstractSpringWebInstrumentationAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/testing/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/AbstractSpringWebInstrumentationAutoConfigurationTest.java index 4b9a339d38b7..9d56280ea857 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/testing/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/AbstractSpringWebInstrumentationAutoConfigurationTest.java +++ b/instrumentation/spring/spring-boot-autoconfigure/testing/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/AbstractSpringWebInstrumentationAutoConfigurationTest.java @@ -5,14 +5,12 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.internal; +import static io.opentelemetry.instrumentation.spring.autoconfigure.internal.AbstractKafkaInstrumentationAutoConfigurationTest.EMPTY_INSTRUMENTATION_CONFIG; import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.web.RestTemplateBeanPostProcessor; -import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.ConfigPropertiesBridge; -import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; -import java.util.Collections; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -25,11 +23,7 @@ public abstract class AbstractSpringWebInstrumentationAutoConfigurationTest { protected final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withBean(OpenTelemetry.class, OpenTelemetry::noop) - .withBean( - InstrumentationConfig.class, - () -> - new ConfigPropertiesBridge( - DefaultConfigProperties.createFromMap(Collections.emptyMap()))) + .withBean(InstrumentationConfig.class, () -> EMPTY_INSTRUMENTATION_CONFIG) .withBean(RestTemplate.class, RestTemplate::new) .withConfiguration(autoConfigurations()); diff --git a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/EmptyInstrumentationConfig.java b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/EmptyInstrumentationConfig.java index 56cd43580c17..b99c30e45444 100644 --- a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/EmptyInstrumentationConfig.java +++ b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/EmptyInstrumentationConfig.java @@ -6,7 +6,6 @@ package io.opentelemetry.javaagent.bootstrap.internal; import io.opentelemetry.api.incubator.config.ConfigProvider; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import java.time.Duration; import java.util.List; @@ -61,20 +60,8 @@ public Map getMap(String name, Map defaultValue) return defaultValue; } - @Override - public boolean isDeclarative() { - return false; - } - - @Override - public DeclarativeConfigProperties getDeclarativeConfig(String node) { - throw new IllegalStateException( - "Declarative configuration is not supported in the empty instrumentation config"); - } - - @Nullable @Override public ConfigProvider getConfigProvider() { - return null; + return ConfigProvider.noop(); } } diff --git a/javaagent-tooling/build.gradle.kts b/javaagent-tooling/build.gradle.kts index 5434028a60a0..bc69d6a56f34 100644 --- a/javaagent-tooling/build.gradle.kts +++ b/javaagent-tooling/build.gradle.kts @@ -105,6 +105,7 @@ testing { val testConfigFile by registering(JvmTestSuite::class) { dependencies { + implementation(project(":instrumentation-api")) implementation(project(":javaagent-tooling")) // requires mockito-inline implementation("uk.org.webcompere:system-stubs-jupiter") diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java index 769908d7f2a8..a49af71ba868 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/AgentInstaller.java @@ -10,15 +10,19 @@ import static io.opentelemetry.javaagent.tooling.SafeServiceLoader.loadOrdered; import static io.opentelemetry.javaagent.tooling.Utils.getResourceName; import static java.util.Arrays.asList; +import static java.util.Objects.requireNonNull; import static java.util.logging.Level.FINE; import static java.util.logging.Level.SEVERE; import static net.bytebuddy.matcher.ElementMatchers.any; import static net.bytebuddy.matcher.ElementMatchers.none; +import io.opentelemetry.api.incubator.config.ConfigProvider; import io.opentelemetry.context.Context; import io.opentelemetry.context.ContextStorage; import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.instrumentation.api.internal.EmbeddedInstrumentationProperties; +import io.opentelemetry.instrumentation.config.bridge.ConfigPropertiesDeclarativeConfigProperties; import io.opentelemetry.javaagent.bootstrap.AgentClassLoader; import io.opentelemetry.javaagent.bootstrap.BootstrapPackagePrefixesHolder; import io.opentelemetry.javaagent.bootstrap.DefineClassHelper; @@ -168,8 +172,7 @@ private static void installBytebuddyAgent( ConfigProperties sdkConfig = AutoConfigureUtil.getConfig(autoConfiguredSdk); AgentInstrumentationConfig.internalInitializeConfig( - new ConfigPropertiesBridge( - sdkConfig, AutoConfigureUtil.getConfigProvider(autoConfiguredSdk))); + getInstrumentationConfig(autoConfiguredSdk, sdkConfig)); copyNecessaryConfigToSystemProperties(sdkConfig); setBootstrapPackages(sdkConfig, extensionClassLoader); @@ -228,6 +231,20 @@ private static void installBytebuddyAgent( runAfterAgentListeners(agentListeners, autoConfiguredSdk, sdkConfig); } + private static InstrumentationConfig getInstrumentationConfig( + AutoConfiguredOpenTelemetrySdk autoConfiguredSdk, ConfigProperties sdkConfig) { + ConfigProvider originalProvider = AutoConfigureUtil.getConfigProvider(autoConfiguredSdk); + + boolean isDeclarativeConfig = originalProvider != null; + // use the bridge only if the configuration is not already declarative + ConfigProvider provider = + isDeclarativeConfig + ? originalProvider + : ConfigPropertiesDeclarativeConfigProperties.create( + requireNonNull(AutoConfigureUtil.getConfig(autoConfiguredSdk))); + return new ConfigPropertiesBridge(sdkConfig, provider); + } + private static AgentBuilder newAgentBuilder(ByteBuddy byteBuddy) { // AgentBuilder.Default constructor triggers sun.misc.Unsafe::objectFieldOffset called warning // AgentBuilder$Default. diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/config/ConfigPropertiesBridge.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/config/ConfigPropertiesBridge.java index 5c7fe70d9f1d..d28afe95da47 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/config/ConfigPropertiesBridge.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/config/ConfigPropertiesBridge.java @@ -5,12 +5,7 @@ package io.opentelemetry.javaagent.tooling.config; -import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; -import static java.util.Objects.requireNonNull; - import io.opentelemetry.api.incubator.config.ConfigProvider; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; @@ -22,10 +17,9 @@ public final class ConfigPropertiesBridge implements InstrumentationConfig { private final ConfigProperties configProperties; - @Nullable private final ConfigProvider configProvider; + private final ConfigProvider configProvider; - public ConfigPropertiesBridge( - ConfigProperties configProperties, @Nullable ConfigProvider configProvider) { + public ConfigPropertiesBridge(ConfigProperties configProperties, ConfigProvider configProvider) { this.configProperties = configProperties; this.configProvider = configProvider; } @@ -112,22 +106,6 @@ public Map getMap(String name, Map defaultValue) } } - @Override - public boolean isDeclarative() { - return configProvider != null; - } - - @Override - public DeclarativeConfigProperties getDeclarativeConfig(String node) { - DeclarativeConfigProperties config = - InstrumentationConfigUtil.javaInstrumentationConfig(requireNonNull(configProvider), node); - if (config == null) { - // there is no declarative config for this node - return empty(); - } - return config; - } - @Nullable @Override public ConfigProvider getConfigProvider() { diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractTestContainerManager.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractTestContainerManager.java index 985c4381138a..8342151bb4c5 100644 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractTestContainerManager.java +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractTestContainerManager.java @@ -45,7 +45,9 @@ protected Map getAgentEnvironment( environment.put("OTEL_RESOURCE_ATTRIBUTES", "service.name=smoke-test"); } environment.put("OTEL_JAVAAGENT_DEBUG", "true"); - environment.put("OTEL_EXPERIMENTAL_JAVASCRIPT_SNIPPET", ""); + environment.put( + "OTEL_INSTRUMENTATION_SERVLET_EXPERIMENTAL_JAVASCRIPT_SNIPPET", + ""); environment.put("OTEL_INSTRUMENTATION_RUNTIME_TELEMETRY_PACKAGE_EMITTER_ENABLED", "true"); return environment; }