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 bb64425c6da5..a02297001b42 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 @@ -7,6 +7,8 @@ import static java.util.Collections.emptyMap; +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; import io.opentelemetry.instrumentation.api.incubator.log.LoggingContextConstants; import io.opentelemetry.instrumentation.api.incubator.semconv.net.PeerServiceResolver; import io.opentelemetry.instrumentation.api.internal.HttpConstants; @@ -14,6 +16,8 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; /** * This class is internal and is hence not for public use. Its APIs are unstable and can change at @@ -39,16 +43,32 @@ public final class CommonConfig { public CommonConfig(InstrumentationConfig config) { peerServiceResolver = PeerServiceResolver.create( - config.getMap("otel.instrumentation.common.peer-service-mapping", emptyMap())); + getFromConfigProviderOrFallback( + config, + InstrumentationConfigUtil::peerServiceMapping, + () -> + config.getMap("otel.instrumentation.common.peer-service-mapping", emptyMap()))); clientRequestHeaders = - config.getList("otel.instrumentation.http.client.capture-request-headers"); + getFromConfigProviderOrFallback( + config, + InstrumentationConfigUtil::httpClientRequestCapturedHeaders, + () -> config.getList("otel.instrumentation.http.client.capture-request-headers")); clientResponseHeaders = - config.getList("otel.instrumentation.http.client.capture-response-headers"); + getFromConfigProviderOrFallback( + config, + InstrumentationConfigUtil::httpClientResponseCapturedHeaders, + () -> config.getList("otel.instrumentation.http.client.capture-response-headers")); serverRequestHeaders = - config.getList("otel.instrumentation.http.server.capture-request-headers"); + getFromConfigProviderOrFallback( + config, + InstrumentationConfigUtil::httpServerRequestCapturedHeaders, + () -> config.getList("otel.instrumentation.http.server.capture-request-headers")); serverResponseHeaders = - config.getList("otel.instrumentation.http.server.capture-response-headers"); + getFromConfigProviderOrFallback( + config, + InstrumentationConfigUtil::httpServerResponseCapturedHeaders, + () -> config.getList("otel.instrumentation.http.server.capture-response-headers")); knownHttpRequestMethods = new HashSet<>( config.getList( @@ -130,4 +150,15 @@ public String getSpanIdKey() { public String getTraceFlagsKey() { return loggingTraceFlagsKey; } + + private static T getFromConfigProviderOrFallback( + InstrumentationConfig config, + Function getFromConfigProvider, + Supplier fallback) { + ConfigProvider configProvider = config.getConfigProvider(); + if (configProvider != null) { + return getFromConfigProvider.apply(configProvider); + } + return fallback.get(); + } } 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 61ebef57caa2..ab1bb761aa22 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 @@ -7,6 +7,7 @@ import static java.util.Collections.emptyList; +import io.opentelemetry.api.incubator.config.ConfigProvider; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import java.time.Duration; import java.util.List; @@ -109,17 +110,30 @@ default List getList(String name) { */ Map getMap(String name, Map defaultValue); + /** Returns {@code true} if declarative configuration is used in this configuration. */ + boolean isDeclarative(); + /** - * Returns a {@link DeclarativeConfigProperties} for the given instrumentation name, or {@code - * null} if no declarative configuration is available for that instrumentation. + * 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. * *

Declarative configuration is used to configure instrumentation properties in a declarative * way, such as through YAML or JSON files. * - * @param instrumentationName the name of the instrumentation - * @return the declarative configuration properties for the given instrumentation name, or {@code - * null} if not available + * @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); + + /** + * Returns the {@link ConfigProvider} if declarative configuration is used. + * + * @return the {@link ConfigProvider} or {@code null} if no provider is available */ @Nullable - DeclarativeConfigProperties getDeclarativeConfig(String instrumentationName); + ConfigProvider getConfigProvider(); } diff --git a/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java b/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java index 267bc031d160..39d32e69e4a8 100644 --- a/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java +++ b/instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java @@ -14,8 +14,8 @@ import io.opentelemetry.instrumentation.jmx.engine.MetricConfiguration; import io.opentelemetry.instrumentation.jmx.yaml.RuleParser; import io.opentelemetry.javaagent.extension.AgentListener; -import io.opentelemetry.javaagent.extension.internal.ConfigPropertiesUtil; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import java.io.InputStream; import java.nio.file.Files; @@ -29,7 +29,7 @@ public class JmxMetricInsightInstaller implements AgentListener { @Override public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { - ConfigProperties config = ConfigPropertiesUtil.resolveConfigProperties(autoConfiguredSdk); + ConfigProperties config = AutoConfigureUtil.getConfig(autoConfiguredSdk); if (config.getBoolean("otel.jmx.enabled", true)) { JmxMetricInsight service = diff --git a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java index 67cff1841338..3106c332c8da 100644 --- a/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java +++ b/instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java @@ -10,8 +10,8 @@ import static java.util.Collections.singletonMap; import com.google.auto.service.AutoService; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; @@ -34,10 +34,11 @@ public MethodInstrumentationModule() { } private static List createInstrumentations() { - DeclarativeConfigProperties methods = - AgentInstrumentationConfig.get().getDeclarativeConfig("methods"); + InstrumentationConfig config = AgentInstrumentationConfig.get(); List list = - methods != null ? MethodsConfig.parseDeclarativeConfig(methods) : parseConfigProperties(); + config.isDeclarative() + ? MethodsConfig.parseDeclarativeConfig(config.getDeclarativeConfig("methods")) + : parseConfigProperties(); // ensure that there is at least one instrumentation so that muzzle reference collection could // work if (list.isEmpty()) { diff --git a/instrumentation/oshi/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/oshi/OshiMetricsInstaller.java b/instrumentation/oshi/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/oshi/OshiMetricsInstaller.java index 028dc7da46ed..5a5b04443d2e 100644 --- a/instrumentation/oshi/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/oshi/OshiMetricsInstaller.java +++ b/instrumentation/oshi/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/oshi/OshiMetricsInstaller.java @@ -7,8 +7,8 @@ import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.AgentListener; -import io.opentelemetry.javaagent.extension.internal.ConfigPropertiesUtil; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import java.lang.reflect.Method; @@ -21,7 +21,7 @@ public class OshiMetricsInstaller implements AgentListener { @Override public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { - ConfigProperties config = ConfigPropertiesUtil.resolveConfigProperties(autoConfiguredSdk); + ConfigProperties config = AutoConfigureUtil.getConfig(autoConfiguredSdk); boolean defaultEnabled = config.getBoolean("otel.instrumentation.common.default-enabled", true); if (!config.getBoolean("otel.instrumentation.oshi.enabled", defaultEnabled)) { diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java8/JarAnalyzerInstaller.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java8/JarAnalyzerInstaller.java index 51d18eb32caa..102e3892ffe6 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java8/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java8/JarAnalyzerInstaller.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java8/JarAnalyzerInstaller.java @@ -7,9 +7,9 @@ import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.bootstrap.InstrumentationHolder; -import io.opentelemetry.javaagent.extension.internal.ConfigPropertiesUtil; import io.opentelemetry.javaagent.tooling.BeforeAgentListener; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import java.lang.instrument.Instrumentation; @@ -19,8 +19,7 @@ public class JarAnalyzerInstaller implements BeforeAgentListener { @Override public void beforeAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) { - ConfigProperties config = - ConfigPropertiesUtil.resolveConfigProperties(autoConfiguredOpenTelemetrySdk); + ConfigProperties config = AutoConfigureUtil.getConfig(autoConfiguredOpenTelemetrySdk); boolean enabled = config.getBoolean("otel.instrumentation.runtime-telemetry.package-emitter.enabled", false); 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 200bd30c73d6..047d2ee809ea 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,6 +5,7 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties; +import io.opentelemetry.api.incubator.config.ConfigProvider; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; @@ -110,10 +111,21 @@ public Map getMap(String name, Map defaultValue) } } + @Override + public boolean isDeclarative() { + return false; + } + + @Override + public DeclarativeConfigProperties getDeclarativeConfig(String node) { + throw new IllegalStateException( + "Declarative configuration is not supported in spring boot autoconfigure yet"); + } + @Nullable @Override - public DeclarativeConfigProperties getDeclarativeConfig(String instrumentationName) { - // create a spring boot bridge for DeclarativeConfigProperties + public ConfigProvider getConfigProvider() { + // declarative config support will be added in the future return null; } } 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 8a6c8110da32..56cd43580c17 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 @@ -5,6 +5,7 @@ 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; @@ -60,9 +61,20 @@ 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 DeclarativeConfigProperties getDeclarativeConfig(String instrumentationName) { + public ConfigProvider getConfigProvider() { return null; } } diff --git a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/internal/ConfigPropertiesUtil.java b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/internal/ConfigPropertiesUtil.java deleted file mode 100644 index 914d07d20f36..000000000000 --- a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/internal/ConfigPropertiesUtil.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.extension.internal; - -import io.opentelemetry.api.incubator.config.ConfigProvider; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; -import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; -import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; - -/** - * This class is internal and is hence not for public use. Its APIs are unstable and can change at - * any time. - */ -public final class ConfigPropertiesUtil { - private ConfigPropertiesUtil() {} - - /** Resolve {@link ConfigProperties} from the {@code autoConfiguredOpenTelemetrySdk}. */ - public static ConfigProperties resolveConfigProperties( - AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) { - ConfigProperties sdkConfigProperties = - AutoConfigureUtil.getConfig(autoConfiguredOpenTelemetrySdk); - if (sdkConfigProperties != null) { - return sdkConfigProperties; - } - ConfigProvider configProvider = - AutoConfigureUtil.getConfigProvider(autoConfiguredOpenTelemetrySdk); - if (configProvider != null) { - DeclarativeConfigProperties instrumentationConfig = configProvider.getInstrumentationConfig(); - - if (instrumentationConfig == null) { - instrumentationConfig = DeclarativeConfigProperties.empty(); - } - - return new DeclarativeConfigPropertiesBridge(instrumentationConfig); - } - // Should never happen - throw new IllegalStateException( - "AutoConfiguredOpenTelemetrySdk does not have ConfigProperties or DeclarativeConfigProperties. This is likely a programming error in opentelemetry-java"); - } -} diff --git a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/internal/DeclarativeConfigPropertiesBridge.java b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/internal/DeclarativeConfigPropertiesBridge.java index 0d4de14c217f..e2e782443361 100644 --- a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/internal/DeclarativeConfigPropertiesBridge.java +++ b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/internal/DeclarativeConfigPropertiesBridge.java @@ -14,6 +14,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.BiFunction; import javax.annotation.Nullable; @@ -50,66 +51,80 @@ final class DeclarativeConfigPropertiesBridge implements ConfigProperties { private static final String OTEL_INSTRUMENTATION_PREFIX = "otel.instrumentation."; - // The node at .instrumentation.java - private final DeclarativeConfigProperties instrumentationJavaNode; + private final DeclarativeConfigProperties baseNode; - DeclarativeConfigPropertiesBridge(DeclarativeConfigProperties instrumentationNode) { - instrumentationJavaNode = instrumentationNode.getStructured("java", empty()); + // lookup order matters - we choose the first match + private final Map mappings; + private final Map overrideValues; + + DeclarativeConfigPropertiesBridge( + DeclarativeConfigProperties baseNode, + Map mappings, + Map overrideValues) { + this.baseNode = Objects.requireNonNull(baseNode); + this.mappings = mappings; + this.overrideValues = overrideValues; } @Nullable @Override public String getString(String propertyName) { - return getPropertyValue(propertyName, DeclarativeConfigProperties::getString); + return getPropertyValue(propertyName, String.class, DeclarativeConfigProperties::getString); } @Nullable @Override public Boolean getBoolean(String propertyName) { - return getPropertyValue(propertyName, DeclarativeConfigProperties::getBoolean); + return getPropertyValue(propertyName, Boolean.class, DeclarativeConfigProperties::getBoolean); } @Nullable @Override public Integer getInt(String propertyName) { - return getPropertyValue(propertyName, DeclarativeConfigProperties::getInt); + return getPropertyValue(propertyName, Integer.class, DeclarativeConfigProperties::getInt); } @Nullable @Override public Long getLong(String propertyName) { - return getPropertyValue(propertyName, DeclarativeConfigProperties::getLong); + return getPropertyValue(propertyName, Long.class, DeclarativeConfigProperties::getLong); } @Nullable @Override public Double getDouble(String propertyName) { - return getPropertyValue(propertyName, DeclarativeConfigProperties::getDouble); + return getPropertyValue(propertyName, Double.class, DeclarativeConfigProperties::getDouble); } @Nullable @Override public Duration getDuration(String propertyName) { - Long millis = getPropertyValue(propertyName, DeclarativeConfigProperties::getLong); + Long millis = getPropertyValue(propertyName, Long.class, DeclarativeConfigProperties::getLong); if (millis == null) { return null; } return Duration.ofMillis(millis); } + @SuppressWarnings("unchecked") @Override public List getList(String propertyName) { List propertyValue = getPropertyValue( propertyName, + List.class, (properties, lastPart) -> properties.getScalarList(lastPart, String.class)); return propertyValue == null ? Collections.emptyList() : propertyValue; } + @SuppressWarnings("unchecked") @Override public Map getMap(String propertyName) { DeclarativeConfigProperties propertyValue = - getPropertyValue(propertyName, DeclarativeConfigProperties::getStructured); + getPropertyValue( + propertyName, + DeclarativeConfigProperties.class, + DeclarativeConfigProperties::getStructured); if (propertyValue == null) { return Collections.emptyMap(); } @@ -129,22 +144,21 @@ public Map getMap(String propertyName) { @Nullable private T getPropertyValue( - String property, BiFunction extractor) { - if (instrumentationJavaNode == null) { - return null; + String property, + Class clazz, + BiFunction extractor) { + T override = clazz.cast(overrideValues.get(property)); + if (override != null) { + return override; } - if (property.startsWith(OTEL_INSTRUMENTATION_PREFIX)) { - property = property.substring(OTEL_INSTRUMENTATION_PREFIX.length()); - } - // Split the remainder of the property on "." - String[] segments = property.split("\\."); + String[] segments = getSegments(translateProperty(property)); if (segments.length == 0) { return null; } // Extract the value by walking to the N-1 entry - DeclarativeConfigProperties target = instrumentationJavaNode; + DeclarativeConfigProperties target = baseNode; if (segments.length > 1) { for (int i = 0; i < segments.length - 1; i++) { target = target.getStructured(segments[i], empty()); @@ -154,4 +168,21 @@ private T getPropertyValue( return extractor.apply(target, lastPart); } + + private static String[] getSegments(String property) { + if (property.startsWith(OTEL_INSTRUMENTATION_PREFIX)) { + property = property.substring(OTEL_INSTRUMENTATION_PREFIX.length()); + } + // Split the remainder of the property on "." + return property.replace('-', '_').split("\\."); + } + + private String translateProperty(String property) { + for (Map.Entry entry : mappings.entrySet()) { + if (property.startsWith(entry.getKey())) { + return entry.getValue() + property.substring(entry.getKey().length()); + } + } + return property; + } } diff --git a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/internal/DeclarativeConfigPropertiesBridgeBuilder.java b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/internal/DeclarativeConfigPropertiesBridgeBuilder.java new file mode 100644 index 000000000000..05da62862dec --- /dev/null +++ b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/internal/DeclarativeConfigPropertiesBridgeBuilder.java @@ -0,0 +1,105 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.extension.internal; + +import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.opentelemetry.api.incubator.config.ConfigProvider; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import javax.annotation.Nullable; + +/** + * A builder for {@link DeclarativeConfigPropertiesBridge} that allows adding translations and fixed + * values for properties. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public class DeclarativeConfigPropertiesBridgeBuilder { + /** + * order is important here, so we use LinkedHashMap - see {@link #addMapping(String, String)} for + * more details + */ + private final Map mappings = new LinkedHashMap<>(); + + private final Map overrideValues = new HashMap<>(); + + public DeclarativeConfigPropertiesBridgeBuilder() {} + + /** + * Adds a mapping from a property prefix to a YAML path. + * + *

For example, if the property prefix is "otel.javaagent" and the YAML path is "agent", then + * any property starting with "otel.javaagent." will be resolved against the "agent" node in the + * instrumentation/java section of the YAML configuration. + * + * @param propertyPrefix the prefix of the property to translate + * @param yamlPath the YAML path to resolve the property against + */ + @CanIgnoreReturnValue + public DeclarativeConfigPropertiesBridgeBuilder addMapping( + String propertyPrefix, String yamlPath) { + mappings.put(propertyPrefix, yamlPath); + return this; + } + + /** + * Adds a fixed override value for a property. + * + * @param propertyName the name of the property to override + * @param value the value to return when the property is requested + */ + @CanIgnoreReturnValue + public DeclarativeConfigPropertiesBridgeBuilder addOverride(String propertyName, Object value) { + overrideValues.put(propertyName, value); + return this; + } + + /** Build {@link ConfigProperties} from the {@code autoConfiguredOpenTelemetrySdk}. */ + public ConfigProperties build(AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) { + ConfigProperties sdkConfigProperties = + AutoConfigureUtil.getConfig(autoConfiguredOpenTelemetrySdk); + if (sdkConfigProperties != null) { + return sdkConfigProperties; + } + ConfigProvider configProvider = + AutoConfigureUtil.getConfigProvider(autoConfiguredOpenTelemetrySdk); + if (configProvider != null) { + return buildFromInstrumentationConfig(configProvider.getInstrumentationConfig()); + } + // Should never happen + throw new IllegalStateException( + "AutoConfiguredOpenTelemetrySdk does not have ConfigProperties or DeclarativeConfigProperties. This is likely a programming error in opentelemetry-java"); + } + + /** + * Build {@link ConfigProperties} from the {@link DeclarativeConfigProperties} provided by the + * instrumentation configuration. + * + *

If the provided {@code instrumentationConfig} is null, an empty {@link + * DeclarativeConfigProperties} will be used. + * + * @param instrumentationConfig the instrumentation configuration to build from + * @return a new instance of {@link ConfigProperties} + */ + public ConfigProperties buildFromInstrumentationConfig( + @Nullable DeclarativeConfigProperties instrumentationConfig) { + // leave the name "build" for a future method that builds from a DeclarativeConfigProperties + // instance that doesn't come from the top-level instrumentation config + if (instrumentationConfig == null) { + instrumentationConfig = DeclarativeConfigProperties.empty(); + } + return new DeclarativeConfigPropertiesBridge( + instrumentationConfig.getStructured("java", empty()), mappings, overrideValues); + } +} diff --git a/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/extension/internal/ConfigPropertiesUtilTest.java b/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/extension/internal/DeclarativeConfigPropertiesBridgeBuilderTest.java similarity index 87% rename from javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/extension/internal/ConfigPropertiesUtilTest.java rename to javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/extension/internal/DeclarativeConfigPropertiesBridgeBuilderTest.java index 67d2fe5fc568..dd41958eebcb 100644 --- a/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/extension/internal/ConfigPropertiesUtilTest.java +++ b/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/extension/internal/DeclarativeConfigPropertiesBridgeBuilderTest.java @@ -21,7 +21,7 @@ import org.mockito.Mockito; @SuppressWarnings("DoNotMockAutoValue") -class ConfigPropertiesUtilTest { +class DeclarativeConfigPropertiesBridgeBuilderTest { @Test void shouldUseConfigPropertiesForAutoConfiguration() { ConfigProperties configPropertiesMock = mock(ConfigProperties.class); @@ -32,7 +32,8 @@ void shouldUseConfigPropertiesForAutoConfiguration() { .when(() -> AutoConfigureUtil.getConfig(sdkMock)) .thenReturn(configPropertiesMock); - ConfigProperties configProperties = ConfigPropertiesUtil.resolveConfigProperties(sdkMock); + ConfigProperties configProperties = + new DeclarativeConfigPropertiesBridgeBuilder().build(sdkMock); assertThat(configProperties).isSameAs(configPropertiesMock); } @@ -60,7 +61,8 @@ void shouldUseConfigProviderForDeclarativeConfiguration() { .when(() -> AutoConfigureUtil.getConfigProvider(sdkMock)) .thenReturn(configProviderMock); - ConfigProperties configProperties = ConfigPropertiesUtil.resolveConfigProperties(sdkMock); + ConfigProperties configProperties = + new DeclarativeConfigPropertiesBridgeBuilder().build(sdkMock); assertThat(configProperties.getString(propertyName)).isEqualTo(expectedValue); } @@ -79,9 +81,10 @@ void shouldUseConfigProviderForDeclarativeConfiguration_noInstrumentationConfig( .when(() -> AutoConfigureUtil.getConfigProvider(sdkMock)) .thenReturn(configProviderMock); - ConfigProperties configProperties = ConfigPropertiesUtil.resolveConfigProperties(sdkMock); + ConfigProperties configProperties = + new DeclarativeConfigPropertiesBridgeBuilder().build(sdkMock); - assertThat(configProperties.getString("testProperty")).isEqualTo(null); + assertThat(configProperties.getString("testProperty")).isNull(); } } } diff --git a/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/extension/internal/DeclarativeConfigPropertiesBridgeTest.java b/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/extension/internal/DeclarativeConfigPropertiesBridgeTest.java index ba5ca8519352..deeb424b8abe 100644 --- a/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/extension/internal/DeclarativeConfigPropertiesBridgeTest.java +++ b/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/extension/internal/DeclarativeConfigPropertiesBridgeTest.java @@ -12,8 +12,6 @@ import io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.InstrumentationModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; -import java.io.ByteArrayInputStream; -import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.Arrays; import java.util.HashMap; @@ -24,51 +22,31 @@ class DeclarativeConfigPropertiesBridgeTest { - private static final String YAML = - "file_format: 0.4\n" - + "instrumentation/development:\n" - + " java:\n" - + " common:\n" - + " default-enabled: true\n" - + " runtime-telemetry:\n" - + " enabled: false\n" - + " example-instrumentation:\n" - + " string_key: value\n" - + " bool_key: true\n" - + " int_key: 1\n" - + " double_key: 1.1\n" - + " list_key:\n" - + " - value1\n" - + " - value2\n" - + " - true\n" - + " map_key:\n" - + " string_key1: value1\n" - + " string_key2: value2\n" - + " bool_key: true\n" - + " acme:\n" - + " full_name:\n" - + " preserved: true"; - private ConfigProperties bridge; private ConfigProperties emptyBridge; @BeforeEach void setup() { - OpenTelemetryConfigurationModel model = - DeclarativeConfiguration.parse( - new ByteArrayInputStream(YAML.getBytes(StandardCharsets.UTF_8))); - SdkConfigProvider configProvider = SdkConfigProvider.create(model); - bridge = - new DeclarativeConfigPropertiesBridge( - Objects.requireNonNull(configProvider.getInstrumentationConfig())); + bridge = create(new DeclarativeConfigPropertiesBridgeBuilder()); OpenTelemetryConfigurationModel emptyModel = new OpenTelemetryConfigurationModel() .withAdditionalProperty("instrumentation/development", new InstrumentationModel()); SdkConfigProvider emptyConfigProvider = SdkConfigProvider.create(emptyModel); emptyBridge = - new DeclarativeConfigPropertiesBridge( - Objects.requireNonNull(emptyConfigProvider.getInstrumentationConfig())); + new DeclarativeConfigPropertiesBridgeBuilder() + .buildFromInstrumentationConfig( + Objects.requireNonNull(emptyConfigProvider.getInstrumentationConfig())); + } + + private static ConfigProperties create(DeclarativeConfigPropertiesBridgeBuilder builder) { + OpenTelemetryConfigurationModel model = + DeclarativeConfiguration.parse( + DeclarativeConfigPropertiesBridgeTest.class + .getClassLoader() + .getResourceAsStream("config.yaml")); + return builder.buildFromInstrumentationConfig( + SdkConfigProvider.create(model).getInstrumentationConfig()); } @Test @@ -82,7 +60,6 @@ void getProperties() { .isTrue(); // common cases - assertThat(bridge.getBoolean("otel.instrumentation.common.default-enabled")).isTrue(); assertThat(bridge.getBoolean("otel.instrumentation.runtime-telemetry.enabled")).isFalse(); // check all the types @@ -135,9 +112,33 @@ void getProperties() { .isEqualTo(Arrays.asList("value1", "value2")); assertThat(bridge.getMap("otel.instrumentation.other-instrumentation.map_key", expectedMap)) .isEqualTo(expectedMap); + } + @Test + void vendor() { // verify vendor specific property names are preserved in unchanged form (prefix is not stripped // as for otel.instrumentation.*) assertThat(bridge.getBoolean("acme.full_name.preserved")).isTrue(); } + + @Test + void vendorTranslation() { + ConfigProperties propertiesBridge = + create(new DeclarativeConfigPropertiesBridgeBuilder().addMapping("acme", "acme.full_name")); + assertThat(propertiesBridge.getBoolean("acme.preserved")).isTrue(); + } + + @Test + void agentTranslation() { + ConfigProperties bridge = + create( + new DeclarativeConfigPropertiesBridgeBuilder() + .addMapping("otel.javaagent", "agent") + .addOverride("otel.javaagent.debug", true) + .addOverride("otel.javaagent.logging", "application")); + + assertThat(bridge.getBoolean("otel.javaagent.debug")).isTrue(); + assertThat(bridge.getBoolean("otel.javaagent.experimental.indy")).isTrue(); + assertThat(bridge.getString("otel.javaagent.logging")).isEqualTo("application"); + } } diff --git a/javaagent-tooling/src/test/resources/config.yaml b/javaagent-extension-api/src/test/resources/config.yaml similarity index 54% rename from javaagent-tooling/src/test/resources/config.yaml rename to javaagent-extension-api/src/test/resources/config.yaml index 02642e40fe24..e0f2020bda37 100644 --- a/javaagent-tooling/src/test/resources/config.yaml +++ b/javaagent-extension-api/src/test/resources/config.yaml @@ -1,12 +1,15 @@ -instrumentation: +file_format: 0.4 +instrumentation/development: java: - common: - default-enabled: true - runtime-telemetry: + acme: + full_name: + preserved: true + agent: + experimental: + indy: true + runtime_telemetry: enabled: false - external-annotations: - enabled: true - example-instrumentation: + example_instrumentation: string_key: value bool_key: true int_key: 1 @@ -14,6 +17,7 @@ instrumentation: list_key: - value1 - value2 + - true map_key: string_key1: value1 string_key2: value2 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 055f3c5ed2d9..948d0352844e 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 @@ -33,7 +33,6 @@ import io.opentelemetry.javaagent.extension.AgentListener; import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesConfigurer; import io.opentelemetry.javaagent.extension.instrumentation.internal.EarlyInstrumentationModule; -import io.opentelemetry.javaagent.extension.internal.ConfigPropertiesUtil; import io.opentelemetry.javaagent.tooling.asyncannotationsupport.WeakRefAsyncOperationEndStrategies; import io.opentelemetry.javaagent.tooling.bootstrap.BootstrapPackagesBuilderImpl; import io.opentelemetry.javaagent.tooling.bootstrap.BootstrapPackagesConfigurer; @@ -162,12 +161,10 @@ private static void installBytebuddyAgent( installEarlyInstrumentation(agentBuilder, inst); - // If noop OpenTelemetry is enabled, autoConfiguredSdk will be null and AgentListeners are not - // called AutoConfiguredOpenTelemetrySdk autoConfiguredSdk = - installOpenTelemetrySdk(extensionClassLoader); + installOpenTelemetrySdk(extensionClassLoader, earlyConfig); - ConfigProperties sdkConfig = ConfigPropertiesUtil.resolveConfigProperties(autoConfiguredSdk); + ConfigProperties sdkConfig = AutoConfigureUtil.getConfig(autoConfiguredSdk); AgentInstrumentationConfig.internalInitializeConfig( new ConfigPropertiesBridge( sdkConfig, AutoConfigureUtil.getConfigProvider(autoConfiguredSdk))); @@ -175,7 +172,7 @@ private static void installBytebuddyAgent( setBootstrapPackages(sdkConfig, extensionClassLoader); ConfiguredResourceAttributesHolder.initialize( - SdkAutoconfigureAccess.getResourceAttributes(autoConfiguredSdk)); + SdkAutoconfigureAccess.getResource(autoConfiguredSdk).getAttributes()); for (BeforeAgentListener agentListener : loadOrdered(BeforeAgentListener.class, extensionClassLoader)) { diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/OpenTelemetryInstaller.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/OpenTelemetryInstaller.java index 7b939c6f927c..29c08e7dbe75 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/OpenTelemetryInstaller.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/OpenTelemetryInstaller.java @@ -5,9 +5,14 @@ package io.opentelemetry.javaagent.tooling; +import io.opentelemetry.api.incubator.config.ConfigProvider; import io.opentelemetry.javaagent.bootstrap.OpenTelemetrySdkAccess; +import io.opentelemetry.javaagent.extension.internal.DeclarativeConfigPropertiesBridgeBuilder; +import io.opentelemetry.javaagent.tooling.config.EarlyInitAgentConfig; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.SdkAutoconfigureAccess; +import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.common.CompletableResultCode; import java.util.Arrays; @@ -20,15 +25,42 @@ public final class OpenTelemetryInstaller { * @return the {@link AutoConfiguredOpenTelemetrySdk} */ public static AutoConfiguredOpenTelemetrySdk installOpenTelemetrySdk( - ClassLoader extensionClassLoader) { + ClassLoader extensionClassLoader, EarlyInitAgentConfig earlyConfig) { AutoConfiguredOpenTelemetrySdk autoConfiguredSdk = AutoConfiguredOpenTelemetrySdk.builder() .setResultAsGlobal() .setServiceClassLoader(extensionClassLoader) .build(); + ConfigProvider configProvider = AutoConfigureUtil.getConfigProvider(autoConfiguredSdk); OpenTelemetrySdk sdk = autoConfiguredSdk.getOpenTelemetrySdk(); + setForceFlush(sdk); + + if (configProvider != null) { + // We create a new instance of AutoConfiguredOpenTelemetrySdk, which has a ConfigProperties + // instance that can be used to read properties from the configuration file. + // This allows most instrumentations to be unaware of which configuration style is used. + return SdkAutoconfigureAccess.create( + sdk, + SdkAutoconfigureAccess.getResource(autoConfiguredSdk), + new DeclarativeConfigPropertiesBridgeBuilder() + .addMapping("otel.javaagent", "agent") + // these properties are used to initialize the SDK before the configuration file + // is loaded for consistency, we pass them to the bridge, so that they can be read + // later with the same value from the {@link DeclarativeConfigPropertiesBridge} + .addOverride( + "otel.javaagent.debug", earlyConfig.getBoolean("otel.javaagent.debug", false)) + .addOverride( + "otel.javaagent.logging", earlyConfig.getString("otel.javaagent.logging")) + .buildFromInstrumentationConfig(configProvider.getInstrumentationConfig()), + configProvider); + } + + return autoConfiguredSdk; + } + + private static void setForceFlush(OpenTelemetrySdk sdk) { OpenTelemetrySdkAccess.internalSetForceFlush( (timeout, unit) -> { CompletableResultCode traceResult = sdk.getSdkTracerProvider().forceFlush(); @@ -37,8 +69,6 @@ public static AutoConfiguredOpenTelemetrySdk installOpenTelemetrySdk( CompletableResultCode.ofAll(Arrays.asList(traceResult, metricsResult, logsResult)) .join(timeout, unit); }); - - return autoConfiguredSdk; } private OpenTelemetryInstaller() {} 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 788aaf7cde94..035799c06d47 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,6 +5,8 @@ package io.opentelemetry.javaagent.tooling.config; +import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; + import io.opentelemetry.api.incubator.config.ConfigProvider; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; @@ -109,11 +111,27 @@ public Map getMap(String name, Map defaultValue) } } + @Override + public boolean isDeclarative() { + return configProvider != null; + } + + @Override + public DeclarativeConfigProperties getDeclarativeConfig(String node) { + DeclarativeConfigProperties config = + InstrumentationConfigUtil.javaInstrumentationConfig(configProvider, node); + if (config == null) { + // there is no declarative config for this node + // this needs to be a different value than null to avoid confusion with + // the case when declarative config is not supported at all + return empty(); + } + return config; + } + @Nullable @Override - public DeclarativeConfigProperties getDeclarativeConfig(String instrumentationName) { - return configProvider != null - ? InstrumentationConfigUtil.javaInstrumentationConfig(configProvider, instrumentationName) - : null; + public ConfigProvider getConfigProvider() { + return configProvider; } } diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/sdk/autoconfigure/SdkAutoconfigureAccess.java b/javaagent-tooling/src/main/java/io/opentelemetry/sdk/autoconfigure/SdkAutoconfigureAccess.java index 477f5bcbdee4..58271bb842c9 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/sdk/autoconfigure/SdkAutoconfigureAccess.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/sdk/autoconfigure/SdkAutoconfigureAccess.java @@ -5,12 +5,19 @@ package io.opentelemetry.sdk.autoconfigure; -import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.resources.Resource; public final class SdkAutoconfigureAccess { - public static Attributes getResourceAttributes(AutoConfiguredOpenTelemetrySdk sdk) { - return sdk.getResource().getAttributes(); + private SdkAutoconfigureAccess() {} + + public static Resource getResource(AutoConfiguredOpenTelemetrySdk sdk) { + return sdk.getResource(); } - private SdkAutoconfigureAccess() {} + public static AutoConfiguredOpenTelemetrySdk create( + OpenTelemetrySdk sdk, Resource resource, ConfigProperties config, Object configProvider) { + return AutoConfiguredOpenTelemetrySdk.create(sdk, resource, config, configProvider); + } } diff --git a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/OpenTelemetryInstallerTest.groovy b/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/OpenTelemetryInstallerTest.groovy deleted file mode 100755 index 74c9b1932993..000000000000 --- a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/OpenTelemetryInstallerTest.groovy +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.tooling - -import io.opentelemetry.api.GlobalOpenTelemetry -import io.opentelemetry.api.OpenTelemetry -import spock.lang.Specification - -class OpenTelemetryInstallerTest extends Specification { - - void setup() { - GlobalOpenTelemetry.resetForTest() - } - - void cleanup() { - GlobalOpenTelemetry.resetForTest() - } - - def "should initialize GlobalOpenTelemetry"() { - when: - def autoConfiguredSdk = OpenTelemetryInstaller.installOpenTelemetrySdk(OpenTelemetryInstaller.classLoader) - - then: - autoConfiguredSdk != null - GlobalOpenTelemetry.get() != OpenTelemetry.noop() - } - -} diff --git a/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/OpenTelemetryInstallerTest.java b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/OpenTelemetryInstallerTest.java new file mode 100644 index 000000000000..268f4b40ccc7 --- /dev/null +++ b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/OpenTelemetryInstallerTest.java @@ -0,0 +1,34 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.tooling; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.javaagent.tooling.config.EarlyInitAgentConfig; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class OpenTelemetryInstallerTest { + + @BeforeEach + @AfterEach + void setUp() { + GlobalOpenTelemetry.resetForTest(); + } + + @Test + void globalOpenTelemetry() { + AutoConfiguredOpenTelemetrySdk sdk = + OpenTelemetryInstaller.installOpenTelemetrySdk( + EarlyInitAgentConfig.class.getClassLoader(), EarlyInitAgentConfig.create()); + + assertThat(sdk).isNotNull().isNotEqualTo(OpenTelemetry.noop()); + } +} diff --git a/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/config/ConfigurationPropertiesSupplierTest.java b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/config/ConfigurationPropertiesSupplierTest.java index d2083b45933b..93c4b7574999 100644 --- a/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/config/ConfigurationPropertiesSupplierTest.java +++ b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/config/ConfigurationPropertiesSupplierTest.java @@ -18,8 +18,8 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.junitpioneer.jupiter.ClearSystemProperty; @@ -28,9 +28,9 @@ @ClearSystemProperty(key = ConfigurationFile.CONFIGURATION_FILE_PROPERTY) class ConfigurationPropertiesSupplierTest { - @BeforeAll - @AfterAll - static void cleanUp() { + @BeforeEach + @AfterEach + void setUp() { GlobalOpenTelemetry.resetForTest(); ConfigurationFile.resetForTest(); } @@ -46,7 +46,8 @@ void fileConfigOverwritesUserPropertiesSupplier(@TempDir Path tempDir) throws IO // when AutoConfiguredOpenTelemetrySdk autoConfiguredSdk = - OpenTelemetryInstaller.installOpenTelemetrySdk(this.getClass().getClassLoader()); + OpenTelemetryInstaller.installOpenTelemetrySdk( + this.getClass().getClassLoader(), EarlyInitAgentConfig.create()); // then assertThat(AutoConfigureUtil.getConfig(autoConfiguredSdk).getString("custom.key")) diff --git a/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/config/OtlpProtocolPropertiesSupplierTest.java b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/config/OtlpProtocolPropertiesSupplierTest.java index e023d06b44af..cbca89d51548 100644 --- a/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/config/OtlpProtocolPropertiesSupplierTest.java +++ b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/config/OtlpProtocolPropertiesSupplierTest.java @@ -12,13 +12,15 @@ import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junitpioneer.jupiter.SetSystemProperty; class OtlpProtocolPropertiesSupplierTest { + @BeforeEach @AfterEach - void cleanUp() { + void setUp() { GlobalOpenTelemetry.resetForTest(); } @@ -29,7 +31,8 @@ void cleanUp() { void keepUserOtlpProtocolConfiguration() { // when AutoConfiguredOpenTelemetrySdk autoConfiguredSdk = - OpenTelemetryInstaller.installOpenTelemetrySdk(this.getClass().getClassLoader()); + OpenTelemetryInstaller.installOpenTelemetrySdk( + this.getClass().getClassLoader(), EarlyInitAgentConfig.create()); // then assertThat( @@ -41,7 +44,8 @@ void keepUserOtlpProtocolConfiguration() { void defaultHttpProtobufOtlpProtocolConfiguration() { // when AutoConfiguredOpenTelemetrySdk autoConfiguredSdk = - OpenTelemetryInstaller.installOpenTelemetrySdk(this.getClass().getClassLoader()); + OpenTelemetryInstaller.installOpenTelemetrySdk( + this.getClass().getClassLoader(), EarlyInitAgentConfig.create()); // then assertThat( diff --git a/testing/agent-exporter/src/main/java/io/opentelemetry/javaagent/testing/exporter/AgentTestingExporterFactory.java b/testing/agent-exporter/src/main/java/io/opentelemetry/javaagent/testing/exporter/AgentTestingExporterFactory.java index dda3cafdee04..bffc8aed789c 100644 --- a/testing/agent-exporter/src/main/java/io/opentelemetry/javaagent/testing/exporter/AgentTestingExporterFactory.java +++ b/testing/agent-exporter/src/main/java/io/opentelemetry/javaagent/testing/exporter/AgentTestingExporterFactory.java @@ -5,9 +5,6 @@ package io.opentelemetry.javaagent.testing.exporter; -import io.opentelemetry.javaagent.testing.provider.AgentTestLogRecordExporterComponentProvider; -import io.opentelemetry.javaagent.testing.provider.AgentTestMetricExporterComponentProvider; -import io.opentelemetry.javaagent.testing.provider.AgentTestSpanExporterComponentProvider; import java.util.List; import java.util.concurrent.TimeUnit; @@ -18,13 +15,7 @@ public final class AgentTestingExporterFactory { static final OtlpInMemoryLogRecordExporter logExporter = new OtlpInMemoryLogRecordExporter(); static { - init(); - } - - public static void init() { - AgentTestSpanExporterComponentProvider.setSpanExporter(spanExporter); - AgentTestMetricExporterComponentProvider.setMetricExporter(metricExporter); - AgentTestLogRecordExporterComponentProvider.setLogRecordExporter(logExporter); + TestExportersUtil.initTestExporters(); } public static List getSpanExportRequests() { diff --git a/testing/agent-exporter/src/main/java/io/opentelemetry/javaagent/testing/exporter/TestExportersUtil.java b/testing/agent-exporter/src/main/java/io/opentelemetry/javaagent/testing/exporter/TestExportersUtil.java new file mode 100644 index 000000000000..0cb67fd1c085 --- /dev/null +++ b/testing/agent-exporter/src/main/java/io/opentelemetry/javaagent/testing/exporter/TestExportersUtil.java @@ -0,0 +1,23 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.testing.exporter; + +import io.opentelemetry.javaagent.testing.provider.AgentTestLogRecordExporterComponentProvider; +import io.opentelemetry.javaagent.testing.provider.AgentTestMetricExporterComponentProvider; +import io.opentelemetry.javaagent.testing.provider.AgentTestSpanExporterComponentProvider; + +public class TestExportersUtil { + private TestExportersUtil() {} + + public static void initTestExporters() { + AgentTestSpanExporterComponentProvider.setSpanExporter( + AgentTestingExporterFactory.spanExporter); + AgentTestMetricExporterComponentProvider.setMetricExporter( + AgentTestingExporterFactory.metricExporter); + AgentTestLogRecordExporterComponentProvider.setLogRecordExporter( + AgentTestingExporterFactory.logExporter); + } +} diff --git a/testing/agent-exporter/src/main/java/io/opentelemetry/javaagent/testing/provider/AgentTestExporterCustomizerProvider.java b/testing/agent-exporter/src/main/java/io/opentelemetry/javaagent/testing/provider/AgentTestExporterCustomizerProvider.java index ae9a7f6e5463..487f1ff5bbf0 100644 --- a/testing/agent-exporter/src/main/java/io/opentelemetry/javaagent/testing/provider/AgentTestExporterCustomizerProvider.java +++ b/testing/agent-exporter/src/main/java/io/opentelemetry/javaagent/testing/provider/AgentTestExporterCustomizerProvider.java @@ -6,7 +6,7 @@ package io.opentelemetry.javaagent.testing.provider; import com.google.auto.service.AutoService; -import io.opentelemetry.javaagent.testing.exporter.AgentTestingExporterFactory; +import io.opentelemetry.javaagent.testing.exporter.TestExportersUtil; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleExporterModel; @@ -32,7 +32,7 @@ public class AgentTestExporterCustomizerProvider implements DeclarativeConfigurationCustomizerProvider { @Override public void customize(DeclarativeConfigurationCustomizer customizer) { - AgentTestingExporterFactory.init(); + TestExportersUtil.initTestExporters(); customizer.addModelCustomizer( model -> {