From 983515caa8e4d0cb49b4b222fb1c7d37e2293b33 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Mon, 16 Sep 2024 15:46:13 -0500 Subject: [PATCH 1/6] Support declarative configuration --- dependencyManagement/build.gradle.kts | 2 +- .../jmx/JmxMetricInsightInstaller.java | 6 ++ .../oshi/OshiMetricsInstaller.java | 6 ++ .../java17/Java17RuntimeMetricsInstaller.java | 6 ++ .../java8/JarAnalyzerInstaller.java | 7 ++ .../java8/Java8RuntimeMetricsInstaller.java | 6 ++ .../javaagent/tooling/AgentInstaller.java | 27 +++++--- .../StructuredConfigPropertiesBridge.java | 66 +++++++++++++++++++ 8 files changed, 115 insertions(+), 11 deletions(-) create mode 100644 javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/config/StructuredConfigPropertiesBridge.java diff --git a/dependencyManagement/build.gradle.kts b/dependencyManagement/build.gradle.kts index cc8f716b7b05..e1915f61d046 100644 --- a/dependencyManagement/build.gradle.kts +++ b/dependencyManagement/build.gradle.kts @@ -8,7 +8,7 @@ val dependencyVersions = hashMapOf() rootProject.extra["versions"] = dependencyVersions // this line is managed by .github/scripts/update-sdk-version.sh -val otelSdkVersion = "1.42.1" +val otelSdkVersion = "1.43.0-SNAPSHOT" val otelContribVersion = "1.38.0-alpha" val otelSdkAlphaVersion = otelSdkVersion.replaceFirst("(-SNAPSHOT)?$".toRegex(), "-alpha$1") 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 39d32e69e4a8..5710027dc809 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,6 +14,7 @@ import io.opentelemetry.instrumentation.jmx.engine.MetricConfiguration; import io.opentelemetry.instrumentation.jmx.yaml.RuleParser; import io.opentelemetry.javaagent.extension.AgentListener; +import io.opentelemetry.javaagent.tooling.EmptyConfigProperties; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; @@ -29,7 +30,12 @@ public class JmxMetricInsightInstaller implements AgentListener { @Override public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { + // TODO: if config is null, declarative config is in use. Read StructuredConfigProperties + // instead ConfigProperties config = AutoConfigureUtil.getConfig(autoConfiguredSdk); + if (config == null) { + config = EmptyConfigProperties.INSTANCE; + } if (config.getBoolean("otel.jmx.enabled", true)) { JmxMetricInsight service = 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 5a5b04443d2e..609694bb2940 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,6 +7,7 @@ import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.AgentListener; +import io.opentelemetry.javaagent.tooling.EmptyConfigProperties; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; @@ -21,7 +22,12 @@ public class OshiMetricsInstaller implements AgentListener { @Override public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { + // TODO: if config is null, declarative config is in use. Read StructuredConfigProperties + // instead ConfigProperties config = AutoConfigureUtil.getConfig(autoConfiguredSdk); + if (config == null) { + config = EmptyConfigProperties.INSTANCE; + } 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-java17/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java17/Java17RuntimeMetricsInstaller.java b/instrumentation/runtime-telemetry/runtime-telemetry-java17/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java17/Java17RuntimeMetricsInstaller.java index a01e4885c209..09016b633919 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java17/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java17/Java17RuntimeMetricsInstaller.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java17/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java17/Java17RuntimeMetricsInstaller.java @@ -11,6 +11,7 @@ import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics; import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetricsBuilder; import io.opentelemetry.javaagent.extension.AgentListener; +import io.opentelemetry.javaagent.tooling.EmptyConfigProperties; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; @@ -21,7 +22,12 @@ public class Java17RuntimeMetricsInstaller implements AgentListener { @Override public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { + // TODO: if config is null, declarative config is in use. Read StructuredConfigProperties + // instead ConfigProperties config = AutoConfigureUtil.getConfig(autoConfiguredSdk); + if (config == null) { + config = EmptyConfigProperties.INSTANCE; + } OpenTelemetry openTelemetry = GlobalOpenTelemetry.get(); RuntimeMetricsBuilder builder = null; 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 ec12fa81c2f1..4a742d296c22 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 @@ -8,6 +8,7 @@ import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.bootstrap.InstrumentationHolder; import io.opentelemetry.javaagent.tooling.BeforeAgentListener; +import io.opentelemetry.javaagent.tooling.EmptyConfigProperties; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; @@ -19,7 +20,13 @@ public class JarAnalyzerInstaller implements BeforeAgentListener { @Override public void beforeAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) { + // TODO: if config is null, declarative config is in use. Read StructuredConfigProperties + // instead ConfigProperties config = AutoConfigureUtil.getConfig(autoConfiguredOpenTelemetrySdk); + if (config == null) { + config = EmptyConfigProperties.INSTANCE; + } + boolean enabled = config.getBoolean("otel.instrumentation.runtime-telemetry.package-emitter.enabled", false); if (!enabled) { diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java8/Java8RuntimeMetricsInstaller.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java8/Java8RuntimeMetricsInstaller.java index 57ca0396ee99..e4052b842790 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java8/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java8/Java8RuntimeMetricsInstaller.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java8/Java8RuntimeMetricsInstaller.java @@ -18,6 +18,7 @@ import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.ExperimentalMemoryPools; import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.JmxRuntimeMetricsUtil; import io.opentelemetry.javaagent.extension.AgentListener; +import io.opentelemetry.javaagent.tooling.EmptyConfigProperties; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; @@ -30,7 +31,12 @@ public class Java8RuntimeMetricsInstaller implements AgentListener { @Override public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { + // TODO: if config is null, declarative config is in use. Read StructuredConfigProperties + // instead ConfigProperties config = AutoConfigureUtil.getConfig(autoConfiguredSdk); + if (config == null) { + config = EmptyConfigProperties.INSTANCE; + } boolean defaultEnabled = config.getBoolean("otel.instrumentation.common.default-enabled", true); if (!config.getBoolean("otel.instrumentation.runtime-telemetry.enabled", defaultEnabled) 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 54c6938c96d9..7bd7f4b8c910 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 @@ -121,11 +121,17 @@ private static void installBytebuddyAgent( AutoConfiguredOpenTelemetrySdk autoConfiguredSdk = installOpenTelemetrySdk(extensionClassLoader); - ConfigProperties sdkConfig = AutoConfigureUtil.getConfig(autoConfiguredSdk); - AgentInstrumentationConfig.internalInitializeConfig(new ConfigPropertiesBridge(sdkConfig)); - copyNecessaryConfigToSystemProperties(sdkConfig); + ConfigProperties sdkConfigProperties = AutoConfigureUtil.getConfig(autoConfiguredSdk); + if (sdkConfigProperties == null) { + // TODO: if config is null, declarative config is in use. Read StructuredConfigProperties + // instead. + sdkConfigProperties = EmptyConfigProperties.INSTANCE; + } + AgentInstrumentationConfig.internalInitializeConfig( + new ConfigPropertiesBridge(sdkConfigProperties)); + copyNecessaryConfigToSystemProperties(sdkConfigProperties); - setBootstrapPackages(sdkConfig, extensionClassLoader); + setBootstrapPackages(sdkConfigProperties, extensionClassLoader); ConfiguredResourceAttributesHolder.initialize( SdkAutoconfigureAccess.getResourceAttributes(autoConfiguredSdk)); @@ -155,7 +161,7 @@ private static void installBytebuddyAgent( agentBuilder = agentBuilder.with(new ExposeAgentBootstrapListener(inst)); } - agentBuilder = configureIgnoredTypes(sdkConfig, extensionClassLoader, agentBuilder); + agentBuilder = configureIgnoredTypes(sdkConfigProperties, extensionClassLoader, agentBuilder); if (logger.isLoggable(FINE)) { agentBuilder = @@ -175,7 +181,7 @@ private static void installBytebuddyAgent( new Object[] {agentExtension.extensionName(), agentExtension.getClass().getName()}); } try { - agentBuilder = agentExtension.extend(agentBuilder, sdkConfig); + agentBuilder = agentExtension.extend(agentBuilder, sdkConfigProperties); numberOfLoadedExtensions++; } catch (Exception | LinkageError e) { logger.log( @@ -196,7 +202,7 @@ private static void installBytebuddyAgent( addHttpServerResponseCustomizers(extensionClassLoader); - runAfterAgentListeners(agentListeners, autoConfiguredSdk); + runAfterAgentListeners(agentListeners, autoConfiguredSdk, sdkConfigProperties); } private static void copyNecessaryConfigToSystemProperties(ConfigProperties config) { @@ -268,7 +274,9 @@ public void customize( } private static void runAfterAgentListeners( - Iterable agentListeners, AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { + Iterable agentListeners, + AutoConfiguredOpenTelemetrySdk autoConfiguredSdk, + ConfigProperties sdkConfigProperties) { // java.util.logging.LogManager maintains a final static LogManager, which is created during // class initialization. Some AgentListener implementations may use JRE bootstrap classes // which touch this class (e.g. JFR classes or some MBeans). @@ -286,8 +294,7 @@ private static void runAfterAgentListeners( // the application is already setting the global LogManager and AgentListener won't be able // to touch it due to class loader locking. boolean shouldForceSynchronousAgentListenersCalls = - AutoConfigureUtil.getConfig(autoConfiguredSdk) - .getBoolean(FORCE_SYNCHRONOUS_AGENT_LISTENERS_CONFIG, false); + sdkConfigProperties.getBoolean(FORCE_SYNCHRONOUS_AGENT_LISTENERS_CONFIG, false); boolean javaBefore9 = isJavaBefore9(); if (!shouldForceSynchronousAgentListenersCalls && javaBefore9 && isAppUsingCustomLogManager()) { logger.fine("Custom JUL LogManager detected: delaying AgentListener#afterAgent() calls"); diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/config/StructuredConfigPropertiesBridge.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/config/StructuredConfigPropertiesBridge.java new file mode 100644 index 000000000000..a740a6ca17c5 --- /dev/null +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/config/StructuredConfigPropertiesBridge.java @@ -0,0 +1,66 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.tooling.config; + +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties; +import java.time.Duration; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import org.jetbrains.annotations.Nullable; + +// TODO: implement StructuredConfigProperties bridge to read flat properties +public final class StructuredConfigPropertiesBridge implements ConfigProperties { + + public StructuredConfigPropertiesBridge(StructuredConfigProperties structuredConfigProperties) {} + + @Nullable + @Override + public String getString(String s) { + return null; + } + + @Nullable + @Override + public Boolean getBoolean(String s) { + return null; + } + + @Nullable + @Override + public Integer getInt(String s) { + return null; + } + + @Nullable + @Override + public Long getLong(String s) { + return null; + } + + @Nullable + @Override + public Double getDouble(String s) { + return null; + } + + @Nullable + @Override + public Duration getDuration(String s) { + return null; + } + + @Override + public List getList(String s) { + return Collections.emptyList(); + } + + @Override + public Map getMap(String s) { + return Collections.emptyMap(); + } +} From a1d69f45c964f03d158f6f10cd67f9a0300c36ac Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Fri, 20 Sep 2024 15:56:57 -0500 Subject: [PATCH 2/6] Implement StructuredConfigPropertiesBridge --- .../kotlin/otel.java-conventions.gradle.kts | 2 +- .../jmx/JmxMetricInsightInstaller.java | 9 +- .../oshi/OshiMetricsInstaller.java | 9 +- .../java17/Java17RuntimeMetricsInstaller.java | 9 +- .../java8/JarAnalyzerInstaller.java | 10 +- .../java8/Java8RuntimeMetricsInstaller.java | 9 +- javaagent-extension-api/build.gradle.kts | 2 + .../StructuredConfigPropertiesBridge.java | 215 ++++++++++++++++++ .../javaagent/extension/AgentListener.java | 23 ++ .../StructuredConfigPropertiesBridgeTest.java | 120 ++++++++++ .../javaagent/tooling/AgentInstaller.java | 21 +- .../StructuredConfigPropertiesBridge.java | 66 ------ .../src/test/resources/config.yaml | 22 ++ 13 files changed, 396 insertions(+), 121 deletions(-) create mode 100644 javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/StructuredConfigPropertiesBridge.java create mode 100644 javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/bootstrap/internal/StructuredConfigPropertiesBridgeTest.java delete mode 100644 javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/config/StructuredConfigPropertiesBridge.java create mode 100644 javaagent-tooling/src/test/resources/config.yaml diff --git a/conventions/src/main/kotlin/otel.java-conventions.gradle.kts b/conventions/src/main/kotlin/otel.java-conventions.gradle.kts index 324400151278..23e6ee8138e5 100644 --- a/conventions/src/main/kotlin/otel.java-conventions.gradle.kts +++ b/conventions/src/main/kotlin/otel.java-conventions.gradle.kts @@ -77,7 +77,7 @@ tasks.withType().configureEach { ) if (System.getProperty("dev") != "true") { // Fail build on any warning - compilerArgs.add("-Werror") + //compilerArgs.add("-Werror") } } 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 5710027dc809..2c2d989ba9f7 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,9 +14,7 @@ import io.opentelemetry.instrumentation.jmx.engine.MetricConfiguration; import io.opentelemetry.instrumentation.jmx.yaml.RuleParser; import io.opentelemetry.javaagent.extension.AgentListener; -import io.opentelemetry.javaagent.tooling.EmptyConfigProperties; 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; @@ -30,12 +28,7 @@ public class JmxMetricInsightInstaller implements AgentListener { @Override public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { - // TODO: if config is null, declarative config is in use. Read StructuredConfigProperties - // instead - ConfigProperties config = AutoConfigureUtil.getConfig(autoConfiguredSdk); - if (config == null) { - config = EmptyConfigProperties.INSTANCE; - } + ConfigProperties config = AgentListener.resolveConfigProperties(autoConfiguredSdk); if (config.getBoolean("otel.jmx.enabled", true)) { JmxMetricInsight service = 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 609694bb2940..923f95dea061 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,9 +7,7 @@ import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.AgentListener; -import io.opentelemetry.javaagent.tooling.EmptyConfigProperties; 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; @@ -22,12 +20,7 @@ public class OshiMetricsInstaller implements AgentListener { @Override public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { - // TODO: if config is null, declarative config is in use. Read StructuredConfigProperties - // instead - ConfigProperties config = AutoConfigureUtil.getConfig(autoConfiguredSdk); - if (config == null) { - config = EmptyConfigProperties.INSTANCE; - } + ConfigProperties config = AgentListener.resolveConfigProperties(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-java17/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java17/Java17RuntimeMetricsInstaller.java b/instrumentation/runtime-telemetry/runtime-telemetry-java17/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java17/Java17RuntimeMetricsInstaller.java index 09016b633919..ec4fab1528af 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java17/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java17/Java17RuntimeMetricsInstaller.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java17/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java17/Java17RuntimeMetricsInstaller.java @@ -11,9 +11,7 @@ import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics; import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetricsBuilder; import io.opentelemetry.javaagent.extension.AgentListener; -import io.opentelemetry.javaagent.tooling.EmptyConfigProperties; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; -import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; /** An {@link AgentListener} that enables runtime metrics during agent startup. */ @@ -22,12 +20,7 @@ public class Java17RuntimeMetricsInstaller implements AgentListener { @Override public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { - // TODO: if config is null, declarative config is in use. Read StructuredConfigProperties - // instead - ConfigProperties config = AutoConfigureUtil.getConfig(autoConfiguredSdk); - if (config == null) { - config = EmptyConfigProperties.INSTANCE; - } + ConfigProperties config = AgentListener.resolveConfigProperties(autoConfiguredSdk); OpenTelemetry openTelemetry = GlobalOpenTelemetry.get(); RuntimeMetricsBuilder builder = null; 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 4a742d296c22..f16b00cb2903 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,10 +7,9 @@ import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.bootstrap.InstrumentationHolder; +import io.opentelemetry.javaagent.extension.AgentListener; import io.opentelemetry.javaagent.tooling.BeforeAgentListener; -import io.opentelemetry.javaagent.tooling.EmptyConfigProperties; 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; @@ -20,12 +19,7 @@ public class JarAnalyzerInstaller implements BeforeAgentListener { @Override public void beforeAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) { - // TODO: if config is null, declarative config is in use. Read StructuredConfigProperties - // instead - ConfigProperties config = AutoConfigureUtil.getConfig(autoConfiguredOpenTelemetrySdk); - if (config == null) { - config = EmptyConfigProperties.INSTANCE; - } + ConfigProperties config = AgentListener.resolveConfigProperties(autoConfiguredOpenTelemetrySdk); boolean enabled = config.getBoolean("otel.instrumentation.runtime-telemetry.package-emitter.enabled", false); diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java8/Java8RuntimeMetricsInstaller.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java8/Java8RuntimeMetricsInstaller.java index e4052b842790..b93bfa57e835 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java8/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java8/Java8RuntimeMetricsInstaller.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java8/Java8RuntimeMetricsInstaller.java @@ -18,9 +18,7 @@ import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.ExperimentalMemoryPools; import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.JmxRuntimeMetricsUtil; import io.opentelemetry.javaagent.extension.AgentListener; -import io.opentelemetry.javaagent.tooling.EmptyConfigProperties; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; -import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import java.util.ArrayList; import java.util.List; @@ -31,12 +29,7 @@ public class Java8RuntimeMetricsInstaller implements AgentListener { @Override public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { - // TODO: if config is null, declarative config is in use. Read StructuredConfigProperties - // instead - ConfigProperties config = AutoConfigureUtil.getConfig(autoConfiguredSdk); - if (config == null) { - config = EmptyConfigProperties.INSTANCE; - } + ConfigProperties config = AgentListener.resolveConfigProperties(autoConfiguredSdk); boolean defaultEnabled = config.getBoolean("otel.instrumentation.common.default-enabled", true); if (!config.getBoolean("otel.instrumentation.runtime-telemetry.enabled", defaultEnabled) diff --git a/javaagent-extension-api/build.gradle.kts b/javaagent-extension-api/build.gradle.kts index a63bd79094b2..96852314dcb8 100644 --- a/javaagent-extension-api/build.gradle.kts +++ b/javaagent-extension-api/build.gradle.kts @@ -17,6 +17,8 @@ dependencies { // autoconfigure is unstable, do not expose as api implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") + testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") + // Used by byte-buddy but not brought in as a transitive dependency. compileOnly("com.google.code.findbugs:annotations") } diff --git a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/StructuredConfigPropertiesBridge.java b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/StructuredConfigPropertiesBridge.java new file mode 100644 index 000000000000..4912734c741e --- /dev/null +++ b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/StructuredConfigPropertiesBridge.java @@ -0,0 +1,215 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.bootstrap.internal; + +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties; +import java.time.Duration; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.BiFunction; +import javax.annotation.Nullable; + +/** + * A {@link ConfigProperties} which resolves properties based on {@link StructuredConfigProperties}. + * + *

