From 646ec13c94089d61f2cc8d584bff09afff35af63 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 20 Jan 2025 16:42:33 +0100 Subject: [PATCH 01/35] spring boot runtime metrics for java 17+ --- .../java17/Java17RuntimeMetricsInstaller.java | 32 ++----------- .../java17/RuntimeMetricsBuilder.java | 30 ++++++++++++ .../build.gradle.kts | 1 + ...Java17RuntimeMetricsAutoConfiguration.java | 48 +++++++++++++++++++ .../properties/ConfigPropertiesBridge.java | 8 +++- .../main/resources/META-INF/spring.factories | 3 +- ...ot.autoconfigure.AutoConfiguration.imports | 1 + .../AbstractOtelSpringStarterSmokeTest.java | 5 ++ .../OtelSpringStarterSmokeTestController.java | 2 - 9 files changed, 97 insertions(+), 33 deletions(-) create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsAutoConfiguration.java 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 ec4fab1528af..32fbd70c656f 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 @@ -9,10 +9,9 @@ import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics; -import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetricsBuilder; +import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; import io.opentelemetry.javaagent.extension.AgentListener; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; -import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; /** An {@link AgentListener} that enables runtime metrics during agent startup. */ @AutoService(AgentListener.class) @@ -20,34 +19,9 @@ public class Java17RuntimeMetricsInstaller implements AgentListener { @Override public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { - ConfigProperties config = AgentListener.resolveConfigProperties(autoConfiguredSdk); - OpenTelemetry openTelemetry = GlobalOpenTelemetry.get(); - RuntimeMetricsBuilder builder = null; - /* - By default don't use any JFR metrics. May change this once semantic conventions are updated. - If enabled, default to only the metrics not already covered by runtime-telemetry-java8 - */ - boolean defaultEnabled = config.getBoolean("otel.instrumentation.common.default-enabled", true); - if (config.getBoolean("otel.instrumentation.runtime-telemetry-java17.enable-all", false)) { - builder = RuntimeMetrics.builder(openTelemetry).enableAllFeatures(); - } else if (config.getBoolean("otel.instrumentation.runtime-telemetry-java17.enabled", false)) { - builder = RuntimeMetrics.builder(openTelemetry); - } else if (config.getBoolean( - "otel.instrumentation.runtime-telemetry.enabled", defaultEnabled)) { - // This only uses metrics gathered by JMX - builder = RuntimeMetrics.builder(openTelemetry).disableAllFeatures(); - } - - if (builder != null) { - if (config.getBoolean( - "otel.instrumentation.runtime-telemetry.emit-experimental-telemetry", false)) { - builder.enableExperimentalJmxTelemetry(); - } - RuntimeMetrics finalJfrTelemetry = builder.build(); - Thread cleanupTelemetry = new Thread(() -> finalJfrTelemetry.close()); - Runtime.getRuntime().addShutdownHook(cleanupTelemetry); - } + RuntimeMetrics.builder(openTelemetry) + .startFromInstrumentationConfig(AgentInstrumentationConfig.get()); } } diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java index e73c535e5803..c1c011a06ccf 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java @@ -7,6 +7,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.instrumentation.runtimemetrics.java8.Classes; import io.opentelemetry.instrumentation.runtimemetrics.java8.Cpu; import io.opentelemetry.instrumentation.runtimemetrics.java8.GarbageCollector; @@ -90,6 +91,35 @@ public RuntimeMetricsBuilder enableExperimentalJmxTelemetry() { return this; } + public void startFromInstrumentationConfig(InstrumentationConfig config) { + /* + By default, don't use any JFR metrics. May change this once semantic conventions are updated. + If enabled, default to only the metrics not already covered by runtime-telemetry-java8 + */ + boolean defaultEnabled = config.getBoolean("otel.instrumentation.common.default-enabled", true); + if (config.getBoolean("otel.instrumentation.runtime-telemetry-java17.enable-all", false)) { + this.enableAllFeatures(); + } else if (config.getBoolean("otel.instrumentation.runtime-telemetry-java17.enabled", false)) { + // default configuration + } else if (config.getBoolean( + "otel.instrumentation.runtime-telemetry.enabled", defaultEnabled)) { + // This only uses metrics gathered by JMX + this.disableAllFeatures(); + } else { + // nothing is enabled + return; + } + + if (config.getBoolean( + "otel.instrumentation.runtime-telemetry.emit-experimental-telemetry", false)) { + this.enableExperimentalJmxTelemetry(); + } + + RuntimeMetrics finalJfrTelemetry = this.build(); + Thread cleanupTelemetry = new Thread(finalJfrTelemetry::close); + Runtime.getRuntime().addShutdownHook(cleanupTelemetry); + } + /** Build and start an {@link RuntimeMetrics} with the config from this builder. */ public RuntimeMetrics build() { List observables = buildObservables(); diff --git a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts index d701141e3f65..6cc1f6cbf6a9 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts +++ b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts @@ -53,6 +53,7 @@ dependencies { implementation(project(":instrumentation:logback:logback-mdc-1.0:library")) compileOnly("ch.qos.logback:logback-classic:1.0.0") implementation(project(":instrumentation:jdbc:library")) + implementation(project(":instrumentation:runtime-telemetry:runtime-telemetry-java17:library")) library("org.springframework.kafka:spring-kafka:2.9.0") library("org.springframework.boot:spring-boot-starter-actuator:$springBootVersion") diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsAutoConfiguration.java new file mode 100644 index 000000000000..3c33b8d3e068 --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsAutoConfiguration.java @@ -0,0 +1,48 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics; +import io.opentelemetry.instrumentation.spring.autoconfigure.internal.ConditionalOnEnabledInstrumentation; +import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.ConfigPropertiesBridge; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.EventListener; + +/** + * Configures runtime metrics collection. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +@ConditionalOnEnabledInstrumentation(module = "runtime-telemetry-java17") +@Configuration +public class Java17RuntimeMetricsAutoConfiguration { + + private static final Logger logger = + LoggerFactory.getLogger(Java17RuntimeMetricsAutoConfiguration.class); + + @EventListener + public void handleApplicationReadyEvent(ApplicationReadyEvent event) { + if (Double.parseDouble(System.getProperty("java.specification.version")) < 17) { + logger.debug( + "Java 17 runtime metrics instrumentation enabled but running on Java version < 17"); + return; + } + logger.debug( + "Java 17 runtime metrics instrumentation enabled and running on Java version >= 17"); + ConfigurableApplicationContext applicationContext = event.getApplicationContext(); + OpenTelemetry openTelemetry = applicationContext.getBean(OpenTelemetry.class); + ConfigProperties configProperties = applicationContext.getBean(ConfigProperties.class); + RuntimeMetrics.builder(openTelemetry) + .startFromInstrumentationConfig(new ConfigPropertiesBridge(configProperties)); + } +} 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 49d50f94cc5c..8305aef6a4f0 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 @@ -13,7 +13,13 @@ import java.util.Map; import javax.annotation.Nullable; -final class ConfigPropertiesBridge implements InstrumentationConfig { +/** + * Support for {@link ConfigProperties} in {@link InstrumentationConfig}. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class ConfigPropertiesBridge implements InstrumentationConfig { private final ConfigProperties configProperties; diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 049b3b068f1d..a9c9e379f88c 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -10,7 +10,8 @@ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.r io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.web.SpringWebInstrumentationAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.webflux.SpringWebfluxInstrumentationAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.webmvc.SpringWebMvc5InstrumentationAutoConfiguration,\ -io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.scheduling.SpringSchedulingInstrumentationAutoConfiguration +io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.scheduling.SpringSchedulingInstrumentationAutoConfiguration,\ +io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java17RuntimeMetricsAutoConfiguration org.springframework.context.ApplicationListener=\ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.logging.LogbackAppenderApplicationListener diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 73b6f4a6f840..c7a9ffefac86 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -11,3 +11,4 @@ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.w io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.web.RestClientInstrumentationAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.webmvc.SpringWebMvc6InstrumentationAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.scheduling.SpringSchedulingInstrumentationAutoConfiguration +io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java17RuntimeMetricsAutoConfiguration diff --git a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java index 0709434bc883..9056a3fad25e 100644 --- a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java @@ -209,6 +209,11 @@ void shouldSendTelemetry() { OtelSpringStarterSmokeTestController.METER_SCOPE_NAME, OtelSpringStarterSmokeTestController.TEST_HISTOGRAM, AbstractIterableAssert::isNotEmpty); + // runtime metrics + testing.waitAndAssertMetrics( + "io.opentelemetry.runtime-telemetry-java8", + "jvm.thread.count", + AbstractIterableAssert::isNotEmpty); // Log List exportedLogRecords = testing.getExportedLogRecords(); diff --git a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTestController.java b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTestController.java index 7d02c29d5fc1..c4902b2d65d5 100644 --- a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTestController.java +++ b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTestController.java @@ -15,8 +15,6 @@ public class OtelSpringStarterSmokeTestController { public static final String PING = "/ping"; - public static final String REST_CLIENT = "/rest-client"; - public static final String REST_TEMPLATE = "/rest-template"; public static final String TEST_HISTOGRAM = "histogram-test-otel-spring-starter"; public static final String METER_SCOPE_NAME = "scope"; private final LongHistogram histogram; From d94f2d69c3b9ae16eada1eae37aee7661dd97911 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 21 Jan 2025 14:19:23 +0100 Subject: [PATCH 02/35] spring boot runtime metrics for java 8 --- .../java17/Java17RuntimeMetricsInstaller.java | 5 +- .../java17/RuntimeMetricsBuilder.java | 41 ++----------- .../java8/Java8RuntimeMetricsInstaller.java | 42 ++----------- .../runtimemetrics/java8/RuntimeMetrics.java | 60 ++++++++++++++++++ .../java8/RuntimeMetricsBuilder.java | 61 +++++++++++++++++++ .../internal/JmxRuntimeMetricsFactory.java | 49 +++++++++++++++ .../build.gradle.kts | 1 + ...a => RuntimeMetricsAutoConfiguration.java} | 29 ++++----- .../main/resources/META-INF/spring.factories | 2 +- ...ot.autoconfigure.AutoConfiguration.imports | 2 +- 10 files changed, 198 insertions(+), 94 deletions(-) create mode 100644 instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetrics.java create mode 100644 instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java create mode 100644 instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/internal/JmxRuntimeMetricsFactory.java rename instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/{Java17RuntimeMetricsAutoConfiguration.java => RuntimeMetricsAutoConfiguration.java} (66%) 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 32fbd70c656f..10a535f8d393 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 @@ -7,7 +7,6 @@ import com.google.auto.service.AutoService; import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics; import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; import io.opentelemetry.javaagent.extension.AgentListener; @@ -19,9 +18,7 @@ public class Java17RuntimeMetricsInstaller implements AgentListener { @Override public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { - OpenTelemetry openTelemetry = GlobalOpenTelemetry.get(); - - RuntimeMetrics.builder(openTelemetry) + RuntimeMetrics.builder(GlobalOpenTelemetry.get()) .startFromInstrumentationConfig(AgentInstrumentationConfig.get()); } } diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java index c1c011a06ccf..025623659454 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java @@ -8,17 +8,8 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; -import io.opentelemetry.instrumentation.runtimemetrics.java8.Classes; -import io.opentelemetry.instrumentation.runtimemetrics.java8.Cpu; -import io.opentelemetry.instrumentation.runtimemetrics.java8.GarbageCollector; -import io.opentelemetry.instrumentation.runtimemetrics.java8.MemoryPools; -import io.opentelemetry.instrumentation.runtimemetrics.java8.Threads; -import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.ExperimentalBufferPools; -import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.ExperimentalCpu; -import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.ExperimentalMemoryPools; -import java.util.ArrayList; +import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.JmxRuntimeMetricsFactory; import java.util.Arrays; -import java.util.Collections; import java.util.EnumMap; import java.util.List; import javax.annotation.Nullable; @@ -84,7 +75,7 @@ public RuntimeMetricsBuilder disableAllJmx() { return this; } - /** Disable telemetry collection associated with the {@link JfrFeature}. */ + /** Enable experimental JMX telemetry collection. */ @CanIgnoreReturnValue public RuntimeMetricsBuilder enableExperimentalJmxTelemetry() { enableExperimentalJmxTelemetry = true; @@ -122,35 +113,13 @@ public void startFromInstrumentationConfig(InstrumentationConfig config) { /** Build and start an {@link RuntimeMetrics} with the config from this builder. */ public RuntimeMetrics build() { - List observables = buildObservables(); + List observables = + JmxRuntimeMetricsFactory.buildObservables( + openTelemetry, disableJmx, enableExperimentalJmxTelemetry); RuntimeMetrics.JfrRuntimeMetrics jfrRuntimeMetrics = buildJfrMetrics(); return new RuntimeMetrics(openTelemetry, observables, jfrRuntimeMetrics); } - @SuppressWarnings("CatchingUnchecked") - private List buildObservables() { - if (disableJmx) { - return Collections.emptyList(); - } - try { - // Set up metrics gathered by JMX - List observables = new ArrayList<>(); - observables.addAll(Classes.registerObservers(openTelemetry)); - observables.addAll(Cpu.registerObservers(openTelemetry)); - observables.addAll(GarbageCollector.registerObservers(openTelemetry)); - observables.addAll(MemoryPools.registerObservers(openTelemetry)); - observables.addAll(Threads.registerObservers(openTelemetry)); - if (enableExperimentalJmxTelemetry) { - observables.addAll(ExperimentalBufferPools.registerObservers(openTelemetry)); - observables.addAll(ExperimentalCpu.registerObservers(openTelemetry)); - observables.addAll(ExperimentalMemoryPools.registerObservers(openTelemetry)); - } - return observables; - } catch (Exception e) { - throw new IllegalStateException("Error building RuntimeMetrics", e); - } - } - @Nullable private RuntimeMetrics.JfrRuntimeMetrics buildJfrMetrics() { if (enabledFeatureMap.values().stream().noneMatch(isEnabled -> isEnabled)) { 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 b93bfa57e835..57a569a976dc 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 @@ -7,21 +7,10 @@ import com.google.auto.service.AutoService; import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.instrumentation.runtimemetrics.java8.Classes; -import io.opentelemetry.instrumentation.runtimemetrics.java8.Cpu; -import io.opentelemetry.instrumentation.runtimemetrics.java8.GarbageCollector; -import io.opentelemetry.instrumentation.runtimemetrics.java8.MemoryPools; -import io.opentelemetry.instrumentation.runtimemetrics.java8.Threads; -import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.ExperimentalBufferPools; -import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.ExperimentalCpu; -import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.ExperimentalMemoryPools; -import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.JmxRuntimeMetricsUtil; +import io.opentelemetry.instrumentation.runtimemetrics.java8.RuntimeMetrics; +import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; import io.opentelemetry.javaagent.extension.AgentListener; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; -import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; -import java.util.ArrayList; -import java.util.List; /** An {@link AgentListener} that enables runtime metrics during agent startup. */ @AutoService(AgentListener.class) @@ -29,30 +18,7 @@ public class Java8RuntimeMetricsInstaller implements AgentListener { @Override public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { - ConfigProperties config = AgentListener.resolveConfigProperties(autoConfiguredSdk); - - boolean defaultEnabled = config.getBoolean("otel.instrumentation.common.default-enabled", true); - if (!config.getBoolean("otel.instrumentation.runtime-telemetry.enabled", defaultEnabled) - || Double.parseDouble(System.getProperty("java.specification.version")) >= 17) { - return; - } - - OpenTelemetry openTelemetry = GlobalOpenTelemetry.get(); - List observables = new ArrayList<>(); - observables.addAll(Classes.registerObservers(openTelemetry)); - observables.addAll(Cpu.registerObservers(openTelemetry)); - observables.addAll(GarbageCollector.registerObservers(openTelemetry)); - observables.addAll(MemoryPools.registerObservers(openTelemetry)); - observables.addAll(Threads.registerObservers(openTelemetry)); - - if (config.getBoolean( - "otel.instrumentation.runtime-telemetry.emit-experimental-telemetry", false)) { - observables.addAll(ExperimentalBufferPools.registerObservers(openTelemetry)); - observables.addAll(ExperimentalCpu.registerObservers(openTelemetry)); - observables.addAll(ExperimentalMemoryPools.registerObservers(openTelemetry)); - } - - Thread cleanupTelemetry = new Thread(() -> JmxRuntimeMetricsUtil.closeObservers(observables)); - Runtime.getRuntime().addShutdownHook(cleanupTelemetry); + RuntimeMetrics.builder(GlobalOpenTelemetry.get()) + .startFromInstrumentationConfig(AgentInstrumentationConfig.get()); } } diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetrics.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetrics.java new file mode 100644 index 000000000000..86afabd17301 --- /dev/null +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetrics.java @@ -0,0 +1,60 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.java8; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.JmxRuntimeMetricsUtil; +import java.io.Closeable; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** The entry point class for runtime metrics support using JFR and JMX. */ +public final class RuntimeMetrics implements Closeable { + + private static final Logger logger = Logger.getLogger(RuntimeMetrics.class.getName()); + + private final AtomicBoolean isClosed = new AtomicBoolean(); + private final List observables; + + RuntimeMetrics(List observables) { + this.observables = Collections.unmodifiableList(observables); + } + + /** + * Create and start {@link RuntimeMetrics}. + * + *

Listens for select JFR events, extracts data, and records to various metrics. Recording will + * continue until {@link #close()} is called. + * + * @param openTelemetry the {@link OpenTelemetry} instance used to record telemetry + */ + public static RuntimeMetrics create(OpenTelemetry openTelemetry) { + return new RuntimeMetricsBuilder(openTelemetry).build(); + } + + /** + * Create a builder for configuring {@link RuntimeMetrics}. + * + * @param openTelemetry the {@link OpenTelemetry} instance used to record telemetry + */ + public static RuntimeMetricsBuilder builder(OpenTelemetry openTelemetry) { + return new RuntimeMetricsBuilder(openTelemetry); + } + + /** Stop recording JFR events. */ + @Override + public void close() { + if (!isClosed.compareAndSet(false, true)) { + logger.log(Level.WARNING, "RuntimeMetrics is already closed"); + return; + } + + JmxRuntimeMetricsUtil.closeObservers(observables); + } +} diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java new file mode 100644 index 000000000000..d82020c23fd7 --- /dev/null +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java @@ -0,0 +1,61 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.java8; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; +import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.JmxRuntimeMetricsFactory; +import java.util.List; + +/** Builder for {@link RuntimeMetrics}. */ +public final class RuntimeMetricsBuilder { + + private final OpenTelemetry openTelemetry; + + private boolean disableJmx = false; + private boolean enableExperimentalJmxTelemetry = false; + + RuntimeMetricsBuilder(OpenTelemetry openTelemetry) { + this.openTelemetry = openTelemetry; + } + + /** Enable all JMX telemetry collection. */ + @CanIgnoreReturnValue + public RuntimeMetricsBuilder enableExperimentalJmxTelemetry() { + enableExperimentalJmxTelemetry = true; + return this; + } + + /** Build and start an {@link RuntimeMetrics} with the config from this builder. */ + public RuntimeMetrics build() { + List observables = + JmxRuntimeMetricsFactory.buildObservables( + openTelemetry, disableJmx, enableExperimentalJmxTelemetry); + return new RuntimeMetrics(observables); + } + + public void startFromInstrumentationConfig(InstrumentationConfig config) { + /* + By default, don't use any JFR metrics. May change this once semantic conventions are updated. + If enabled, default to only the metrics not already covered by runtime-telemetry-java8 + */ + boolean defaultEnabled = config.getBoolean("otel.instrumentation.common.default-enabled", true); + if (!config.getBoolean("otel.instrumentation.runtime-telemetry.enabled", defaultEnabled)) { + // nothing is enabled + return; + } + + if (config.getBoolean( + "otel.instrumentation.runtime-telemetry.emit-experimental-telemetry", false)) { + this.enableExperimentalJmxTelemetry(); + } + + RuntimeMetrics finalJfrTelemetry = this.build(); + Thread cleanupTelemetry = new Thread(finalJfrTelemetry::close); + Runtime.getRuntime().addShutdownHook(cleanupTelemetry); + } +} diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/internal/JmxRuntimeMetricsFactory.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/internal/JmxRuntimeMetricsFactory.java new file mode 100644 index 000000000000..16fdf3e000fd --- /dev/null +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/internal/JmxRuntimeMetricsFactory.java @@ -0,0 +1,49 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.java8.internal; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.runtimemetrics.java8.Classes; +import io.opentelemetry.instrumentation.runtimemetrics.java8.Cpu; +import io.opentelemetry.instrumentation.runtimemetrics.java8.GarbageCollector; +import io.opentelemetry.instrumentation.runtimemetrics.java8.MemoryPools; +import io.opentelemetry.instrumentation.runtimemetrics.java8.Threads; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public class JmxRuntimeMetricsFactory { + @SuppressWarnings("CatchingUnchecked") + public static List buildObservables( + OpenTelemetry openTelemetry, boolean disableJmx, boolean enableExperimentalJmxTelemetry) { + if (disableJmx) { + return Collections.emptyList(); + } + try { + // Set up metrics gathered by JMX + List observables = new ArrayList<>(); + observables.addAll(Classes.registerObservers(openTelemetry)); + observables.addAll(Cpu.registerObservers(openTelemetry)); + observables.addAll(GarbageCollector.registerObservers(openTelemetry)); + observables.addAll(MemoryPools.registerObservers(openTelemetry)); + observables.addAll(Threads.registerObservers(openTelemetry)); + if (enableExperimentalJmxTelemetry) { + observables.addAll(ExperimentalBufferPools.registerObservers(openTelemetry)); + observables.addAll(ExperimentalCpu.registerObservers(openTelemetry)); + observables.addAll(ExperimentalMemoryPools.registerObservers(openTelemetry)); + } + return observables; + } catch (Exception e) { + throw new IllegalStateException("Error building RuntimeMetrics", e); + } + } + + private JmxRuntimeMetricsFactory() {} +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts index 6cc1f6cbf6a9..99fbcbd98b8e 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts +++ b/instrumentation/spring/spring-boot-autoconfigure/build.gradle.kts @@ -53,6 +53,7 @@ dependencies { implementation(project(":instrumentation:logback:logback-mdc-1.0:library")) compileOnly("ch.qos.logback:logback-classic:1.0.0") implementation(project(":instrumentation:jdbc:library")) + implementation(project(":instrumentation:runtime-telemetry:runtime-telemetry-java8:library")) implementation(project(":instrumentation:runtime-telemetry:runtime-telemetry-java17:library")) library("org.springframework.kafka:spring-kafka:2.9.0") diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java similarity index 66% rename from instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsAutoConfiguration.java rename to instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java index 3c33b8d3e068..c04a0fe704a5 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java @@ -6,7 +6,6 @@ package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics; import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics; import io.opentelemetry.instrumentation.spring.autoconfigure.internal.ConditionalOnEnabledInstrumentation; import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.ConfigPropertiesBridge; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; @@ -23,26 +22,28 @@ *

This class is internal and is hence not for public use. Its APIs are unstable and can change * at any time. */ -@ConditionalOnEnabledInstrumentation(module = "runtime-telemetry-java17") +@ConditionalOnEnabledInstrumentation(module = "runtime-telemetry") @Configuration -public class Java17RuntimeMetricsAutoConfiguration { +public class RuntimeMetricsAutoConfiguration { private static final Logger logger = - LoggerFactory.getLogger(Java17RuntimeMetricsAutoConfiguration.class); + LoggerFactory.getLogger(RuntimeMetricsAutoConfiguration.class); @EventListener public void handleApplicationReadyEvent(ApplicationReadyEvent event) { - if (Double.parseDouble(System.getProperty("java.specification.version")) < 17) { - logger.debug( - "Java 17 runtime metrics instrumentation enabled but running on Java version < 17"); - return; - } - logger.debug( - "Java 17 runtime metrics instrumentation enabled and running on Java version >= 17"); ConfigurableApplicationContext applicationContext = event.getApplicationContext(); OpenTelemetry openTelemetry = applicationContext.getBean(OpenTelemetry.class); - ConfigProperties configProperties = applicationContext.getBean(ConfigProperties.class); - RuntimeMetrics.builder(openTelemetry) - .startFromInstrumentationConfig(new ConfigPropertiesBridge(configProperties)); + ConfigPropertiesBridge config = + new ConfigPropertiesBridge(applicationContext.getBean(ConfigProperties.class)); + + if (Double.parseDouble(System.getProperty("java.specification.version")) >= 17) { + logger.debug("Use runtime metrics instrumentation for Java 17+"); + io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics.builder(openTelemetry) + .startFromInstrumentationConfig(config); + } else { + logger.debug("Use runtime metrics instrumentation for Java 8"); + io.opentelemetry.instrumentation.runtimemetrics.java8.RuntimeMetrics.builder(openTelemetry) + .startFromInstrumentationConfig(config); + } } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index a9c9e379f88c..bf7f5dc46fe2 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -11,7 +11,7 @@ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.w io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.webflux.SpringWebfluxInstrumentationAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.webmvc.SpringWebMvc5InstrumentationAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.scheduling.SpringSchedulingInstrumentationAutoConfiguration,\ -io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java17RuntimeMetricsAutoConfiguration +io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.RuntimeMetricsAutoConfiguration org.springframework.context.ApplicationListener=\ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.logging.LogbackAppenderApplicationListener diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index c7a9ffefac86..fda05853c855 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -11,4 +11,4 @@ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.w io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.web.RestClientInstrumentationAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.webmvc.SpringWebMvc6InstrumentationAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.scheduling.SpringSchedulingInstrumentationAutoConfiguration -io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java17RuntimeMetricsAutoConfiguration +io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.RuntimeMetricsAutoConfiguration From 6b9c0261d798ebd2f4de61a3576dd3a63f7d1e9d Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 21 Jan 2025 15:06:11 +0100 Subject: [PATCH 03/35] spring boot runtime metrics for java 8 --- .../runtimemetrics/java8/RuntimeMetricsBuilder.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java index d82020c23fd7..dbe7435c1166 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java @@ -16,7 +16,6 @@ public final class RuntimeMetricsBuilder { private final OpenTelemetry openTelemetry; - private boolean disableJmx = false; private boolean enableExperimentalJmxTelemetry = false; RuntimeMetricsBuilder(OpenTelemetry openTelemetry) { @@ -34,7 +33,7 @@ public RuntimeMetricsBuilder enableExperimentalJmxTelemetry() { public RuntimeMetrics build() { List observables = JmxRuntimeMetricsFactory.buildObservables( - openTelemetry, disableJmx, enableExperimentalJmxTelemetry); + openTelemetry, false, enableExperimentalJmxTelemetry); return new RuntimeMetrics(observables); } From 7792de6b6057e38e2c3ff5e2681e9a5bee011d41 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 22 Jan 2025 11:31:29 +0100 Subject: [PATCH 04/35] fix native --- .../META-INF/native-image/reflect-config.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/resources/META-INF/native-image/reflect-config.json diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/resources/META-INF/native-image/reflect-config.json b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/resources/META-INF/native-image/reflect-config.json new file mode 100644 index 000000000000..1e250d63300c --- /dev/null +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/resources/META-INF/native-image/reflect-config.json @@ -0,0 +1,10 @@ +[ + { + "name": "com.sun.management.OperatingSystemMXBean", + "allPublicMethods": true + }, + { + "name": "com.ibm.lang.management.OperatingSystemMXBean", + "allPublicMethods": true + } +] From b262de9e8c8e5dcd28bad70581edf122baf73928 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 22 Jan 2025 13:26:45 +0100 Subject: [PATCH 05/35] use spring shutdown hook --- .../java17/RuntimeMetricsBuilder.java | 23 +++++++++++++++---- .../java8/RuntimeMetricsBuilder.java | 20 ++++++++++++---- .../internal/JmxRuntimeMetricsFactory.java | 6 +---- .../RuntimeMetricsAutoConfiguration.java | 12 ++++++++++ 4 files changed, 46 insertions(+), 15 deletions(-) diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java index 025623659454..7411dc747886 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java @@ -12,6 +12,7 @@ import java.util.Arrays; import java.util.EnumMap; import java.util.List; +import java.util.function.Consumer; import javax.annotation.Nullable; /** Builder for {@link RuntimeMetrics}. */ @@ -23,6 +24,10 @@ public final class RuntimeMetricsBuilder { private boolean disableJmx = false; private boolean enableExperimentalJmxTelemetry = false; + private Consumer shutdownHook = + runnable -> { + Runtime.getRuntime().addShutdownHook(new Thread(runnable)); + }; RuntimeMetricsBuilder(OpenTelemetry openTelemetry) { this.openTelemetry = openTelemetry; @@ -82,6 +87,13 @@ public RuntimeMetricsBuilder enableExperimentalJmxTelemetry() { return this; } + /** Set a custom shutdown hook for the {@link RuntimeMetrics}. */ + @CanIgnoreReturnValue + public RuntimeMetricsBuilder setShutdownHook(Consumer shutdownHook) { + this.shutdownHook = shutdownHook; + return this; + } + public void startFromInstrumentationConfig(InstrumentationConfig config) { /* By default, don't use any JFR metrics. May change this once semantic conventions are updated. @@ -106,16 +118,17 @@ public void startFromInstrumentationConfig(InstrumentationConfig config) { this.enableExperimentalJmxTelemetry(); } - RuntimeMetrics finalJfrTelemetry = this.build(); - Thread cleanupTelemetry = new Thread(finalJfrTelemetry::close); - Runtime.getRuntime().addShutdownHook(cleanupTelemetry); + RuntimeMetrics runtimeMetrics = this.build(); + shutdownHook.accept(runtimeMetrics::close); } /** Build and start an {@link RuntimeMetrics} with the config from this builder. */ public RuntimeMetrics build() { List observables = - JmxRuntimeMetricsFactory.buildObservables( - openTelemetry, disableJmx, enableExperimentalJmxTelemetry); + disableJmx + ? List.of() + : JmxRuntimeMetricsFactory.buildObservables( + openTelemetry, enableExperimentalJmxTelemetry); RuntimeMetrics.JfrRuntimeMetrics jfrRuntimeMetrics = buildJfrMetrics(); return new RuntimeMetrics(openTelemetry, observables, jfrRuntimeMetrics); } diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java index dbe7435c1166..e6cceaa095d9 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java @@ -10,6 +10,7 @@ import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.JmxRuntimeMetricsFactory; import java.util.List; +import java.util.function.Consumer; /** Builder for {@link RuntimeMetrics}. */ public final class RuntimeMetricsBuilder { @@ -17,6 +18,10 @@ public final class RuntimeMetricsBuilder { private final OpenTelemetry openTelemetry; private boolean enableExperimentalJmxTelemetry = false; + private Consumer shutdownHook = + runnable -> { + Runtime.getRuntime().addShutdownHook(new Thread(runnable)); + }; RuntimeMetricsBuilder(OpenTelemetry openTelemetry) { this.openTelemetry = openTelemetry; @@ -32,11 +37,17 @@ public RuntimeMetricsBuilder enableExperimentalJmxTelemetry() { /** Build and start an {@link RuntimeMetrics} with the config from this builder. */ public RuntimeMetrics build() { List observables = - JmxRuntimeMetricsFactory.buildObservables( - openTelemetry, false, enableExperimentalJmxTelemetry); + JmxRuntimeMetricsFactory.buildObservables(openTelemetry, enableExperimentalJmxTelemetry); return new RuntimeMetrics(observables); } + /** Set a custom shutdown hook for the {@link RuntimeMetrics}. */ + @CanIgnoreReturnValue + public RuntimeMetricsBuilder setShutdownHook(Consumer shutdownHook) { + this.shutdownHook = shutdownHook; + return this; + } + public void startFromInstrumentationConfig(InstrumentationConfig config) { /* By default, don't use any JFR metrics. May change this once semantic conventions are updated. @@ -53,8 +64,7 @@ public void startFromInstrumentationConfig(InstrumentationConfig config) { this.enableExperimentalJmxTelemetry(); } - RuntimeMetrics finalJfrTelemetry = this.build(); - Thread cleanupTelemetry = new Thread(finalJfrTelemetry::close); - Runtime.getRuntime().addShutdownHook(cleanupTelemetry); + RuntimeMetrics runtimeMetrics = this.build(); + shutdownHook.accept(runtimeMetrics::close); } } diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/internal/JmxRuntimeMetricsFactory.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/internal/JmxRuntimeMetricsFactory.java index 16fdf3e000fd..405fbb48c80e 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/internal/JmxRuntimeMetricsFactory.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/internal/JmxRuntimeMetricsFactory.java @@ -12,7 +12,6 @@ import io.opentelemetry.instrumentation.runtimemetrics.java8.MemoryPools; import io.opentelemetry.instrumentation.runtimemetrics.java8.Threads; import java.util.ArrayList; -import java.util.Collections; import java.util.List; /** @@ -22,10 +21,7 @@ public class JmxRuntimeMetricsFactory { @SuppressWarnings("CatchingUnchecked") public static List buildObservables( - OpenTelemetry openTelemetry, boolean disableJmx, boolean enableExperimentalJmxTelemetry) { - if (disableJmx) { - return Collections.emptyList(); - } + OpenTelemetry openTelemetry, boolean enableExperimentalJmxTelemetry) { try { // Set up metrics gathered by JMX List observables = new ArrayList<>(); diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java index c04a0fe704a5..7c3a312131e8 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java @@ -9,6 +9,7 @@ import io.opentelemetry.instrumentation.spring.autoconfigure.internal.ConditionalOnEnabledInstrumentation; import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.ConfigPropertiesBridge; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import javax.annotation.PreDestroy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.context.event.ApplicationReadyEvent; @@ -29,6 +30,15 @@ public class RuntimeMetricsAutoConfiguration { private static final Logger logger = LoggerFactory.getLogger(RuntimeMetricsAutoConfiguration.class); + private Runnable shutdownHook; + + @PreDestroy + public void stopMetrics() { + if (shutdownHook != null) { + shutdownHook.run(); + } + } + @EventListener public void handleApplicationReadyEvent(ApplicationReadyEvent event) { ConfigurableApplicationContext applicationContext = event.getApplicationContext(); @@ -39,10 +49,12 @@ public void handleApplicationReadyEvent(ApplicationReadyEvent event) { if (Double.parseDouble(System.getProperty("java.specification.version")) >= 17) { logger.debug("Use runtime metrics instrumentation for Java 17+"); io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics.builder(openTelemetry) + .setShutdownHook(runnable -> shutdownHook = runnable) .startFromInstrumentationConfig(config); } else { logger.debug("Use runtime metrics instrumentation for Java 8"); io.opentelemetry.instrumentation.runtimemetrics.java8.RuntimeMetrics.builder(openTelemetry) + .setShutdownHook(runnable -> shutdownHook = runnable) .startFromInstrumentationConfig(config); } } From e10e8c13ad562d8a35db54d1fd0729eb4b48e137 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 28 Jan 2025 09:24:46 +0100 Subject: [PATCH 06/35] disable threads --- .../instrumentation/runtimemetrics/java8/Threads.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/Threads.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/Threads.java index d3af5bf00ea9..0705fbdbedb3 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/Threads.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/Threads.java @@ -57,7 +57,13 @@ public final class Threads { /** Register observers for java runtime class metrics. */ public static List registerObservers(OpenTelemetry openTelemetry) { - return INSTANCE.registerObservers(openTelemetry, !isJava9OrNewer()); + return INSTANCE.registerObservers(openTelemetry, useThreads()); + } + + private static boolean useThreads() { + // GraalVM native image does not support ThreadMXBean yet + // see https://github.com/oracle/graal/issues/6101 + return !isJava9OrNewer() || System.getProperty("org.graalvm.nativeimage.imagecode") != null; } private List registerObservers(OpenTelemetry openTelemetry, boolean useThread) { From 17dd2518f34851191a332813acc9f6f8e6da3815 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 28 Jan 2025 09:42:04 +0100 Subject: [PATCH 07/35] disable threads --- .../runtimemetrics/java8/Threads.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/Threads.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/Threads.java index 0705fbdbedb3..2b720ab813bd 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/Threads.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/Threads.java @@ -60,12 +60,6 @@ public static List registerObservers(OpenTelemetry openTelemetry) return INSTANCE.registerObservers(openTelemetry, useThreads()); } - private static boolean useThreads() { - // GraalVM native image does not support ThreadMXBean yet - // see https://github.com/oracle/graal/issues/6101 - return !isJava9OrNewer() || System.getProperty("org.graalvm.nativeimage.imagecode") != null; - } - private List registerObservers(OpenTelemetry openTelemetry, boolean useThread) { if (useThread) { return registerObservers(openTelemetry, Threads::getThreads); @@ -122,6 +116,12 @@ private static boolean isJava9OrNewer() { return THREAD_INFO_IS_DAEMON != null; } + private static boolean useThreads() { + // GraalVM native image does not support ThreadMXBean yet + // see https://github.com/oracle/graal/issues/6101 + return !isJava9OrNewer() || System.getProperty("org.graalvm.nativeimage.imagecode") != null; + } + private static Consumer java8Callback(ThreadMXBean threadBean) { return measurement -> { int daemonThreadCount = threadBean.getDaemonThreadCount(); From 697c197c192a5d2633532d1ccfc56816926ace5c Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 28 Jan 2025 18:56:21 +0100 Subject: [PATCH 08/35] test more metric types --- .../smoketest/OtelSpringStarterSmokeTest.java | 16 ++++++++++++++-- .../AbstractOtelSpringStarterSmokeTest.java | 11 +++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/smoke-tests-otel-starter/spring-boot-3/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-boot-3/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java index 315e8155413b..eee483ccb319 100644 --- a/smoke-tests-otel-starter/spring-boot-3/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-boot-3/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java @@ -5,6 +5,7 @@ package io.opentelemetry.spring.smoketest; +import org.assertj.core.api.AbstractIterableAssert; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest( @@ -16,6 +17,17 @@ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { // The headers are simply set here to make sure that headers can be parsed - "otel.exporter.otlp.headers.c=3" + "otel.exporter.otlp.headers.c=3", + "otel.instrumentation.runtime-telemetry-java17.enabled=true", }) -class OtelSpringStarterSmokeTest extends AbstractOtelSpringStarterSmokeTest {} +class OtelSpringStarterSmokeTest extends AbstractOtelSpringStarterSmokeTest { + + @Override + protected void assertAdditionalMetrics() { + // JFR based metrics + testing.waitAndAssertMetrics( + "io.opentelemetry.runtime-telemetry-java17", + "jvm.cpu.limit", + AbstractIterableAssert::isNotEmpty); + } +} diff --git a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java index 9056a3fad25e..1988b1e900df 100644 --- a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java @@ -209,11 +209,20 @@ void shouldSendTelemetry() { OtelSpringStarterSmokeTestController.METER_SCOPE_NAME, OtelSpringStarterSmokeTestController.TEST_HISTOGRAM, AbstractIterableAssert::isNotEmpty); + // runtime metrics + // from special logic for threads that is automatically detected in GraalVM native image + // see io.opentelemetry.instrumentation.runtimemetrics.java8.Threads testing.waitAndAssertMetrics( "io.opentelemetry.runtime-telemetry-java8", "jvm.thread.count", AbstractIterableAssert::isNotEmpty); + // JMX based metrics + testing.waitAndAssertMetrics( + "io.opentelemetry.runtime-telemetry-java8", + "jvm.memory.used", + AbstractIterableAssert::isNotEmpty); + assertAdditionalMetrics(); // Log List exportedLogRecords = testing.getExportedLogRecords(); @@ -233,6 +242,8 @@ void shouldSendTelemetry() { } } + protected void assertAdditionalMetrics() {} + @Test void databaseQuery() { testing.clearAllExportedData(); From a4eec274e44361dcdae266aea0effdd3b42d03c8 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 28 Jan 2025 19:10:42 +0100 Subject: [PATCH 09/35] add metadata --- ...itional-spring-configuration-metadata.json | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 68a06350a09d..f179b7e7f9bd 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -476,6 +476,30 @@ "description": "Enables the DB statement sanitization.", "defaultValue": true }, + { + "name": "otel.instrumentation.runtime-telemetry.enabled", + "type": "java.lang.Boolean", + "description": "Enable runtime telemetry metrics.", + "defaultValue": true + }, + { + "name": "otel.instrumentation.runtime-telemetry.emit-experimental-telemetry", + "type": "java.lang.Boolean", + "description": "Enable the capture of experimental metrics.", + "defaultValue": false + }, + { + "name": "otel.instrumentation.runtime-telemetry-java17.enable-all", + "type": "java.lang.Boolean", + "description": "Enable the capture of all JFR based metrics.", + "defaultValue": false + }, + { + "name": "otel.instrumentation.runtime-telemetry-java17.enabled", + "type": "java.lang.Boolean", + "description": "Enable the capture of JFR based metrics.", + "defaultValue": false + }, { "name": "otel.instrumentation.spring-web.enabled", "type": "java.lang.Boolean", From 66a8a9a80586a93d68de10e5378b86577f4cde18 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 29 Jan 2025 13:28:33 +0100 Subject: [PATCH 10/35] fix jfr and native image --- .../runtimemetrics/java17/RuntimeMetrics.java | 5 +++-- .../runtimemetrics/java17/RuntimeMetricsBuilder.java | 2 +- .../runtimemetrics/java8/RuntimeMetricsBuilder.java | 2 +- smoke-tests-otel-starter/spring-boot-3/build.gradle.kts | 4 ++++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java index 96a98b7fcdbd..188d939576f7 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java @@ -101,7 +101,7 @@ private JfrRuntimeMetrics(OpenTelemetry openTelemetry, Predicate fea recordingStream.onEvent(handler.getEventName(), handler); }); recordingStream.onMetadata(event -> startUpLatch.countDown()); - Thread daemonRunner = new Thread(() -> recordingStream.start()); + Thread daemonRunner = new Thread(recordingStream::start, "JFR-Metrics-Runner"); daemonRunner.setDaemon(true); daemonRunner.start(); } @@ -138,7 +138,8 @@ CountDownLatch getStartUpLatch() { private static boolean isJfrAvailable() { try { Class.forName("jdk.jfr.FlightRecorder"); - } catch (ClassNotFoundException e) { + // UnsatisfiedLinkError or ClassNotFoundException + } catch (Exception e) { return false; } diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java index 7411dc747886..add6f0460656 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java @@ -26,7 +26,7 @@ public final class RuntimeMetricsBuilder { private boolean enableExperimentalJmxTelemetry = false; private Consumer shutdownHook = runnable -> { - Runtime.getRuntime().addShutdownHook(new Thread(runnable)); + Runtime.getRuntime().addShutdownHook(new Thread(runnable, "RuntimeMetricsShutdownHook")); }; RuntimeMetricsBuilder(OpenTelemetry openTelemetry) { diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java index e6cceaa095d9..7e8e9a036f06 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java @@ -20,7 +20,7 @@ public final class RuntimeMetricsBuilder { private boolean enableExperimentalJmxTelemetry = false; private Consumer shutdownHook = runnable -> { - Runtime.getRuntime().addShutdownHook(new Thread(runnable)); + Runtime.getRuntime().addShutdownHook(new Thread(runnable, "RuntimeMetricsShutdownHook")); }; RuntimeMetricsBuilder(OpenTelemetry openTelemetry) { diff --git a/smoke-tests-otel-starter/spring-boot-3/build.gradle.kts b/smoke-tests-otel-starter/spring-boot-3/build.gradle.kts index 78e01e6685e1..284d3543fc0b 100644 --- a/smoke-tests-otel-starter/spring-boot-3/build.gradle.kts +++ b/smoke-tests-otel-starter/spring-boot-3/build.gradle.kts @@ -66,6 +66,10 @@ graalvmNative { // Workaround for https://github.com/junit-team/junit5/issues/3405 buildArgs.add("--initialize-at-build-time=org.junit.platform.launcher.core.LauncherConfig") buildArgs.add("--initialize-at-build-time=org.junit.jupiter.engine.config.InstantiatingConfigurationParameterConverter") + + // enable JFR - see https://www.graalvm.org/22.0/reference-manual/native-image/JFR/ + buildArgs.add("-H:+AllowVMInspection") + jvmArgs("-XX:+FlightRecorder") } // See https://github.com/graalvm/native-build-tools/issues/572 From c659bcbd1730f550df238a2258162e8b3113fe31 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 29 Jan 2025 13:29:38 +0100 Subject: [PATCH 11/35] fix jfr and native image --- smoke-tests-otel-starter/spring-boot-3/build.gradle.kts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/smoke-tests-otel-starter/spring-boot-3/build.gradle.kts b/smoke-tests-otel-starter/spring-boot-3/build.gradle.kts index 284d3543fc0b..3aacaf77d539 100644 --- a/smoke-tests-otel-starter/spring-boot-3/build.gradle.kts +++ b/smoke-tests-otel-starter/spring-boot-3/build.gradle.kts @@ -68,8 +68,7 @@ graalvmNative { buildArgs.add("--initialize-at-build-time=org.junit.jupiter.engine.config.InstantiatingConfigurationParameterConverter") // enable JFR - see https://www.graalvm.org/22.0/reference-manual/native-image/JFR/ - buildArgs.add("-H:+AllowVMInspection") - jvmArgs("-XX:+FlightRecorder") + buildArgs.add("--enable-monitoring=jfr") } // See https://github.com/graalvm/native-build-tools/issues/572 From f0c06cdd419cfc55de2d8285f7866e720564a15c Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 30 Jan 2025 12:28:14 +0100 Subject: [PATCH 12/35] review --- .../runtimemetrics/java17/RuntimeMetrics.java | 2 +- .../runtimemetrics/java17/RuntimeMetricsBuilder.java | 2 +- .../runtimemetrics/java8/RuntimeMetrics.java | 6 +++--- .../runtimemetrics/java8/RuntimeMetricsBuilder.java | 6 +----- smoke-tests-otel-starter/spring-boot-3/build.gradle.kts | 2 +- 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java index 188d939576f7..aabe280576cb 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java @@ -101,7 +101,7 @@ private JfrRuntimeMetrics(OpenTelemetry openTelemetry, Predicate fea recordingStream.onEvent(handler.getEventName(), handler); }); recordingStream.onMetadata(event -> startUpLatch.countDown()); - Thread daemonRunner = new Thread(recordingStream::start, "JFR-Metrics-Runner"); + Thread daemonRunner = new Thread(recordingStream::start, "OpenTelemetry JFR-Metrics-Runner"); daemonRunner.setDaemon(true); daemonRunner.start(); } diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java index add6f0460656..155ba20b7297 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java @@ -26,7 +26,7 @@ public final class RuntimeMetricsBuilder { private boolean enableExperimentalJmxTelemetry = false; private Consumer shutdownHook = runnable -> { - Runtime.getRuntime().addShutdownHook(new Thread(runnable, "RuntimeMetricsShutdownHook")); + Runtime.getRuntime().addShutdownHook(new Thread(runnable, "OpenTelemetry RuntimeMetricsShutdownHook")); }; RuntimeMetricsBuilder(OpenTelemetry openTelemetry) { diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetrics.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetrics.java index 86afabd17301..dec3beac8685 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetrics.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetrics.java @@ -14,7 +14,7 @@ import java.util.logging.Level; import java.util.logging.Logger; -/** The entry point class for runtime metrics support using JFR and JMX. */ +/** The entry point class for runtime metrics support using JMX. */ public final class RuntimeMetrics implements Closeable { private static final Logger logger = Logger.getLogger(RuntimeMetrics.class.getName()); @@ -29,7 +29,7 @@ public final class RuntimeMetrics implements Closeable { /** * Create and start {@link RuntimeMetrics}. * - *

Listens for select JFR events, extracts data, and records to various metrics. Recording will + *

Listens for select JMX beans, extracts data, and records to various metrics. Recording will * continue until {@link #close()} is called. * * @param openTelemetry the {@link OpenTelemetry} instance used to record telemetry @@ -47,7 +47,7 @@ public static RuntimeMetricsBuilder builder(OpenTelemetry openTelemetry) { return new RuntimeMetricsBuilder(openTelemetry); } - /** Stop recording JFR events. */ + /** Stop recording JMX metrics. */ @Override public void close() { if (!isClosed.compareAndSet(false, true)) { diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java index 7e8e9a036f06..0c7c973d1034 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java @@ -20,7 +20,7 @@ public final class RuntimeMetricsBuilder { private boolean enableExperimentalJmxTelemetry = false; private Consumer shutdownHook = runnable -> { - Runtime.getRuntime().addShutdownHook(new Thread(runnable, "RuntimeMetricsShutdownHook")); + Runtime.getRuntime().addShutdownHook(new Thread(runnable, "OpenTelemetry RuntimeMetricsShutdownHook")); }; RuntimeMetricsBuilder(OpenTelemetry openTelemetry) { @@ -49,10 +49,6 @@ public RuntimeMetricsBuilder setShutdownHook(Consumer shutdownHook) { } public void startFromInstrumentationConfig(InstrumentationConfig config) { - /* - By default, don't use any JFR metrics. May change this once semantic conventions are updated. - If enabled, default to only the metrics not already covered by runtime-telemetry-java8 - */ boolean defaultEnabled = config.getBoolean("otel.instrumentation.common.default-enabled", true); if (!config.getBoolean("otel.instrumentation.runtime-telemetry.enabled", defaultEnabled)) { // nothing is enabled diff --git a/smoke-tests-otel-starter/spring-boot-3/build.gradle.kts b/smoke-tests-otel-starter/spring-boot-3/build.gradle.kts index 3aacaf77d539..1392ad4844ab 100644 --- a/smoke-tests-otel-starter/spring-boot-3/build.gradle.kts +++ b/smoke-tests-otel-starter/spring-boot-3/build.gradle.kts @@ -67,7 +67,7 @@ graalvmNative { buildArgs.add("--initialize-at-build-time=org.junit.platform.launcher.core.LauncherConfig") buildArgs.add("--initialize-at-build-time=org.junit.jupiter.engine.config.InstantiatingConfigurationParameterConverter") - // enable JFR - see https://www.graalvm.org/22.0/reference-manual/native-image/JFR/ + // enable JFR - see https://www.graalvm.org/latest/reference-manual/native-image/debugging-and-diagnostics/JFR/ buildArgs.add("--enable-monitoring=jfr") } From 1b3b510c5e39ad1fb17882e219563ea8b1cff6e3 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 30 Jan 2025 13:01:44 +0100 Subject: [PATCH 13/35] test more metrics --- .../smoketest/OtelSpringStarterSmokeTest.java | 3 ++- .../smoketest/OtelSpringStarterSmokeTest.java | 25 +++++++++++++++---- .../AbstractOtelSpringStarterSmokeTest.java | 18 ++++++++++--- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/smoke-tests-otel-starter/spring-boot-2/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-boot-2/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java index 315e8155413b..65315b926d5b 100644 --- a/smoke-tests-otel-starter/spring-boot-2/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-boot-2/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java @@ -16,6 +16,7 @@ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { // The headers are simply set here to make sure that headers can be parsed - "otel.exporter.otlp.headers.c=3" + "otel.exporter.otlp.headers.c=3", + "otel.instrumentation.runtime-telemetry.emit-experimental-telemetry=true", }) class OtelSpringStarterSmokeTest extends AbstractOtelSpringStarterSmokeTest {} diff --git a/smoke-tests-otel-starter/spring-boot-3/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-boot-3/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java index eee483ccb319..76184abc1f6b 100644 --- a/smoke-tests-otel-starter/spring-boot-3/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-boot-3/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java @@ -5,6 +5,7 @@ package io.opentelemetry.spring.smoketest; +import java.util.List; import org.assertj.core.api.AbstractIterableAssert; import org.springframework.boot.test.context.SpringBootTest; @@ -18,16 +19,30 @@ properties = { // The headers are simply set here to make sure that headers can be parsed "otel.exporter.otlp.headers.c=3", - "otel.instrumentation.runtime-telemetry-java17.enabled=true", + "otel.instrumentation.runtime-telemetry.emit-experimental-telemetry=true", + "otel.instrumentation.runtime-telemetry-java17.enable-all=true", }) class OtelSpringStarterSmokeTest extends AbstractOtelSpringStarterSmokeTest { @Override protected void assertAdditionalMetrics() { // JFR based metrics - testing.waitAndAssertMetrics( - "io.opentelemetry.runtime-telemetry-java17", - "jvm.cpu.limit", - AbstractIterableAssert::isNotEmpty); + for (String metric : + List.of( + "jvm.cpu.limit", + "jvm.buffer.count", + "jvm.class.count", + "jvm.cpu.context_switch", + "jvm.cpu.longlock", + "jvm.system.cpu.utilization", + "jvm.gc.duration", + "jvm.memory.init", + "jvm.memory.used", + "jvm.memory.allocation", + "jvm.network.io ", + "jvm.thread.count")) { + testing.waitAndAssertMetrics( + "io.opentelemetry.runtime-telemetry-java17", metric, AbstractIterableAssert::isNotEmpty); + } } } diff --git a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java index 1988b1e900df..d4a0a2425a78 100644 --- a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java @@ -29,6 +29,7 @@ import io.opentelemetry.semconv.incubating.DbIncubatingAttributes; import io.opentelemetry.semconv.incubating.ServiceIncubatingAttributes; import java.net.URI; +import java.util.Arrays; import java.util.Collections; import java.util.List; import org.assertj.core.api.AbstractCharSequenceAssert; @@ -217,11 +218,20 @@ void shouldSendTelemetry() { "io.opentelemetry.runtime-telemetry-java8", "jvm.thread.count", AbstractIterableAssert::isNotEmpty); + // JMX based metrics - testing.waitAndAssertMetrics( - "io.opentelemetry.runtime-telemetry-java8", - "jvm.memory.used", - AbstractIterableAssert::isNotEmpty); + Arrays.asList( + "jvm.memory.used", + "jvm.system.cpu.load_1m", + "jvm.buffer.memory.usage", + "jvm.memory.init") + .forEach( + metricName -> + testing.waitAndAssertMetrics( + "io.opentelemetry.runtime-telemetry-java8", + metricName, + AbstractIterableAssert::isNotEmpty)); + assertAdditionalMetrics(); // Log From 3f64db1c128695e24a507ebc45fc7e27658fefbd Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 30 Jan 2025 13:11:59 +0100 Subject: [PATCH 14/35] test more metrics --- .../spring/smoketest/OtelSpringStarterSmokeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smoke-tests-otel-starter/spring-boot-3/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-boot-3/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java index 76184abc1f6b..b94278398ff4 100644 --- a/smoke-tests-otel-starter/spring-boot-3/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-boot-3/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java @@ -39,7 +39,7 @@ protected void assertAdditionalMetrics() { "jvm.memory.init", "jvm.memory.used", "jvm.memory.allocation", - "jvm.network.io ", + "jvm.network.io", "jvm.thread.count")) { testing.waitAndAssertMetrics( "io.opentelemetry.runtime-telemetry-java17", metric, AbstractIterableAssert::isNotEmpty); From bcd43e69fd0852892aaa0a8a037ca1ef2ed0a251 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 30 Jan 2025 14:17:32 +0100 Subject: [PATCH 15/35] format --- .../runtimemetrics/java17/RuntimeMetricsBuilder.java | 3 ++- .../runtimemetrics/java8/RuntimeMetricsBuilder.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java index 155ba20b7297..c6886403f01f 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java @@ -26,7 +26,8 @@ public final class RuntimeMetricsBuilder { private boolean enableExperimentalJmxTelemetry = false; private Consumer shutdownHook = runnable -> { - Runtime.getRuntime().addShutdownHook(new Thread(runnable, "OpenTelemetry RuntimeMetricsShutdownHook")); + Runtime.getRuntime() + .addShutdownHook(new Thread(runnable, "OpenTelemetry RuntimeMetricsShutdownHook")); }; RuntimeMetricsBuilder(OpenTelemetry openTelemetry) { diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java index 0c7c973d1034..584c68433e1b 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java @@ -20,7 +20,8 @@ public final class RuntimeMetricsBuilder { private boolean enableExperimentalJmxTelemetry = false; private Consumer shutdownHook = runnable -> { - Runtime.getRuntime().addShutdownHook(new Thread(runnable, "OpenTelemetry RuntimeMetricsShutdownHook")); + Runtime.getRuntime() + .addShutdownHook(new Thread(runnable, "OpenTelemetry RuntimeMetricsShutdownHook")); }; RuntimeMetricsBuilder(OpenTelemetry openTelemetry) { From 215d8572af9ee7f8169be494825134972ae53802 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 30 Jan 2025 14:18:06 +0100 Subject: [PATCH 16/35] use newer graalvm --- .github/workflows/reusable-native-tests.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/reusable-native-tests.yml b/.github/workflows/reusable-native-tests.yml index b72256ee0ed5..c551e297be50 100644 --- a/.github/workflows/reusable-native-tests.yml +++ b/.github/workflows/reusable-native-tests.yml @@ -19,12 +19,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - id: read-java - run: echo "version=$(cat .java-version)" >> "$GITHUB_OUTPUT" - uses: graalvm/setup-graalvm@aafbedb8d382ed0ca6167d3a051415f20c859274 # v1.2.8.1 with: version: "latest" - java-version: "${{ steps.read-java.outputs.version }}" + java-version: "23" # earlier versions have different arguments to enable JFR components: "native-image" - name: Running test env: From 638af92562d77f3581f18caf214488cf89ec20e8 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 30 Jan 2025 15:19:47 +0100 Subject: [PATCH 17/35] init at build time --- .../opentelemetry-instrumentation-api/native-image.properties | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/instrumentation-api/src/main/resources/META-INF/native-image/io.opentelemetry.instrumentation/opentelemetry-instrumentation-api/native-image.properties b/instrumentation-api/src/main/resources/META-INF/native-image/io.opentelemetry.instrumentation/opentelemetry-instrumentation-api/native-image.properties index 758891265640..5620b43240bb 100644 --- a/instrumentation-api/src/main/resources/META-INF/native-image/io.opentelemetry.instrumentation/opentelemetry-instrumentation-api/native-image.properties +++ b/instrumentation-api/src/main/resources/META-INF/native-image/io.opentelemetry.instrumentation/opentelemetry-instrumentation-api/native-image.properties @@ -1,2 +1,3 @@ Args=\ - --initialize-at-build-time=io.opentelemetry.instrumentation.api.internal.cache.concurrentlinkedhashmap.ConcurrentLinkedHashMap + --initialize-at-build-time=io.opentelemetry.instrumentation.api.internal.cache.concurrentlinkedhashmap.ConcurrentLinkedHashMap \ + --initialize-at-build-time=io.opentelemetry.api.internal.InternalAttributeKeyImpl From b51bec3877917f55f13c1587adff2c105649f099 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 31 Jan 2025 10:47:00 +0100 Subject: [PATCH 18/35] init at build time --- .../opentelemetry-instrumentation-api/native-image.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/instrumentation-api/src/main/resources/META-INF/native-image/io.opentelemetry.instrumentation/opentelemetry-instrumentation-api/native-image.properties b/instrumentation-api/src/main/resources/META-INF/native-image/io.opentelemetry.instrumentation/opentelemetry-instrumentation-api/native-image.properties index 5620b43240bb..83efd36a27e8 100644 --- a/instrumentation-api/src/main/resources/META-INF/native-image/io.opentelemetry.instrumentation/opentelemetry-instrumentation-api/native-image.properties +++ b/instrumentation-api/src/main/resources/META-INF/native-image/io.opentelemetry.instrumentation/opentelemetry-instrumentation-api/native-image.properties @@ -1,3 +1,4 @@ Args=\ --initialize-at-build-time=io.opentelemetry.instrumentation.api.internal.cache.concurrentlinkedhashmap.ConcurrentLinkedHashMap \ + --initialize-at-build-time=io.opentelemetry.instrumentation.api.internal.cache.MapBackedCache \ --initialize-at-build-time=io.opentelemetry.api.internal.InternalAttributeKeyImpl From b7e8dbc1c15ff048dba29d6318bfa00b466c9aa0 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 3 Feb 2025 10:47:16 +0100 Subject: [PATCH 19/35] disable jfr for native for now --- .github/workflows/reusable-native-tests.yml | 4 +++- smoke-tests-otel-starter/spring-boot-3/build.gradle.kts | 3 --- .../spring/smoketest/OtelSpringStarterSmokeTest.java | 5 +++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/reusable-native-tests.yml b/.github/workflows/reusable-native-tests.yml index c551e297be50..b72256ee0ed5 100644 --- a/.github/workflows/reusable-native-tests.yml +++ b/.github/workflows/reusable-native-tests.yml @@ -19,10 +19,12 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - id: read-java + run: echo "version=$(cat .java-version)" >> "$GITHUB_OUTPUT" - uses: graalvm/setup-graalvm@aafbedb8d382ed0ca6167d3a051415f20c859274 # v1.2.8.1 with: version: "latest" - java-version: "23" # earlier versions have different arguments to enable JFR + java-version: "${{ steps.read-java.outputs.version }}" components: "native-image" - name: Running test env: diff --git a/smoke-tests-otel-starter/spring-boot-3/build.gradle.kts b/smoke-tests-otel-starter/spring-boot-3/build.gradle.kts index 1392ad4844ab..78e01e6685e1 100644 --- a/smoke-tests-otel-starter/spring-boot-3/build.gradle.kts +++ b/smoke-tests-otel-starter/spring-boot-3/build.gradle.kts @@ -66,9 +66,6 @@ graalvmNative { // Workaround for https://github.com/junit-team/junit5/issues/3405 buildArgs.add("--initialize-at-build-time=org.junit.platform.launcher.core.LauncherConfig") buildArgs.add("--initialize-at-build-time=org.junit.jupiter.engine.config.InstantiatingConfigurationParameterConverter") - - // enable JFR - see https://www.graalvm.org/latest/reference-manual/native-image/debugging-and-diagnostics/JFR/ - buildArgs.add("--enable-monitoring=jfr") } // See https://github.com/graalvm/native-build-tools/issues/572 diff --git a/smoke-tests-otel-starter/spring-boot-3/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-boot-3/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java index b94278398ff4..89a0a07c1b3a 100644 --- a/smoke-tests-otel-starter/spring-boot-3/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-boot-3/src/test/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTest.java @@ -26,6 +26,11 @@ class OtelSpringStarterSmokeTest extends AbstractOtelSpringStarterSmokeTest { @Override protected void assertAdditionalMetrics() { + if (System.getProperty("org.graalvm.nativeimage.imagecode") != null) { + // GraalVM native image does not support JFR + return; + } + // JFR based metrics for (String metric : List.of( From fca99a57bc46fbdc7d24f957188ec69ac7c9682f Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 3 Feb 2025 12:14:15 +0100 Subject: [PATCH 20/35] fix jfr --- .../runtimemetrics/java17/RuntimeMetrics.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java index aabe280576cb..e180d769b271 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java @@ -136,6 +136,11 @@ CountDownLatch getStartUpLatch() { } private static boolean isJfrAvailable() { + if (System.getProperty("org.graalvm.nativeimage.imagecode") != null) { + // GraalVM native image does not support JFR + return false; + } + try { Class.forName("jdk.jfr.FlightRecorder"); // UnsatisfiedLinkError or ClassNotFoundException From 4d9792ef062da9eae095e78783827cdf80d047b0 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 3 Feb 2025 14:14:27 +0100 Subject: [PATCH 21/35] fix buffer pools --- .../AbstractOtelSpringStarterSmokeTest.java | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java index d4a0a2425a78..090af6ff5965 100644 --- a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java @@ -29,6 +29,7 @@ import io.opentelemetry.semconv.incubating.DbIncubatingAttributes; import io.opentelemetry.semconv.incubating.ServiceIncubatingAttributes; import java.net.URI; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -220,24 +221,28 @@ void shouldSendTelemetry() { AbstractIterableAssert::isNotEmpty); // JMX based metrics - Arrays.asList( - "jvm.memory.used", - "jvm.system.cpu.load_1m", - "jvm.buffer.memory.usage", - "jvm.memory.init") - .forEach( - metricName -> - testing.waitAndAssertMetrics( - "io.opentelemetry.runtime-telemetry-java8", - metricName, - AbstractIterableAssert::isNotEmpty)); + List jmxMetrics = + new ArrayList<>( + Arrays.asList("jvm.memory.used", "jvm.system.cpu.load_1m", "jvm.memory.init")); + + boolean noNative = System.getProperty("org.graalvm.nativeimage.imagecode") == null; + if (noNative) { + // GraalVM native image does not support buffer pools - have to investigate why + jmxMetrics.add("jvm.buffer.memory.usage"); + } + jmxMetrics.forEach( + metricName -> + testing.waitAndAssertMetrics( + "io.opentelemetry.runtime-telemetry-java8", + metricName, + AbstractIterableAssert::isNotEmpty)); assertAdditionalMetrics(); // Log List exportedLogRecords = testing.getExportedLogRecords(); assertThat(exportedLogRecords).as("No log record exported.").isNotEmpty(); - if (System.getProperty("org.graalvm.nativeimage.imagecode") == null) { + if (noNative) { // log records differ in native image mode due to different startup timing LogRecordData firstLog = exportedLogRecords.get(0); assertThat(firstLog.getBodyValue().asString()) From 611404af0d7481d49b3a6b76d0a95cbb86b90d6e Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 3 Feb 2025 14:17:02 +0100 Subject: [PATCH 22/35] fix buffer pools --- .../AbstractOtelSpringStarterSmokeTest.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java index 090af6ff5965..e4a85eb343f0 100644 --- a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java @@ -212,18 +212,14 @@ void shouldSendTelemetry() { OtelSpringStarterSmokeTestController.TEST_HISTOGRAM, AbstractIterableAssert::isNotEmpty); - // runtime metrics - // from special logic for threads that is automatically detected in GraalVM native image - // see io.opentelemetry.instrumentation.runtimemetrics.java8.Threads - testing.waitAndAssertMetrics( - "io.opentelemetry.runtime-telemetry-java8", - "jvm.thread.count", - AbstractIterableAssert::isNotEmpty); - - // JMX based metrics + // JMX based metrics - test one per JMX bean List jmxMetrics = new ArrayList<>( - Arrays.asList("jvm.memory.used", "jvm.system.cpu.load_1m", "jvm.memory.init")); + Arrays.asList( + "jvm.thread.count", + "jvm.memory.used", + "jvm.system.cpu.load_1m", + "jvm.memory.init")); boolean noNative = System.getProperty("org.graalvm.nativeimage.imagecode") == null; if (noNative) { From 52e3632d345a56526031d53e942c7288a8ac77fe Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 5 Feb 2025 12:45:53 +0100 Subject: [PATCH 23/35] extract metrics providers --- .../Java17RuntimeMetricsProvider.java | 32 +++++++++++++++++++ .../Java8RuntimeMetricsProvider.java | 32 +++++++++++++++++++ .../RuntimeMetricsAutoConfiguration.java | 21 ++++++------ .../RuntimeMetricsProvider.java | 17 ++++++++++ .../main/resources/META-INF/spring.factories | 4 ++- ...ot.autoconfigure.AutoConfiguration.imports | 2 ++ 6 files changed, 98 insertions(+), 10 deletions(-) create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsProvider.java create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsProvider.java diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsProvider.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsProvider.java new file mode 100644 index 000000000000..904722cdbb5c --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsProvider.java @@ -0,0 +1,32 @@ +package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; +import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.function.Consumer; + +/** + * Configures runtime metrics collection for Java 17+. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public class Java17RuntimeMetricsProvider implements RuntimeMetricsProvider { + private static final Logger logger = LoggerFactory.getLogger(Java17RuntimeMetricsProvider.class); + + @Override + public int minJavaVersion() { + return 17; + } + + @Override + public void start( + OpenTelemetry openTelemetry, Consumer shutdownHook, InstrumentationConfig config) { + logger.debug("Use runtime metrics instrumentation for Java 17+"); + RuntimeMetrics.builder(openTelemetry) + .setShutdownHook(shutdownHook) + .startFromInstrumentationConfig(config); + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java new file mode 100644 index 000000000000..7e2199a9bf20 --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java @@ -0,0 +1,32 @@ +package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; +import io.opentelemetry.instrumentation.runtimemetrics.java8.RuntimeMetrics; +import java.util.function.Consumer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Configures runtime metrics collection for Java 8. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public class Java8RuntimeMetricsProvider implements RuntimeMetricsProvider { + private static final Logger logger = LoggerFactory.getLogger(Java8RuntimeMetricsProvider.class); + + @Override + public int minJavaVersion() { + return 1; + } + + @Override + public void start( + OpenTelemetry openTelemetry, Consumer shutdownHook, InstrumentationConfig config) { + logger.debug("Use runtime metrics instrumentation for Java 8"); + RuntimeMetrics.builder(openTelemetry) + .setShutdownHook(shutdownHook) + .startFromInstrumentationConfig(config); + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java index 7c3a312131e8..c3526c5fee5c 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java @@ -9,6 +9,8 @@ import io.opentelemetry.instrumentation.spring.autoconfigure.internal.ConditionalOnEnabledInstrumentation; import io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties.ConfigPropertiesBridge; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import java.util.Comparator; +import java.util.Optional; import javax.annotation.PreDestroy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,16 +48,17 @@ public void handleApplicationReadyEvent(ApplicationReadyEvent event) { ConfigPropertiesBridge config = new ConfigPropertiesBridge(applicationContext.getBean(ConfigProperties.class)); - if (Double.parseDouble(System.getProperty("java.specification.version")) >= 17) { - logger.debug("Use runtime metrics instrumentation for Java 17+"); - io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics.builder(openTelemetry) - .setShutdownHook(runnable -> shutdownHook = runnable) - .startFromInstrumentationConfig(config); + double version = Double.parseDouble(System.getProperty("java.specification.version")); + Optional metricsProvider = + applicationContext.getBeanProvider(RuntimeMetricsProvider.class).stream() + .sorted(Comparator.comparing(RuntimeMetricsProvider::minJavaVersion).reversed()) + .filter(provider -> provider.minJavaVersion() <= version) + .findFirst(); + + if (metricsProvider.isPresent()) { + metricsProvider.get().start(openTelemetry, runnable -> shutdownHook = runnable, config); } else { - logger.debug("Use runtime metrics instrumentation for Java 8"); - io.opentelemetry.instrumentation.runtimemetrics.java8.RuntimeMetrics.builder(openTelemetry) - .setShutdownHook(runnable -> shutdownHook = runnable) - .startFromInstrumentationConfig(config); + logger.debug("No runtime metrics instrumentation available for Java {}", version); } } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsProvider.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsProvider.java new file mode 100644 index 000000000000..914db0c7badd --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsProvider.java @@ -0,0 +1,17 @@ +package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; +import java.util.function.Consumer; + +/** + * Configures runtime metrics collection. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public interface RuntimeMetricsProvider { + int minJavaVersion(); + + void start(OpenTelemetry openTelemetry, Consumer shutdownHook, InstrumentationConfig config); +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index bf7f5dc46fe2..cb026785d354 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -11,7 +11,9 @@ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.w io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.webflux.SpringWebfluxInstrumentationAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.webmvc.SpringWebMvc5InstrumentationAutoConfiguration,\ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.scheduling.SpringSchedulingInstrumentationAutoConfiguration,\ -io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.RuntimeMetricsAutoConfiguration +io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.RuntimeMetricsAutoConfiguration,\ +io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java8RuntimeMetricsProvider,\ +io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java17RuntimeMetricsProvider org.springframework.context.ApplicationListener=\ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.logging.LogbackAppenderApplicationListener diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index fda05853c855..2392e0c35592 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -12,3 +12,5 @@ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.w io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.webmvc.SpringWebMvc6InstrumentationAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.scheduling.SpringSchedulingInstrumentationAutoConfiguration io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.RuntimeMetricsAutoConfiguration +io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java8RuntimeMetricsProvider +io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java17RuntimeMetricsProvider From b805da906342293c1d652fba5886a7289f396eeb Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 5 Feb 2025 13:00:07 +0100 Subject: [PATCH 24/35] exclude JFR from native image at build time --- .../runtimemetrics/java17/RuntimeMetrics.java | 5 ----- ...eMetricsBeanRegistrationExcludeFilter.java | 19 +++++++++++++++++++ .../resources/META-INF/spring/aot.factories | 3 +++ 3 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java index e180d769b271..aabe280576cb 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java @@ -136,11 +136,6 @@ CountDownLatch getStartUpLatch() { } private static boolean isJfrAvailable() { - if (System.getProperty("org.graalvm.nativeimage.imagecode") != null) { - // GraalVM native image does not support JFR - return false; - } - try { Class.forName("jdk.jfr.FlightRecorder"); // UnsatisfiedLinkError or ClassNotFoundException diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java new file mode 100644 index 000000000000..8580fbd42188 --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java @@ -0,0 +1,19 @@ +package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics; + +import org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter; +import org.springframework.beans.factory.support.RegisteredBean; + +/** + * Configures runtime metrics collection for Java 17+. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public class RuntimeMetricsBeanRegistrationExcludeFilter implements BeanRegistrationExcludeFilter { + @Override + public boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) { + // GraalVM native image does not support JFR, so we exclude Java 17+ runtime metrics provider + return "io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java17RuntimeMetricsProvider" + .equals(registeredBean.getBeanName()); + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/aot.factories b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/aot.factories index 8d199e0f8345..e97c4b46ae9c 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/aot.factories +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/spring/aot.factories @@ -1,2 +1,5 @@ org.springframework.aot.hint.RuntimeHintsRegistrar=\ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.annotations.OpenTelemetryAnnotationsRuntimeHints + +org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter=\ +io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.RuntimeMetricsBeanRegistrationExcludeFilter From 67fb8d2c4375547eeda366cb741968824dcde4cf Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 5 Feb 2025 14:20:18 +0100 Subject: [PATCH 25/35] format --- .../runtimemetrics/Java17RuntimeMetricsProvider.java | 7 ++++++- .../runtimemetrics/Java8RuntimeMetricsProvider.java | 5 +++++ .../runtimemetrics/RuntimeMetricsProvider.java | 8 +++++++- .../RuntimeMetricsBeanRegistrationExcludeFilter.java | 5 +++++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsProvider.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsProvider.java index 904722cdbb5c..3ea023b00ae3 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsProvider.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsProvider.java @@ -1,11 +1,16 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics; +import java.util.function.Consumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.function.Consumer; /** * Configures runtime metrics collection for Java 17+. diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java index 7e2199a9bf20..c9b23c08bc6d 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java @@ -1,3 +1,8 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics; import io.opentelemetry.api.OpenTelemetry; diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsProvider.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsProvider.java index 914db0c7badd..553a0a2e5273 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsProvider.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsProvider.java @@ -1,3 +1,8 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics; import io.opentelemetry.api.OpenTelemetry; @@ -13,5 +18,6 @@ public interface RuntimeMetricsProvider { int minJavaVersion(); - void start(OpenTelemetry openTelemetry, Consumer shutdownHook, InstrumentationConfig config); + void start( + OpenTelemetry openTelemetry, Consumer shutdownHook, InstrumentationConfig config); } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java index 8580fbd42188..64cc9300ee55 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java @@ -1,3 +1,8 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics; import org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter; From c5790fdd99fb5c7bae13a39209727a604a536316 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 6 Feb 2025 11:39:18 +0100 Subject: [PATCH 26/35] Update instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java Co-authored-by: Jean Bisutti --- .../RuntimeMetricsBeanRegistrationExcludeFilter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java index 64cc9300ee55..365c38ad586e 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java @@ -17,7 +17,8 @@ public class RuntimeMetricsBeanRegistrationExcludeFilter implements BeanRegistrationExcludeFilter { @Override public boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) { - // GraalVM native image does not support JFR, so we exclude Java 17+ runtime metrics provider + // The JFR-based runtime metric code is exlcuded from the Spring AOT processing step. So, this code is not included in a Spring native image application. + return "io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java17RuntimeMetricsProvider" .equals(registeredBean.getBeanName()); } From 8cc8c0008c906e6ab3a669abb6c34f1392792435 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 6 Feb 2025 12:10:39 +0100 Subject: [PATCH 27/35] format --- .../RuntimeMetricsBeanRegistrationExcludeFilter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java index 365c38ad586e..6909a362e2bd 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java @@ -17,7 +17,8 @@ public class RuntimeMetricsBeanRegistrationExcludeFilter implements BeanRegistrationExcludeFilter { @Override public boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) { - // The JFR-based runtime metric code is exlcuded from the Spring AOT processing step. So, this code is not included in a Spring native image application. + // The JFR-based runtime metric code is excluded from the Spring AOT processing step. + // That way, this code is not included in a Spring native image application. return "io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java17RuntimeMetricsProvider" .equals(registeredBean.getBeanName()); From a6a87c502de813dad3d6be6a65f932f315ea28fc Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 10 Feb 2025 11:12:23 +0100 Subject: [PATCH 28/35] fix java version parsing --- .../runtimemetrics/Java8RuntimeMetricsProvider.java | 2 +- .../RuntimeMetricsAutoConfiguration.java | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java index c9b23c08bc6d..bd3ada26461e 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java @@ -23,7 +23,7 @@ public class Java8RuntimeMetricsProvider implements RuntimeMetricsProvider { @Override public int minJavaVersion() { - return 1; + return 8; } @Override diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java index c3526c5fee5c..86e4b6adb4c5 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java @@ -48,7 +48,7 @@ public void handleApplicationReadyEvent(ApplicationReadyEvent event) { ConfigPropertiesBridge config = new ConfigPropertiesBridge(applicationContext.getBean(ConfigProperties.class)); - double version = Double.parseDouble(System.getProperty("java.specification.version")); + double version = javaVersion(); Optional metricsProvider = applicationContext.getBeanProvider(RuntimeMetricsProvider.class).stream() .sorted(Comparator.comparing(RuntimeMetricsProvider::minJavaVersion).reversed()) @@ -61,4 +61,13 @@ public void handleApplicationReadyEvent(ApplicationReadyEvent event) { logger.debug("No runtime metrics instrumentation available for Java {}", version); } } + + private int javaVersion() { + try { + return Integer.parseInt(System.getProperty("java.specification.version")); + } catch (NumberFormatException nfe) { + // The value of the java.specification.version property is 1.8 with a Java 8 runtime. + return 8; + } + } } From a1bd5189744ad1a2160b8534029fc493c06b8c3a Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 10 Feb 2025 11:31:18 +0100 Subject: [PATCH 29/35] fix java version parsing --- .../runtimemetrics/RuntimeMetricsAutoConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java index 86e4b6adb4c5..70d33ede5185 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java @@ -62,7 +62,7 @@ public void handleApplicationReadyEvent(ApplicationReadyEvent event) { } } - private int javaVersion() { + private static int javaVersion() { try { return Integer.parseInt(System.getProperty("java.specification.version")); } catch (NumberFormatException nfe) { From 1eea5d3f7820443e83ed76e1c3b7cf4183e69e41 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 10 Feb 2025 13:05:30 +0100 Subject: [PATCH 30/35] Update instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/Threads.java Co-authored-by: Jean Bisutti --- .../instrumentation/runtimemetrics/java8/Threads.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/Threads.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/Threads.java index 2b720ab813bd..204eff083329 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/Threads.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/Threads.java @@ -119,7 +119,8 @@ private static boolean isJava9OrNewer() { private static boolean useThreads() { // GraalVM native image does not support ThreadMXBean yet // see https://github.com/oracle/graal/issues/6101 - return !isJava9OrNewer() || System.getProperty("org.graalvm.nativeimage.imagecode") != null; + boolean isNativeExecution = System.getProperty("org.graalvm.nativeimage.imagecode") != null; + return !isJava9OrNewer() || isNativeExecution; } private static Consumer java8Callback(ThreadMXBean threadBean) { From 59c14253d65b4e369b8fd1f4e5f98c5383c7a4da Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 10 Feb 2025 13:10:44 +0100 Subject: [PATCH 31/35] cleanup --- .../RuntimeMetricsBeanRegistrationExcludeFilter.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java index 6909a362e2bd..e6b98f3fa675 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/javaSpring3/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsBeanRegistrationExcludeFilter.java @@ -20,7 +20,6 @@ public boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) { // The JFR-based runtime metric code is excluded from the Spring AOT processing step. // That way, this code is not included in a Spring native image application. - return "io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java17RuntimeMetricsProvider" - .equals(registeredBean.getBeanName()); + return Java17RuntimeMetricsProvider.class.getName().equals(registeredBean.getBeanName()); } } From 53a3e6ac54468b342f489079c486e0a3876e494f Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 10 Feb 2025 14:11:14 +0100 Subject: [PATCH 32/35] cleanup --- .../internal/JmxRuntimeMetricsFactory.java | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/internal/JmxRuntimeMetricsFactory.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/internal/JmxRuntimeMetricsFactory.java index 405fbb48c80e..2cb1b55b3d72 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/internal/JmxRuntimeMetricsFactory.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/internal/JmxRuntimeMetricsFactory.java @@ -22,23 +22,19 @@ public class JmxRuntimeMetricsFactory { @SuppressWarnings("CatchingUnchecked") public static List buildObservables( OpenTelemetry openTelemetry, boolean enableExperimentalJmxTelemetry) { - try { - // Set up metrics gathered by JMX - List observables = new ArrayList<>(); - observables.addAll(Classes.registerObservers(openTelemetry)); - observables.addAll(Cpu.registerObservers(openTelemetry)); - observables.addAll(GarbageCollector.registerObservers(openTelemetry)); - observables.addAll(MemoryPools.registerObservers(openTelemetry)); - observables.addAll(Threads.registerObservers(openTelemetry)); - if (enableExperimentalJmxTelemetry) { - observables.addAll(ExperimentalBufferPools.registerObservers(openTelemetry)); - observables.addAll(ExperimentalCpu.registerObservers(openTelemetry)); - observables.addAll(ExperimentalMemoryPools.registerObservers(openTelemetry)); - } - return observables; - } catch (Exception e) { - throw new IllegalStateException("Error building RuntimeMetrics", e); + // Set up metrics gathered by JMX + List observables = new ArrayList<>(); + observables.addAll(Classes.registerObservers(openTelemetry)); + observables.addAll(Cpu.registerObservers(openTelemetry)); + observables.addAll(GarbageCollector.registerObservers(openTelemetry)); + observables.addAll(MemoryPools.registerObservers(openTelemetry)); + observables.addAll(Threads.registerObservers(openTelemetry)); + if (enableExperimentalJmxTelemetry) { + observables.addAll(ExperimentalBufferPools.registerObservers(openTelemetry)); + observables.addAll(ExperimentalCpu.registerObservers(openTelemetry)); + observables.addAll(ExperimentalMemoryPools.registerObservers(openTelemetry)); } + return observables; } private JmxRuntimeMetricsFactory() {} From 6a1e1b2bbc1d29ef5b3b8dd2da83b7a40f5296e2 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 14 Feb 2025 13:20:17 +0100 Subject: [PATCH 33/35] pr review --- .../java17/Java17RuntimeMetricsInstaller.java | 11 ++++- .../java17/RuntimeMetricsBuilder.java | 42 ---------------- .../internal/RuntimeMetricsConfigUtil.java | 48 +++++++++++++++++++ .../java8/Java8RuntimeMetricsInstaller.java | 11 ++++- .../java8/RuntimeMetricsBuilder.java | 30 ------------ .../internal/RuntimeMetricsConfigUtil.java | 36 ++++++++++++++ .../Java17RuntimeMetricsProvider.java | 9 ++-- .../Java8RuntimeMetricsProvider.java | 9 ++-- 8 files changed, 114 insertions(+), 82 deletions(-) create mode 100644 instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/internal/RuntimeMetricsConfigUtil.java create mode 100644 instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/internal/RuntimeMetricsConfigUtil.java 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 10a535f8d393..e4286d0e7148 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 @@ -8,6 +8,7 @@ import com.google.auto.service.AutoService; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics; +import io.opentelemetry.instrumentation.runtimemetrics.java17.internal.RuntimeMetricsConfigUtil; import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; import io.opentelemetry.javaagent.extension.AgentListener; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; @@ -18,7 +19,13 @@ public class Java17RuntimeMetricsInstaller implements AgentListener { @Override public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { - RuntimeMetrics.builder(GlobalOpenTelemetry.get()) - .startFromInstrumentationConfig(AgentInstrumentationConfig.get()); + RuntimeMetrics runtimeMetrics = + RuntimeMetricsConfigUtil.configure( + RuntimeMetrics.builder(GlobalOpenTelemetry.get()), AgentInstrumentationConfig.get()); + if (runtimeMetrics != null) { + Runtime.getRuntime() + .addShutdownHook( + new Thread(runtimeMetrics::close, "OpenTelemetry RuntimeMetricsShutdownHook")); + } } } diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java index c6886403f01f..103a3efef6ca 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetricsBuilder.java @@ -7,12 +7,10 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.JmxRuntimeMetricsFactory; import java.util.Arrays; import java.util.EnumMap; import java.util.List; -import java.util.function.Consumer; import javax.annotation.Nullable; /** Builder for {@link RuntimeMetrics}. */ @@ -24,11 +22,6 @@ public final class RuntimeMetricsBuilder { private boolean disableJmx = false; private boolean enableExperimentalJmxTelemetry = false; - private Consumer shutdownHook = - runnable -> { - Runtime.getRuntime() - .addShutdownHook(new Thread(runnable, "OpenTelemetry RuntimeMetricsShutdownHook")); - }; RuntimeMetricsBuilder(OpenTelemetry openTelemetry) { this.openTelemetry = openTelemetry; @@ -88,41 +81,6 @@ public RuntimeMetricsBuilder enableExperimentalJmxTelemetry() { return this; } - /** Set a custom shutdown hook for the {@link RuntimeMetrics}. */ - @CanIgnoreReturnValue - public RuntimeMetricsBuilder setShutdownHook(Consumer shutdownHook) { - this.shutdownHook = shutdownHook; - return this; - } - - public void startFromInstrumentationConfig(InstrumentationConfig config) { - /* - By default, don't use any JFR metrics. May change this once semantic conventions are updated. - If enabled, default to only the metrics not already covered by runtime-telemetry-java8 - */ - boolean defaultEnabled = config.getBoolean("otel.instrumentation.common.default-enabled", true); - if (config.getBoolean("otel.instrumentation.runtime-telemetry-java17.enable-all", false)) { - this.enableAllFeatures(); - } else if (config.getBoolean("otel.instrumentation.runtime-telemetry-java17.enabled", false)) { - // default configuration - } else if (config.getBoolean( - "otel.instrumentation.runtime-telemetry.enabled", defaultEnabled)) { - // This only uses metrics gathered by JMX - this.disableAllFeatures(); - } else { - // nothing is enabled - return; - } - - if (config.getBoolean( - "otel.instrumentation.runtime-telemetry.emit-experimental-telemetry", false)) { - this.enableExperimentalJmxTelemetry(); - } - - RuntimeMetrics runtimeMetrics = this.build(); - shutdownHook.accept(runtimeMetrics::close); - } - /** Build and start an {@link RuntimeMetrics} with the config from this builder. */ public RuntimeMetrics build() { List observables = diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/internal/RuntimeMetricsConfigUtil.java b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/internal/RuntimeMetricsConfigUtil.java new file mode 100644 index 000000000000..f8ec8a57e05b --- /dev/null +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/internal/RuntimeMetricsConfigUtil.java @@ -0,0 +1,48 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.java17.internal; + +import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; +import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics; +import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetricsBuilder; +import javax.annotation.Nullable; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public final class RuntimeMetricsConfigUtil { + private RuntimeMetricsConfigUtil() {} + + @Nullable + public static RuntimeMetrics configure( + RuntimeMetricsBuilder builder, InstrumentationConfig config) { + /* + By default, don't use any JFR metrics. May change this once semantic conventions are updated. + If enabled, default to only the metrics not already covered by runtime-telemetry-java8 + */ + boolean defaultEnabled = config.getBoolean("otel.instrumentation.common.default-enabled", true); + if (config.getBoolean("otel.instrumentation.runtime-telemetry-java17.enable-all", false)) { + builder.enableAllFeatures(); + } else if (config.getBoolean("otel.instrumentation.runtime-telemetry-java17.enabled", false)) { + // default configuration + } else if (config.getBoolean( + "otel.instrumentation.runtime-telemetry.enabled", defaultEnabled)) { + // This only uses metrics gathered by JMX + builder.disableAllFeatures(); + } else { + // nothing is enabled + return null; + } + + if (config.getBoolean( + "otel.instrumentation.runtime-telemetry.emit-experimental-telemetry", false)) { + builder.enableExperimentalJmxTelemetry(); + } + + return builder.build(); + } +} 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 57a569a976dc..4af7dd610896 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 @@ -8,6 +8,7 @@ import com.google.auto.service.AutoService; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.instrumentation.runtimemetrics.java8.RuntimeMetrics; +import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.RuntimeMetricsConfigUtil; import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; import io.opentelemetry.javaagent.extension.AgentListener; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; @@ -18,7 +19,13 @@ public class Java8RuntimeMetricsInstaller implements AgentListener { @Override public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) { - RuntimeMetrics.builder(GlobalOpenTelemetry.get()) - .startFromInstrumentationConfig(AgentInstrumentationConfig.get()); + RuntimeMetrics runtimeMetrics = + RuntimeMetricsConfigUtil.configure( + RuntimeMetrics.builder(GlobalOpenTelemetry.get()), AgentInstrumentationConfig.get()); + if (runtimeMetrics != null) { + Runtime.getRuntime() + .addShutdownHook( + new Thread(runtimeMetrics::close, "OpenTelemetry RuntimeMetricsShutdownHook")); + } } } diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java index 584c68433e1b..e342626ac377 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetricsBuilder.java @@ -7,10 +7,8 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.JmxRuntimeMetricsFactory; import java.util.List; -import java.util.function.Consumer; /** Builder for {@link RuntimeMetrics}. */ public final class RuntimeMetricsBuilder { @@ -18,11 +16,6 @@ public final class RuntimeMetricsBuilder { private final OpenTelemetry openTelemetry; private boolean enableExperimentalJmxTelemetry = false; - private Consumer shutdownHook = - runnable -> { - Runtime.getRuntime() - .addShutdownHook(new Thread(runnable, "OpenTelemetry RuntimeMetricsShutdownHook")); - }; RuntimeMetricsBuilder(OpenTelemetry openTelemetry) { this.openTelemetry = openTelemetry; @@ -41,27 +34,4 @@ public RuntimeMetrics build() { JmxRuntimeMetricsFactory.buildObservables(openTelemetry, enableExperimentalJmxTelemetry); return new RuntimeMetrics(observables); } - - /** Set a custom shutdown hook for the {@link RuntimeMetrics}. */ - @CanIgnoreReturnValue - public RuntimeMetricsBuilder setShutdownHook(Consumer shutdownHook) { - this.shutdownHook = shutdownHook; - return this; - } - - public void startFromInstrumentationConfig(InstrumentationConfig config) { - boolean defaultEnabled = config.getBoolean("otel.instrumentation.common.default-enabled", true); - if (!config.getBoolean("otel.instrumentation.runtime-telemetry.enabled", defaultEnabled)) { - // nothing is enabled - return; - } - - if (config.getBoolean( - "otel.instrumentation.runtime-telemetry.emit-experimental-telemetry", false)) { - this.enableExperimentalJmxTelemetry(); - } - - RuntimeMetrics runtimeMetrics = this.build(); - shutdownHook.accept(runtimeMetrics::close); - } } diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/internal/RuntimeMetricsConfigUtil.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/internal/RuntimeMetricsConfigUtil.java new file mode 100644 index 000000000000..f0059cf7f9d3 --- /dev/null +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/internal/RuntimeMetricsConfigUtil.java @@ -0,0 +1,36 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics.java8.internal; + +import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; +import io.opentelemetry.instrumentation.runtimemetrics.java8.RuntimeMetrics; +import io.opentelemetry.instrumentation.runtimemetrics.java8.RuntimeMetricsBuilder; +import javax.annotation.Nullable; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public final class RuntimeMetricsConfigUtil { + private RuntimeMetricsConfigUtil() {} + + @Nullable + public static RuntimeMetrics configure( + RuntimeMetricsBuilder builder, InstrumentationConfig config) { + boolean defaultEnabled = config.getBoolean("otel.instrumentation.common.default-enabled", true); + if (!config.getBoolean("otel.instrumentation.runtime-telemetry.enabled", defaultEnabled)) { + // nothing is enabled + return null; + } + + if (config.getBoolean( + "otel.instrumentation.runtime-telemetry.emit-experimental-telemetry", false)) { + builder.enableExperimentalJmxTelemetry(); + } + + return builder.build(); + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsProvider.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsProvider.java index 3ea023b00ae3..7c6106c0e222 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsProvider.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsProvider.java @@ -8,6 +8,7 @@ import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics; +import io.opentelemetry.instrumentation.runtimemetrics.java17.internal.RuntimeMetricsConfigUtil; import java.util.function.Consumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,8 +31,10 @@ public int minJavaVersion() { public void start( OpenTelemetry openTelemetry, Consumer shutdownHook, InstrumentationConfig config) { logger.debug("Use runtime metrics instrumentation for Java 17+"); - RuntimeMetrics.builder(openTelemetry) - .setShutdownHook(shutdownHook) - .startFromInstrumentationConfig(config); + RuntimeMetrics runtimeMetrics = + RuntimeMetricsConfigUtil.configure(RuntimeMetrics.builder(openTelemetry), config); + if (runtimeMetrics != null) { + shutdownHook.accept(runtimeMetrics::close); + } } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java index bd3ada26461e..d32e3cb74e03 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java @@ -8,6 +8,7 @@ import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.instrumentation.runtimemetrics.java8.RuntimeMetrics; +import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.RuntimeMetricsConfigUtil; import java.util.function.Consumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,8 +31,10 @@ public int minJavaVersion() { public void start( OpenTelemetry openTelemetry, Consumer shutdownHook, InstrumentationConfig config) { logger.debug("Use runtime metrics instrumentation for Java 8"); - RuntimeMetrics.builder(openTelemetry) - .setShutdownHook(shutdownHook) - .startFromInstrumentationConfig(config); + RuntimeMetrics runtimeMetrics = + RuntimeMetricsConfigUtil.configure(RuntimeMetrics.builder(openTelemetry), config); + if (runtimeMetrics != null) { + shutdownHook.accept(runtimeMetrics::close); + } } } From 3c108245a5465c4aaa812c58768d8182a57d6747 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 14 Feb 2025 14:24:42 +0100 Subject: [PATCH 34/35] pr review --- .../runtimemetrics/Java8RuntimeMetricsProvider.java | 2 +- .../RuntimeMetricsAutoConfiguration.java | 11 +---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java index d32e3cb74e03..f655b59df229 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java @@ -24,7 +24,7 @@ public class Java8RuntimeMetricsProvider implements RuntimeMetricsProvider { @Override public int minJavaVersion() { - return 8; + return 1; } @Override diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java index 70d33ede5185..c3526c5fee5c 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java @@ -48,7 +48,7 @@ public void handleApplicationReadyEvent(ApplicationReadyEvent event) { ConfigPropertiesBridge config = new ConfigPropertiesBridge(applicationContext.getBean(ConfigProperties.class)); - double version = javaVersion(); + double version = Double.parseDouble(System.getProperty("java.specification.version")); Optional metricsProvider = applicationContext.getBeanProvider(RuntimeMetricsProvider.class).stream() .sorted(Comparator.comparing(RuntimeMetricsProvider::minJavaVersion).reversed()) @@ -61,13 +61,4 @@ public void handleApplicationReadyEvent(ApplicationReadyEvent event) { logger.debug("No runtime metrics instrumentation available for Java {}", version); } } - - private static int javaVersion() { - try { - return Integer.parseInt(System.getProperty("java.specification.version")); - } catch (NumberFormatException nfe) { - // The value of the java.specification.version property is 1.8 with a Java 8 runtime. - return 8; - } - } } From 838af2e82da5c8b2fedab2090e6fd5a8ebe9a8ac Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 14 Feb 2025 14:40:21 +0100 Subject: [PATCH 35/35] pr review --- .../runtimemetrics/java17/RuntimeMetrics.java | 2 +- .../runtimemetrics/java8/RuntimeMetrics.java | 3 +-- .../Java17RuntimeMetricsProvider.java | 10 ++-------- .../runtimemetrics/Java8RuntimeMetricsProvider.java | 12 +++--------- .../RuntimeMetricsAutoConfiguration.java | 13 +++++++------ .../runtimemetrics/RuntimeMetricsProvider.java | 6 +++--- 6 files changed, 17 insertions(+), 29 deletions(-) diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java index aabe280576cb..42c175d2df4c 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java17/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java17/RuntimeMetrics.java @@ -21,7 +21,7 @@ import jdk.jfr.consumer.RecordingStream; /** The entry point class for runtime metrics support using JFR and JMX. */ -public final class RuntimeMetrics implements Closeable { +public final class RuntimeMetrics implements AutoCloseable { private static final Logger logger = Logger.getLogger(RuntimeMetrics.class.getName()); diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetrics.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetrics.java index dec3beac8685..62e711ebd9aa 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetrics.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/java8/RuntimeMetrics.java @@ -7,7 +7,6 @@ import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.JmxRuntimeMetricsUtil; -import java.io.Closeable; import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -15,7 +14,7 @@ import java.util.logging.Logger; /** The entry point class for runtime metrics support using JMX. */ -public final class RuntimeMetrics implements Closeable { +public final class RuntimeMetrics implements AutoCloseable { private static final Logger logger = Logger.getLogger(RuntimeMetrics.class.getName()); diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsProvider.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsProvider.java index 7c6106c0e222..8f258004a853 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsProvider.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java17RuntimeMetricsProvider.java @@ -9,7 +9,6 @@ import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics; import io.opentelemetry.instrumentation.runtimemetrics.java17.internal.RuntimeMetricsConfigUtil; -import java.util.function.Consumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,13 +27,8 @@ public int minJavaVersion() { } @Override - public void start( - OpenTelemetry openTelemetry, Consumer shutdownHook, InstrumentationConfig config) { + public AutoCloseable start(OpenTelemetry openTelemetry, InstrumentationConfig config) { logger.debug("Use runtime metrics instrumentation for Java 17+"); - RuntimeMetrics runtimeMetrics = - RuntimeMetricsConfigUtil.configure(RuntimeMetrics.builder(openTelemetry), config); - if (runtimeMetrics != null) { - shutdownHook.accept(runtimeMetrics::close); - } + return RuntimeMetricsConfigUtil.configure(RuntimeMetrics.builder(openTelemetry), config); } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java index f655b59df229..fbb10d9e935b 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/Java8RuntimeMetricsProvider.java @@ -9,7 +9,6 @@ import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; import io.opentelemetry.instrumentation.runtimemetrics.java8.RuntimeMetrics; import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.RuntimeMetricsConfigUtil; -import java.util.function.Consumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,17 +23,12 @@ public class Java8RuntimeMetricsProvider implements RuntimeMetricsProvider { @Override public int minJavaVersion() { - return 1; + return 8; } @Override - public void start( - OpenTelemetry openTelemetry, Consumer shutdownHook, InstrumentationConfig config) { + public AutoCloseable start(OpenTelemetry openTelemetry, InstrumentationConfig config) { logger.debug("Use runtime metrics instrumentation for Java 8"); - RuntimeMetrics runtimeMetrics = - RuntimeMetricsConfigUtil.configure(RuntimeMetrics.builder(openTelemetry), config); - if (runtimeMetrics != null) { - shutdownHook.accept(runtimeMetrics::close); - } + return RuntimeMetricsConfigUtil.configure(RuntimeMetrics.builder(openTelemetry), config); } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java index c3526c5fee5c..f58f4da5f217 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsAutoConfiguration.java @@ -32,12 +32,12 @@ public class RuntimeMetricsAutoConfiguration { private static final Logger logger = LoggerFactory.getLogger(RuntimeMetricsAutoConfiguration.class); - private Runnable shutdownHook; + private AutoCloseable closeable; @PreDestroy - public void stopMetrics() { - if (shutdownHook != null) { - shutdownHook.run(); + public void stopMetrics() throws Exception { + if (closeable != null) { + closeable.close(); } } @@ -48,7 +48,8 @@ public void handleApplicationReadyEvent(ApplicationReadyEvent event) { ConfigPropertiesBridge config = new ConfigPropertiesBridge(applicationContext.getBean(ConfigProperties.class)); - double version = Double.parseDouble(System.getProperty("java.specification.version")); + double version = + Math.max(8, Double.parseDouble(System.getProperty("java.specification.version"))); Optional metricsProvider = applicationContext.getBeanProvider(RuntimeMetricsProvider.class).stream() .sorted(Comparator.comparing(RuntimeMetricsProvider::minJavaVersion).reversed()) @@ -56,7 +57,7 @@ public void handleApplicationReadyEvent(ApplicationReadyEvent event) { .findFirst(); if (metricsProvider.isPresent()) { - metricsProvider.get().start(openTelemetry, runnable -> shutdownHook = runnable, config); + this.closeable = metricsProvider.get().start(openTelemetry, config); } else { logger.debug("No runtime metrics instrumentation available for Java {}", version); } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsProvider.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsProvider.java index 553a0a2e5273..8549f9394e61 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsProvider.java +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/runtimemetrics/RuntimeMetricsProvider.java @@ -7,7 +7,7 @@ import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig; -import java.util.function.Consumer; +import javax.annotation.Nullable; /** * Configures runtime metrics collection. @@ -18,6 +18,6 @@ public interface RuntimeMetricsProvider { int minJavaVersion(); - void start( - OpenTelemetry openTelemetry, Consumer shutdownHook, InstrumentationConfig config); + @Nullable + AutoCloseable start(OpenTelemetry openTelemetry, InstrumentationConfig config); }