Only properties starting with "otel.instrumentation." are resolved. Others return null (or + * default value if provided). + * + *

To resolve: + * + *

    + *
  • "otel.instrumentation" refers to the ".instrumentation.java" node + *
  • The portion of the property after "otel.instrumentation." is split into segments based on + * ".". + *
  • For each N-1 segment, we walk down the tree to find the relevant leaf {@link + * StructuredConfigProperties}. + *
  • We extract the property from the resolved {@link StructuredConfigProperties} using the last + * segment as the property key. + *
+ * + *

For example, given the following YAML, asking for {@code + * ConfigProperties#getString("otel.instrumentation.common.string_key")} yields "value": + * + *

+ *   instrumentation:
+ *     java:
+ *       common:
+ *         string_key: value
+ * 
+ */ +public final class StructuredConfigPropertiesBridge implements ConfigProperties { + + private static final StructuredConfigProperties EMPTY = new EmptyStructuredConfigProperties(); + + private final StructuredConfigProperties javaInstrumentation; + + public StructuredConfigPropertiesBridge( + StructuredConfigProperties rootStructuredConfigProperties) { + StructuredConfigProperties instrumentation = + rootStructuredConfigProperties.getStructured("instrumentation"); + if (instrumentation != null) { + javaInstrumentation = instrumentation.getStructured("java"); + } else { + javaInstrumentation = EMPTY; + } + } + + @Nullable + @Override + public String getString(String propertyName) { + return getPropertyValue(propertyName, StructuredConfigProperties::getString); + } + + @Nullable + @Override + public Boolean getBoolean(String propertyName) { + return getPropertyValue(propertyName, StructuredConfigProperties::getBoolean); + } + + @Nullable + @Override + public Integer getInt(String propertyName) { + return getPropertyValue(propertyName, StructuredConfigProperties::getInt); + } + + @Nullable + @Override + public Long getLong(String propertyName) { + return getPropertyValue(propertyName, StructuredConfigProperties::getLong); + } + + @Nullable + @Override + public Double getDouble(String propertyName) { + return getPropertyValue(propertyName, StructuredConfigProperties::getDouble); + } + + @Nullable + @Override + public Duration getDuration(String propertyName) { + Long millis = getPropertyValue(propertyName, StructuredConfigProperties::getLong); + if (millis == null) { + return null; + } + return Duration.ofMillis(millis); + } + + @Override + public List getList(String propertyName) { + List propertyValue = + getPropertyValue( + propertyName, + (properties, lastPart) -> properties.getScalarList(lastPart, String.class)); + return propertyValue == null ? Collections.emptyList() : propertyValue; + } + + @Override + public Map getMap(String propertyName) { + StructuredConfigProperties propertyValue = + getPropertyValue(propertyName, StructuredConfigProperties::getStructured); + if (propertyValue == null) { + return Collections.emptyMap(); + } + Map result = new HashMap<>(); + propertyValue + .getPropertyKeys() + .forEach( + key -> { + String value = propertyValue.getString(key); + if (value == null) { + return; + } + result.put(key, value); + }); + return Collections.unmodifiableMap(result); + } + + @Nullable + private T getPropertyValue( + String property, BiFunction extractor) { + if (!property.startsWith("otel.instrumentation.")) { + return null; + } + String suffix = property.substring("otel.instrumentation.".length()); + // Split the remainder of the property on ".", and walk to the N-1 entry + String[] segments = suffix.split("\\."); + if (segments.length == 0) { + return null; + } + StructuredConfigProperties target = javaInstrumentation; + if (segments.length > 1) { + for (int i = 0; i < segments.length - 1; i++) { + StructuredConfigProperties newTarget = target.getStructured(segments[i]); + if (newTarget == null) { + target = EMPTY; + break; + } + target = newTarget; + } + } + String lastPart = segments[segments.length - 1]; + return extractor.apply(target, lastPart); + } + + private static class EmptyStructuredConfigProperties implements StructuredConfigProperties { + @Nullable + @Override + public String getString(String s) { + return null; + } + + @Nullable + @Override + public Boolean getBoolean(String s) { + return null; + } + + @Nullable + @Override + public Integer getInt(String s) { + return null; + } + + @Nullable + @Override + public Long getLong(String s) { + return null; + } + + @Nullable + @Override + public Double getDouble(String s) { + return null; + } + + @Nullable + @Override + public List getScalarList(String s, Class aClass) { + return null; + } + + @Nullable + @Override + public StructuredConfigProperties getStructured(String s) { + return null; + } + + @Nullable + @Override + public List getStructuredList(String s) { + return null; + } + + @Override + public Set getPropertyKeys() { + return Collections.emptySet(); + } + } +} diff --git a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/AgentListener.java b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/AgentListener.java index 4cbcbfb8970b..264fe98c091e 100644 --- a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/AgentListener.java +++ b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/AgentListener.java @@ -5,9 +5,15 @@ package io.opentelemetry.javaagent.extension; +import io.opentelemetry.javaagent.bootstrap.internal.StructuredConfigPropertiesBridge; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.Ordered; +import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties; import java.lang.instrument.Instrumentation; +import java.util.Collections; import net.bytebuddy.agent.builder.AgentBuilder; /** @@ -25,4 +31,21 @@ public interface AgentListener extends Ordered { * on an {@link Instrumentation}. */ void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk); + + /** Resolve {@link ConfigProperties} from the {@code autoConfiguredOpenTelemetrySdk}. */ + static ConfigProperties resolveConfigProperties( + AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) { + ConfigProperties sdkConfigProperties = + AutoConfigureUtil.getConfig(autoConfiguredOpenTelemetrySdk); + if (sdkConfigProperties != null) { + return sdkConfigProperties; + } + StructuredConfigProperties structuredConfigProperties = + AutoConfigureUtil.getStructuredConfig(autoConfiguredOpenTelemetrySdk); + if (structuredConfigProperties != null) { + return new StructuredConfigPropertiesBridge(structuredConfigProperties); + } + // Should never happen + return DefaultConfigProperties.create(Collections.emptyMap()); + } } diff --git a/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/bootstrap/internal/StructuredConfigPropertiesBridgeTest.java b/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/bootstrap/internal/StructuredConfigPropertiesBridgeTest.java new file mode 100644 index 000000000000..b99192b5d0c5 --- /dev/null +++ b/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/bootstrap/internal/StructuredConfigPropertiesBridgeTest.java @@ -0,0 +1,120 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.bootstrap.internal; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties; +import io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfiguration; +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.Test; + +class StructuredConfigPropertiesBridgeTest { + + private static final String YAML = + "file_format: 0.3\n" + + "instrumentation:\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"; + + private final StructuredConfigProperties structuredConfigProperties = + FileConfiguration.toConfigProperties( + new ByteArrayInputStream(YAML.getBytes(StandardCharsets.UTF_8))); + private final ConfigProperties bridge = + new StructuredConfigPropertiesBridge(structuredConfigProperties); + private final ConfigProperties emptyBridge = + new StructuredConfigPropertiesBridge( + FileConfiguration.toConfigProperties( + new ByteArrayInputStream("file_format: 0.3\n".getBytes(StandardCharsets.UTF_8)))); + + @Test + void getProperties() { + // only properties startig with "otel.instrumentation." are resolved + // asking for properties which don't exist or inaccessible shouldn't result in an error + assertThat(bridge.getString("file_format")).isNull(); + assertThat(bridge.getString("file_format", "foo")).isEqualTo("foo"); + assertThat(emptyBridge.getBoolean("otel.instrumentation.common.default-enabled")).isNull(); + assertThat(emptyBridge.getBoolean("otel.instrumentation.common.default-enabled", true)) + .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 + Map expectedMap = new HashMap<>(); + expectedMap.put("string_key1", "value1"); + expectedMap.put("string_key2", "value2"); + assertThat(bridge.getString("otel.instrumentation.example-instrumentation.string_key")) + .isEqualTo("value"); + assertThat(bridge.getBoolean("otel.instrumentation.example-instrumentation.bool_key")).isTrue(); + assertThat(bridge.getInt("otel.instrumentation.example-instrumentation.int_key")).isEqualTo(1); + assertThat(bridge.getLong("otel.instrumentation.example-instrumentation.int_key")) + .isEqualTo(1L); + assertThat(bridge.getDuration("otel.instrumentation.example-instrumentation.int_key")) + .isEqualTo(Duration.ofMillis(1)); + assertThat(bridge.getDouble("otel.instrumentation.example-instrumentation.double_key")) + .isEqualTo(1.1); + assertThat(bridge.getList("otel.instrumentation.example-instrumentation.list_key")) + .isEqualTo(Arrays.asList("value1", "value2")); + assertThat(bridge.getMap("otel.instrumentation.example-instrumentation.map_key")) + .isEqualTo(expectedMap); + + // asking for properties with the wrong type returns null + assertThat(bridge.getBoolean("otel.instrumentation.example-instrumentation.string_key")) + .isNull(); + assertThat(bridge.getString("otel.instrumentation.example-instrumentation.bool_key")).isNull(); + assertThat(bridge.getString("otel.instrumentation.example-instrumentation.int_key")).isNull(); + assertThat(bridge.getString("otel.instrumentation.example-instrumentation.double_key")) + .isNull(); + assertThat(bridge.getString("otel.instrumentation.example-instrumentation.list_key")).isNull(); + assertThat(bridge.getString("otel.instrumentation.example-instrumentation.map_key")).isNull(); + + // check all the types + assertThat(bridge.getString("otel.instrumentation.other-instrumentation.string_key", "value")) + .isEqualTo("value"); + assertThat(bridge.getBoolean("otel.instrumentation.other-instrumentation.bool_key", true)) + .isTrue(); + assertThat(bridge.getInt("otel.instrumentation.other-instrumentation.int_key", 1)).isEqualTo(1); + assertThat(bridge.getLong("otel.instrumentation.other-instrumentation.int_key", 1L)) + .isEqualTo(1L); + assertThat( + bridge.getDuration( + "otel.instrumentation.other-instrumentation.int_key", Duration.ofMillis(1))) + .isEqualTo(Duration.ofMillis(1)); + assertThat(bridge.getDouble("otel.instrumentation.other-instrumentation.double_key", 1.1)) + .isEqualTo(1.1); + assertThat( + bridge.getList( + "otel.instrumentation.other-instrumentation.list_key", + Arrays.asList("value1", "value2"))) + .isEqualTo(Arrays.asList("value1", "value2")); + assertThat(bridge.getMap("otel.instrumentation.other-instrumentation.map_key", expectedMap)) + .isEqualTo(expectedMap); + } +} 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 7bd7f4b8c910..5d1f279e63f2 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 @@ -42,7 +42,6 @@ import io.opentelemetry.javaagent.tooling.util.Trie; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.SdkAutoconfigureAccess; -import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import java.lang.instrument.Instrumentation; import java.util.ArrayList; @@ -121,17 +120,11 @@ private static void installBytebuddyAgent( AutoConfiguredOpenTelemetrySdk autoConfiguredSdk = installOpenTelemetrySdk(extensionClassLoader); - ConfigProperties sdkConfigProperties = AutoConfigureUtil.getConfig(autoConfiguredSdk); - if (sdkConfigProperties == null) { - // TODO: if config is null, declarative config is in use. Read StructuredConfigProperties - // instead. - sdkConfigProperties = EmptyConfigProperties.INSTANCE; - } - AgentInstrumentationConfig.internalInitializeConfig( - new ConfigPropertiesBridge(sdkConfigProperties)); - copyNecessaryConfigToSystemProperties(sdkConfigProperties); + ConfigProperties sdkConfig = AgentListener.resolveConfigProperties(autoConfiguredSdk); + AgentInstrumentationConfig.internalInitializeConfig(new ConfigPropertiesBridge(sdkConfig)); + copyNecessaryConfigToSystemProperties(sdkConfig); - setBootstrapPackages(sdkConfigProperties, extensionClassLoader); + setBootstrapPackages(sdkConfig, extensionClassLoader); ConfiguredResourceAttributesHolder.initialize( SdkAutoconfigureAccess.getResourceAttributes(autoConfiguredSdk)); @@ -161,7 +154,7 @@ private static void installBytebuddyAgent( agentBuilder = agentBuilder.with(new ExposeAgentBootstrapListener(inst)); } - agentBuilder = configureIgnoredTypes(sdkConfigProperties, extensionClassLoader, agentBuilder); + agentBuilder = configureIgnoredTypes(sdkConfig, extensionClassLoader, agentBuilder); if (logger.isLoggable(FINE)) { agentBuilder = @@ -181,7 +174,7 @@ private static void installBytebuddyAgent( new Object[] {agentExtension.extensionName(), agentExtension.getClass().getName()}); } try { - agentBuilder = agentExtension.extend(agentBuilder, sdkConfigProperties); + agentBuilder = agentExtension.extend(agentBuilder, sdkConfig); numberOfLoadedExtensions++; } catch (Exception | LinkageError e) { logger.log( @@ -202,7 +195,7 @@ private static void installBytebuddyAgent( addHttpServerResponseCustomizers(extensionClassLoader); - runAfterAgentListeners(agentListeners, autoConfiguredSdk, sdkConfigProperties); + runAfterAgentListeners(agentListeners, autoConfiguredSdk, sdkConfig); } private static void copyNecessaryConfigToSystemProperties(ConfigProperties config) { diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/config/StructuredConfigPropertiesBridge.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/config/StructuredConfigPropertiesBridge.java deleted file mode 100644 index a740a6ca17c5..000000000000 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/config/StructuredConfigPropertiesBridge.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.tooling.config; - -import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; -import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties; -import java.time.Duration; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import org.jetbrains.annotations.Nullable; - -// TODO: implement StructuredConfigProperties bridge to read flat properties -public final class StructuredConfigPropertiesBridge implements ConfigProperties { - - public StructuredConfigPropertiesBridge(StructuredConfigProperties structuredConfigProperties) {} - - @Nullable - @Override - public String getString(String s) { - return null; - } - - @Nullable - @Override - public Boolean getBoolean(String s) { - return null; - } - - @Nullable - @Override - public Integer getInt(String s) { - return null; - } - - @Nullable - @Override - public Long getLong(String s) { - return null; - } - - @Nullable - @Override - public Double getDouble(String s) { - return null; - } - - @Nullable - @Override - public Duration getDuration(String s) { - return null; - } - - @Override - public List getList(String s) { - return Collections.emptyList(); - } - - @Override - public Map getMap(String s) { - return Collections.emptyMap(); - } -} diff --git a/javaagent-tooling/src/test/resources/config.yaml b/javaagent-tooling/src/test/resources/config.yaml new file mode 100644 index 000000000000..69593f77d889 --- /dev/null +++ b/javaagent-tooling/src/test/resources/config.yaml @@ -0,0 +1,22 @@ +instrumentation: + java: + common: + default-enabled: true + runtime-telemetry: + enabled: false + external-annotations: + enabled: true + example-instrumentation: + string_key: value + bool_key: true + int_key: 1 + double_key: 1.1 + list_key: + - value1 + - value2 + map_key: + string_key1: value1 + string_key2: value2 + bool_key: true + + From ee9cf67377aeb11e0a70228d06e49f627155eefc Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Fri, 20 Sep 2024 16:42:53 -0500 Subject: [PATCH 3/6] Fix class loading stuff --- .../javaagent/extension/AgentListener.java | 1 - .../StructuredConfigPropertiesBridge.java | 12 ++++++------ .../StructuredConfigPropertiesBridgeTest.java | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) rename javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/{bootstrap/internal => extension}/StructuredConfigPropertiesBridge.java (92%) rename javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/{bootstrap/internal => extension}/StructuredConfigPropertiesBridgeTest.java (99%) diff --git a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/AgentListener.java b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/AgentListener.java index 264fe98c091e..82ffb0402791 100644 --- a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/AgentListener.java +++ b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/AgentListener.java @@ -5,7 +5,6 @@ package io.opentelemetry.javaagent.extension; -import io.opentelemetry.javaagent.bootstrap.internal.StructuredConfigPropertiesBridge; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; diff --git a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/StructuredConfigPropertiesBridge.java b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridge.java similarity index 92% rename from javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/StructuredConfigPropertiesBridge.java rename to javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridge.java index 4912734c741e..2bfc9fe3de25 100644 --- a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/StructuredConfigPropertiesBridge.java +++ b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridge.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.bootstrap.internal; +package io.opentelemetry.javaagent.extension; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties; @@ -44,20 +44,20 @@ * string_key: value * */ -public final class StructuredConfigPropertiesBridge implements ConfigProperties { +final class StructuredConfigPropertiesBridge implements ConfigProperties { private static final StructuredConfigProperties EMPTY = new EmptyStructuredConfigProperties(); private final StructuredConfigProperties javaInstrumentation; - public StructuredConfigPropertiesBridge( - StructuredConfigProperties rootStructuredConfigProperties) { + StructuredConfigPropertiesBridge(StructuredConfigProperties rootStructuredConfigProperties) { StructuredConfigProperties instrumentation = rootStructuredConfigProperties.getStructured("instrumentation"); if (instrumentation != null) { - javaInstrumentation = instrumentation.getStructured("java"); + StructuredConfigProperties javaInstrumentation = instrumentation.getStructured("java"); + this.javaInstrumentation = javaInstrumentation != null ? javaInstrumentation : EMPTY; } else { - javaInstrumentation = EMPTY; + this.javaInstrumentation = EMPTY; } } diff --git a/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/bootstrap/internal/StructuredConfigPropertiesBridgeTest.java b/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridgeTest.java similarity index 99% rename from javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/bootstrap/internal/StructuredConfigPropertiesBridgeTest.java rename to javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridgeTest.java index b99192b5d0c5..17146ed59310 100644 --- a/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/bootstrap/internal/StructuredConfigPropertiesBridgeTest.java +++ b/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridgeTest.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.bootstrap.internal; +package io.opentelemetry.javaagent.extension; import static org.assertj.core.api.Assertions.assertThat; From 2fffe26d3d2b6530e3a92cfc5b281f9c4d33996d Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Wed, 2 Oct 2024 15:04:59 -0500 Subject: [PATCH 4/6] PR feedback --- .../main/kotlin/otel.java-conventions.gradle.kts | 2 +- .../javaagent/extension/AgentListener.java | 5 ++--- .../StructuredConfigPropertiesBridge.java | 15 +++++++++------ 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/conventions/src/main/kotlin/otel.java-conventions.gradle.kts b/conventions/src/main/kotlin/otel.java-conventions.gradle.kts index 23e6ee8138e5..324400151278 100644 --- a/conventions/src/main/kotlin/otel.java-conventions.gradle.kts +++ b/conventions/src/main/kotlin/otel.java-conventions.gradle.kts @@ -77,7 +77,7 @@ tasks.withType().configureEach { ) if (System.getProperty("dev") != "true") { // Fail build on any warning - //compilerArgs.add("-Werror") + compilerArgs.add("-Werror") } } diff --git a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/AgentListener.java b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/AgentListener.java index 82ffb0402791..8b5abbf5222b 100644 --- a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/AgentListener.java +++ b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/AgentListener.java @@ -9,10 +9,8 @@ import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.Ordered; -import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties; import java.lang.instrument.Instrumentation; -import java.util.Collections; import net.bytebuddy.agent.builder.AgentBuilder; /** @@ -45,6 +43,7 @@ static ConfigProperties resolveConfigProperties( return new StructuredConfigPropertiesBridge(structuredConfigProperties); } // Should never happen - return DefaultConfigProperties.create(Collections.emptyMap()); + throw new IllegalStateException( + "AutoConfiguredOpenTelemetrySdk does not have ConfigProperties or StructuredConfigProperties. This is likely a programming error in opentelemetry-java"); } } diff --git a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridge.java b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridge.java index 2bfc9fe3de25..db941ba13ef5 100644 --- a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridge.java +++ b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridge.java @@ -46,18 +46,21 @@ */ final class StructuredConfigPropertiesBridge implements ConfigProperties { + private static final String OTEL_INSTRUMENTATION_PREFIX = "otel.instrumentation."; + private static final StructuredConfigProperties EMPTY = new EmptyStructuredConfigProperties(); - private final StructuredConfigProperties javaInstrumentation; + // The node at .instrumentation.java + private final StructuredConfigProperties instrumentationJavaNode; StructuredConfigPropertiesBridge(StructuredConfigProperties rootStructuredConfigProperties) { StructuredConfigProperties instrumentation = rootStructuredConfigProperties.getStructured("instrumentation"); if (instrumentation != null) { StructuredConfigProperties javaInstrumentation = instrumentation.getStructured("java"); - this.javaInstrumentation = javaInstrumentation != null ? javaInstrumentation : EMPTY; + this.instrumentationJavaNode = javaInstrumentation != null ? javaInstrumentation : EMPTY; } else { - this.javaInstrumentation = EMPTY; + this.instrumentationJavaNode = EMPTY; } } @@ -134,16 +137,16 @@ public Map getMap(String propertyName) { @Nullable private T getPropertyValue( String property, BiFunction extractor) { - if (!property.startsWith("otel.instrumentation.")) { + if (!property.startsWith(OTEL_INSTRUMENTATION_PREFIX)) { return null; } - String suffix = property.substring("otel.instrumentation.".length()); + String suffix = property.substring(OTEL_INSTRUMENTATION_PREFIX.length()); // Split the remainder of the property on ".", and walk to the N-1 entry String[] segments = suffix.split("\\."); if (segments.length == 0) { return null; } - StructuredConfigProperties target = javaInstrumentation; + StructuredConfigProperties target = instrumentationJavaNode; if (segments.length > 1) { for (int i = 0; i < segments.length - 1; i++) { StructuredConfigProperties newTarget = target.getStructured(segments[i]); From 3e2e6f1b5f908417d24d42c1d7aa722e63eb4351 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Wed, 2 Oct 2024 15:37:31 -0500 Subject: [PATCH 5/6] Simplify tree walking --- .../StructuredConfigPropertiesBridge.java | 79 ++----------------- .../StructuredConfigPropertiesBridgeTest.java | 2 +- 2 files changed, 8 insertions(+), 73 deletions(-) diff --git a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridge.java b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridge.java index db941ba13ef5..5c07bcc0a565 100644 --- a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridge.java +++ b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridge.java @@ -5,6 +5,8 @@ package io.opentelemetry.javaagent.extension; +import static io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties.empty; + import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties; import java.time.Duration; @@ -12,7 +14,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.function.BiFunction; import javax.annotation.Nullable; @@ -48,20 +49,14 @@ final class StructuredConfigPropertiesBridge implements ConfigProperties { private static final String OTEL_INSTRUMENTATION_PREFIX = "otel.instrumentation."; - private static final StructuredConfigProperties EMPTY = new EmptyStructuredConfigProperties(); - // The node at .instrumentation.java private final StructuredConfigProperties instrumentationJavaNode; StructuredConfigPropertiesBridge(StructuredConfigProperties rootStructuredConfigProperties) { - StructuredConfigProperties instrumentation = - rootStructuredConfigProperties.getStructured("instrumentation"); - if (instrumentation != null) { - StructuredConfigProperties javaInstrumentation = instrumentation.getStructured("java"); - this.instrumentationJavaNode = javaInstrumentation != null ? javaInstrumentation : EMPTY; - } else { - this.instrumentationJavaNode = EMPTY; - } + instrumentationJavaNode = + rootStructuredConfigProperties + .getStructured("instrumentation", empty()) + .getStructured("java", empty()); } @Nullable @@ -149,70 +144,10 @@ private T getPropertyValue( StructuredConfigProperties target = instrumentationJavaNode; if (segments.length > 1) { for (int i = 0; i < segments.length - 1; i++) { - StructuredConfigProperties newTarget = target.getStructured(segments[i]); - if (newTarget == null) { - target = EMPTY; - break; - } - target = newTarget; + target = target.getStructured(segments[i], empty()); } } String lastPart = segments[segments.length - 1]; return extractor.apply(target, lastPart); } - - private static class EmptyStructuredConfigProperties implements StructuredConfigProperties { - @Nullable - @Override - public String getString(String s) { - return null; - } - - @Nullable - @Override - public Boolean getBoolean(String s) { - return null; - } - - @Nullable - @Override - public Integer getInt(String s) { - return null; - } - - @Nullable - @Override - public Long getLong(String s) { - return null; - } - - @Nullable - @Override - public Double getDouble(String s) { - return null; - } - - @Nullable - @Override - public List getScalarList(String s, Class aClass) { - return null; - } - - @Nullable - @Override - public StructuredConfigProperties getStructured(String s) { - return null; - } - - @Nullable - @Override - public List getStructuredList(String s) { - return null; - } - - @Override - public Set getPropertyKeys() { - return Collections.emptySet(); - } - } } diff --git a/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridgeTest.java b/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridgeTest.java index 17146ed59310..304faac6b9fb 100644 --- a/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridgeTest.java +++ b/javaagent-extension-api/src/test/java/io/opentelemetry/javaagent/extension/StructuredConfigPropertiesBridgeTest.java @@ -54,7 +54,7 @@ class StructuredConfigPropertiesBridgeTest { @Test void getProperties() { - // only properties startig with "otel.instrumentation." are resolved + // only properties starting with "otel.instrumentation." are resolved // asking for properties which don't exist or inaccessible shouldn't result in an error assertThat(bridge.getString("file_format")).isNull(); assertThat(bridge.getString("file_format", "foo")).isEqualTo("foo"); From 63256f76f8a754d231412c100b02e3a7a2f24a9d Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Wed, 2 Oct 2024 15:39:05 -0500 Subject: [PATCH 6/6] remote extra blank lines --- javaagent-tooling/src/test/resources/config.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/javaagent-tooling/src/test/resources/config.yaml b/javaagent-tooling/src/test/resources/config.yaml index 69593f77d889..02642e40fe24 100644 --- a/javaagent-tooling/src/test/resources/config.yaml +++ b/javaagent-tooling/src/test/resources/config.yaml @@ -18,5 +18,3 @@ instrumentation: string_key1: value1 string_key2: value2 bool_key: true - -