Spring boot runtime metrics native reduced (#13173)
Co-authored-by: Jean Bisutti <jean.bisutti@gmail.com>
This commit is contained in:
parent
0e2cc4f81e
commit
9101f0300f
|
@ -1,2 +1,4 @@
|
||||||
Args=\
|
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.instrumentation.api.internal.cache.MapBackedCache \
|
||||||
|
--initialize-at-build-time=io.opentelemetry.api.internal.InternalAttributeKeyImpl
|
||||||
|
|
|
@ -7,12 +7,11 @@ package io.opentelemetry.instrumentation.javaagent.runtimemetrics.java17;
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||||
import io.opentelemetry.api.OpenTelemetry;
|
|
||||||
import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics;
|
import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetrics;
|
||||||
import io.opentelemetry.instrumentation.runtimemetrics.java17.RuntimeMetricsBuilder;
|
import io.opentelemetry.instrumentation.runtimemetrics.java17.internal.RuntimeMetricsConfigUtil;
|
||||||
|
import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig;
|
||||||
import io.opentelemetry.javaagent.extension.AgentListener;
|
import io.opentelemetry.javaagent.extension.AgentListener;
|
||||||
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
|
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
|
||||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
|
||||||
|
|
||||||
/** An {@link AgentListener} that enables runtime metrics during agent startup. */
|
/** An {@link AgentListener} that enables runtime metrics during agent startup. */
|
||||||
@AutoService(AgentListener.class)
|
@AutoService(AgentListener.class)
|
||||||
|
@ -20,34 +19,13 @@ public class Java17RuntimeMetricsInstaller implements AgentListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) {
|
public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) {
|
||||||
ConfigProperties config = AgentListener.resolveConfigProperties(autoConfiguredSdk);
|
RuntimeMetrics runtimeMetrics =
|
||||||
|
RuntimeMetricsConfigUtil.configure(
|
||||||
OpenTelemetry openTelemetry = GlobalOpenTelemetry.get();
|
RuntimeMetrics.builder(GlobalOpenTelemetry.get()), AgentInstrumentationConfig.get());
|
||||||
RuntimeMetricsBuilder builder = null;
|
if (runtimeMetrics != null) {
|
||||||
/*
|
Runtime.getRuntime()
|
||||||
By default don't use any JFR metrics. May change this once semantic conventions are updated.
|
.addShutdownHook(
|
||||||
If enabled, default to only the metrics not already covered by runtime-telemetry-java8
|
new Thread(runtimeMetrics::close, "OpenTelemetry RuntimeMetricsShutdownHook"));
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ import jdk.jfr.FlightRecorder;
|
||||||
import jdk.jfr.consumer.RecordingStream;
|
import jdk.jfr.consumer.RecordingStream;
|
||||||
|
|
||||||
/** The entry point class for runtime metrics support using JFR and JMX. */
|
/** 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());
|
private static final Logger logger = Logger.getLogger(RuntimeMetrics.class.getName());
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ public final class RuntimeMetrics implements Closeable {
|
||||||
recordingStream.onEvent(handler.getEventName(), handler);
|
recordingStream.onEvent(handler.getEventName(), handler);
|
||||||
});
|
});
|
||||||
recordingStream.onMetadata(event -> startUpLatch.countDown());
|
recordingStream.onMetadata(event -> startUpLatch.countDown());
|
||||||
Thread daemonRunner = new Thread(() -> recordingStream.start());
|
Thread daemonRunner = new Thread(recordingStream::start, "OpenTelemetry JFR-Metrics-Runner");
|
||||||
daemonRunner.setDaemon(true);
|
daemonRunner.setDaemon(true);
|
||||||
daemonRunner.start();
|
daemonRunner.start();
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,8 @@ public final class RuntimeMetrics implements Closeable {
|
||||||
private static boolean isJfrAvailable() {
|
private static boolean isJfrAvailable() {
|
||||||
try {
|
try {
|
||||||
Class.forName("jdk.jfr.FlightRecorder");
|
Class.forName("jdk.jfr.FlightRecorder");
|
||||||
} catch (ClassNotFoundException e) {
|
// UnsatisfiedLinkError or ClassNotFoundException
|
||||||
|
} catch (Exception e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,17 +7,8 @@ package io.opentelemetry.instrumentation.runtimemetrics.java17;
|
||||||
|
|
||||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
import io.opentelemetry.api.OpenTelemetry;
|
import io.opentelemetry.api.OpenTelemetry;
|
||||||
import io.opentelemetry.instrumentation.runtimemetrics.java8.Classes;
|
import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.JmxRuntimeMetricsFactory;
|
||||||
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 java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -83,7 +74,7 @@ public final class RuntimeMetricsBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Disable telemetry collection associated with the {@link JfrFeature}. */
|
/** Enable experimental JMX telemetry collection. */
|
||||||
@CanIgnoreReturnValue
|
@CanIgnoreReturnValue
|
||||||
public RuntimeMetricsBuilder enableExperimentalJmxTelemetry() {
|
public RuntimeMetricsBuilder enableExperimentalJmxTelemetry() {
|
||||||
enableExperimentalJmxTelemetry = true;
|
enableExperimentalJmxTelemetry = true;
|
||||||
|
@ -92,35 +83,15 @@ public final class RuntimeMetricsBuilder {
|
||||||
|
|
||||||
/** Build and start an {@link RuntimeMetrics} with the config from this builder. */
|
/** Build and start an {@link RuntimeMetrics} with the config from this builder. */
|
||||||
public RuntimeMetrics build() {
|
public RuntimeMetrics build() {
|
||||||
List<AutoCloseable> observables = buildObservables();
|
List<AutoCloseable> observables =
|
||||||
|
disableJmx
|
||||||
|
? List.of()
|
||||||
|
: JmxRuntimeMetricsFactory.buildObservables(
|
||||||
|
openTelemetry, enableExperimentalJmxTelemetry);
|
||||||
RuntimeMetrics.JfrRuntimeMetrics jfrRuntimeMetrics = buildJfrMetrics();
|
RuntimeMetrics.JfrRuntimeMetrics jfrRuntimeMetrics = buildJfrMetrics();
|
||||||
return new RuntimeMetrics(openTelemetry, observables, jfrRuntimeMetrics);
|
return new RuntimeMetrics(openTelemetry, observables, jfrRuntimeMetrics);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("CatchingUnchecked")
|
|
||||||
private List<AutoCloseable> buildObservables() {
|
|
||||||
if (disableJmx) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// Set up metrics gathered by JMX
|
|
||||||
List<AutoCloseable> 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
|
@Nullable
|
||||||
private RuntimeMetrics.JfrRuntimeMetrics buildJfrMetrics() {
|
private RuntimeMetrics.JfrRuntimeMetrics buildJfrMetrics() {
|
||||||
if (enabledFeatureMap.values().stream().noneMatch(isEnabled -> isEnabled)) {
|
if (enabledFeatureMap.values().stream().noneMatch(isEnabled -> isEnabled)) {
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,21 +7,11 @@ package io.opentelemetry.instrumentation.javaagent.runtimemetrics.java8;
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||||
import io.opentelemetry.api.OpenTelemetry;
|
import io.opentelemetry.instrumentation.runtimemetrics.java8.RuntimeMetrics;
|
||||||
import io.opentelemetry.instrumentation.runtimemetrics.java8.Classes;
|
import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.RuntimeMetricsConfigUtil;
|
||||||
import io.opentelemetry.instrumentation.runtimemetrics.java8.Cpu;
|
import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig;
|
||||||
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.javaagent.extension.AgentListener;
|
import io.opentelemetry.javaagent.extension.AgentListener;
|
||||||
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
|
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. */
|
/** An {@link AgentListener} that enables runtime metrics during agent startup. */
|
||||||
@AutoService(AgentListener.class)
|
@AutoService(AgentListener.class)
|
||||||
|
@ -29,30 +19,13 @@ public class Java8RuntimeMetricsInstaller implements AgentListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) {
|
public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) {
|
||||||
ConfigProperties config = AgentListener.resolveConfigProperties(autoConfiguredSdk);
|
RuntimeMetrics runtimeMetrics =
|
||||||
|
RuntimeMetricsConfigUtil.configure(
|
||||||
boolean defaultEnabled = config.getBoolean("otel.instrumentation.common.default-enabled", true);
|
RuntimeMetrics.builder(GlobalOpenTelemetry.get()), AgentInstrumentationConfig.get());
|
||||||
if (!config.getBoolean("otel.instrumentation.runtime-telemetry.enabled", defaultEnabled)
|
if (runtimeMetrics != null) {
|
||||||
|| Double.parseDouble(System.getProperty("java.specification.version")) >= 17) {
|
Runtime.getRuntime()
|
||||||
return;
|
.addShutdownHook(
|
||||||
|
new Thread(runtimeMetrics::close, "OpenTelemetry RuntimeMetricsShutdownHook"));
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenTelemetry openTelemetry = GlobalOpenTelemetry.get();
|
|
||||||
List<AutoCloseable> 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* 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.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 JMX. */
|
||||||
|
public final class RuntimeMetrics implements AutoCloseable {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(RuntimeMetrics.class.getName());
|
||||||
|
|
||||||
|
private final AtomicBoolean isClosed = new AtomicBoolean();
|
||||||
|
private final List<AutoCloseable> observables;
|
||||||
|
|
||||||
|
RuntimeMetrics(List<AutoCloseable> observables) {
|
||||||
|
this.observables = Collections.unmodifiableList(observables);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and start {@link RuntimeMetrics}.
|
||||||
|
*
|
||||||
|
* <p>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
|
||||||
|
*/
|
||||||
|
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 JMX metrics. */
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
if (!isClosed.compareAndSet(false, true)) {
|
||||||
|
logger.log(Level.WARNING, "RuntimeMetrics is already closed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JmxRuntimeMetricsUtil.closeObservers(observables);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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.runtimemetrics.java8.internal.JmxRuntimeMetricsFactory;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** Builder for {@link RuntimeMetrics}. */
|
||||||
|
public final class RuntimeMetricsBuilder {
|
||||||
|
|
||||||
|
private final OpenTelemetry openTelemetry;
|
||||||
|
|
||||||
|
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<AutoCloseable> observables =
|
||||||
|
JmxRuntimeMetricsFactory.buildObservables(openTelemetry, enableExperimentalJmxTelemetry);
|
||||||
|
return new RuntimeMetrics(observables);
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,7 +57,7 @@ public final class Threads {
|
||||||
|
|
||||||
/** Register observers for java runtime class metrics. */
|
/** Register observers for java runtime class metrics. */
|
||||||
public static List<AutoCloseable> registerObservers(OpenTelemetry openTelemetry) {
|
public static List<AutoCloseable> registerObservers(OpenTelemetry openTelemetry) {
|
||||||
return INSTANCE.registerObservers(openTelemetry, !isJava9OrNewer());
|
return INSTANCE.registerObservers(openTelemetry, useThreads());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<AutoCloseable> registerObservers(OpenTelemetry openTelemetry, boolean useThread) {
|
private List<AutoCloseable> registerObservers(OpenTelemetry openTelemetry, boolean useThread) {
|
||||||
|
@ -116,6 +116,13 @@ public final class Threads {
|
||||||
return THREAD_INFO_IS_DAEMON != null;
|
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
|
||||||
|
boolean isNativeExecution = System.getProperty("org.graalvm.nativeimage.imagecode") != null;
|
||||||
|
return !isJava9OrNewer() || isNativeExecution;
|
||||||
|
}
|
||||||
|
|
||||||
private static Consumer<ObservableLongMeasurement> java8Callback(ThreadMXBean threadBean) {
|
private static Consumer<ObservableLongMeasurement> java8Callback(ThreadMXBean threadBean) {
|
||||||
return measurement -> {
|
return measurement -> {
|
||||||
int daemonThreadCount = threadBean.getDaemonThreadCount();
|
int daemonThreadCount = threadBean.getDaemonThreadCount();
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* 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.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<AutoCloseable> buildObservables(
|
||||||
|
OpenTelemetry openTelemetry, boolean enableExperimentalJmxTelemetry) {
|
||||||
|
// Set up metrics gathered by JMX
|
||||||
|
List<AutoCloseable> 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() {}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "com.sun.management.OperatingSystemMXBean",
|
||||||
|
"allPublicMethods": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "com.ibm.lang.management.OperatingSystemMXBean",
|
||||||
|
"allPublicMethods": true
|
||||||
|
}
|
||||||
|
]
|
|
@ -53,6 +53,8 @@ dependencies {
|
||||||
implementation(project(":instrumentation:logback:logback-mdc-1.0:library"))
|
implementation(project(":instrumentation:logback:logback-mdc-1.0:library"))
|
||||||
compileOnly("ch.qos.logback:logback-classic:1.0.0")
|
compileOnly("ch.qos.logback:logback-classic:1.0.0")
|
||||||
implementation(project(":instrumentation:jdbc:library"))
|
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")
|
library("org.springframework.kafka:spring-kafka:2.9.0")
|
||||||
library("org.springframework.boot:spring-boot-starter-actuator:$springBootVersion")
|
library("org.springframework.boot:spring-boot-starter-actuator:$springBootVersion")
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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 io.opentelemetry.instrumentation.runtimemetrics.java17.internal.RuntimeMetricsConfigUtil;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures runtime metrics collection for Java 17+.
|
||||||
|
*
|
||||||
|
* <p>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 AutoCloseable start(OpenTelemetry openTelemetry, InstrumentationConfig config) {
|
||||||
|
logger.debug("Use runtime metrics instrumentation for Java 17+");
|
||||||
|
return RuntimeMetricsConfigUtil.configure(RuntimeMetrics.builder(openTelemetry), config);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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.java8.RuntimeMetrics;
|
||||||
|
import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.RuntimeMetricsConfigUtil;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures runtime metrics collection for Java 8.
|
||||||
|
*
|
||||||
|
* <p>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 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AutoCloseable start(OpenTelemetry openTelemetry, InstrumentationConfig config) {
|
||||||
|
logger.debug("Use runtime metrics instrumentation for Java 8");
|
||||||
|
return RuntimeMetricsConfigUtil.configure(RuntimeMetrics.builder(openTelemetry), config);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* 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.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;
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* <p>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")
|
||||||
|
@Configuration
|
||||||
|
public class RuntimeMetricsAutoConfiguration {
|
||||||
|
|
||||||
|
private static final Logger logger =
|
||||||
|
LoggerFactory.getLogger(RuntimeMetricsAutoConfiguration.class);
|
||||||
|
|
||||||
|
private AutoCloseable closeable;
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void stopMetrics() throws Exception {
|
||||||
|
if (closeable != null) {
|
||||||
|
closeable.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventListener
|
||||||
|
public void handleApplicationReadyEvent(ApplicationReadyEvent event) {
|
||||||
|
ConfigurableApplicationContext applicationContext = event.getApplicationContext();
|
||||||
|
OpenTelemetry openTelemetry = applicationContext.getBean(OpenTelemetry.class);
|
||||||
|
ConfigPropertiesBridge config =
|
||||||
|
new ConfigPropertiesBridge(applicationContext.getBean(ConfigProperties.class));
|
||||||
|
|
||||||
|
double version =
|
||||||
|
Math.max(8, Double.parseDouble(System.getProperty("java.specification.version")));
|
||||||
|
Optional<RuntimeMetricsProvider> metricsProvider =
|
||||||
|
applicationContext.getBeanProvider(RuntimeMetricsProvider.class).stream()
|
||||||
|
.sorted(Comparator.comparing(RuntimeMetricsProvider::minJavaVersion).reversed())
|
||||||
|
.filter(provider -> provider.minJavaVersion() <= version)
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (metricsProvider.isPresent()) {
|
||||||
|
this.closeable = metricsProvider.get().start(openTelemetry, config);
|
||||||
|
} else {
|
||||||
|
logger.debug("No runtime metrics instrumentation available for Java {}", version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* 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 javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures runtime metrics collection.
|
||||||
|
*
|
||||||
|
* <p>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();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
AutoCloseable start(OpenTelemetry openTelemetry, InstrumentationConfig config);
|
||||||
|
}
|
|
@ -13,7 +13,13 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
final class ConfigPropertiesBridge implements InstrumentationConfig {
|
/**
|
||||||
|
* Support for {@link ConfigProperties} in {@link InstrumentationConfig}.
|
||||||
|
*
|
||||||
|
* <p>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;
|
private final ConfigProperties configProperties;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
import org.springframework.beans.factory.support.RegisteredBean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures runtime metrics collection for Java 17+.
|
||||||
|
*
|
||||||
|
* <p>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) {
|
||||||
|
// 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 Java17RuntimeMetricsProvider.class.getName().equals(registeredBean.getBeanName());
|
||||||
|
}
|
||||||
|
}
|
|
@ -476,6 +476,30 @@
|
||||||
"description": "Enables the DB statement sanitization.",
|
"description": "Enables the DB statement sanitization.",
|
||||||
"defaultValue": true
|
"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",
|
"name": "otel.instrumentation.spring-web.enabled",
|
||||||
"type": "java.lang.Boolean",
|
"type": "java.lang.Boolean",
|
||||||
|
|
|
@ -10,7 +10,10 @@ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.r
|
||||||
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.web.SpringWebInstrumentationAutoConfiguration,\
|
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.webflux.SpringWebfluxInstrumentationAutoConfiguration,\
|
||||||
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.webmvc.SpringWebMvc5InstrumentationAutoConfiguration,\
|
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.RuntimeMetricsAutoConfiguration,\
|
||||||
|
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java8RuntimeMetricsProvider,\
|
||||||
|
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java17RuntimeMetricsProvider
|
||||||
|
|
||||||
org.springframework.context.ApplicationListener=\
|
org.springframework.context.ApplicationListener=\
|
||||||
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.logging.LogbackAppenderApplicationListener
|
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.logging.LogbackAppenderApplicationListener
|
||||||
|
|
|
@ -1,2 +1,5 @@
|
||||||
org.springframework.aot.hint.RuntimeHintsRegistrar=\
|
org.springframework.aot.hint.RuntimeHintsRegistrar=\
|
||||||
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.annotations.OpenTelemetryAnnotationsRuntimeHints
|
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.annotations.OpenTelemetryAnnotationsRuntimeHints
|
||||||
|
|
||||||
|
org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter=\
|
||||||
|
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.RuntimeMetricsBeanRegistrationExcludeFilter
|
||||||
|
|
|
@ -11,3 +11,6 @@ io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.w
|
||||||
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.web.RestClientInstrumentationAutoConfiguration
|
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.webmvc.SpringWebMvc6InstrumentationAutoConfiguration
|
||||||
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.RuntimeMetricsAutoConfiguration
|
||||||
|
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java8RuntimeMetricsProvider
|
||||||
|
io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.runtimemetrics.Java17RuntimeMetricsProvider
|
||||||
|
|
|
@ -16,6 +16,7 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||||
properties = {
|
properties = {
|
||||||
// The headers are simply set here to make sure that headers can be parsed
|
// 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 {}
|
class OtelSpringStarterSmokeTest extends AbstractOtelSpringStarterSmokeTest {}
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
package io.opentelemetry.spring.smoketest;
|
package io.opentelemetry.spring.smoketest;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.assertj.core.api.AbstractIterableAssert;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
@SpringBootTest(
|
@SpringBootTest(
|
||||||
|
@ -16,6 +18,36 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||||
properties = {
|
properties = {
|
||||||
// The headers are simply set here to make sure that headers can be parsed
|
// 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",
|
||||||
|
"otel.instrumentation.runtime-telemetry-java17.enable-all=true",
|
||||||
})
|
})
|
||||||
class OtelSpringStarterSmokeTest extends AbstractOtelSpringStarterSmokeTest {}
|
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(
|
||||||
|
"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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,8 @@ import io.opentelemetry.semconv.incubating.CodeIncubatingAttributes;
|
||||||
import io.opentelemetry.semconv.incubating.DbIncubatingAttributes;
|
import io.opentelemetry.semconv.incubating.DbIncubatingAttributes;
|
||||||
import io.opentelemetry.semconv.incubating.ServiceIncubatingAttributes;
|
import io.opentelemetry.semconv.incubating.ServiceIncubatingAttributes;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.assertj.core.api.AbstractCharSequenceAssert;
|
import org.assertj.core.api.AbstractCharSequenceAssert;
|
||||||
|
@ -210,10 +212,33 @@ class AbstractOtelSpringStarterSmokeTest extends AbstractSpringStarterSmokeTest
|
||||||
OtelSpringStarterSmokeTestController.TEST_HISTOGRAM,
|
OtelSpringStarterSmokeTestController.TEST_HISTOGRAM,
|
||||||
AbstractIterableAssert::isNotEmpty);
|
AbstractIterableAssert::isNotEmpty);
|
||||||
|
|
||||||
|
// JMX based metrics - test one per JMX bean
|
||||||
|
List<String> jmxMetrics =
|
||||||
|
new ArrayList<>(
|
||||||
|
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) {
|
||||||
|
// 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
|
// Log
|
||||||
List<LogRecordData> exportedLogRecords = testing.getExportedLogRecords();
|
List<LogRecordData> exportedLogRecords = testing.getExportedLogRecords();
|
||||||
assertThat(exportedLogRecords).as("No log record exported.").isNotEmpty();
|
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
|
// log records differ in native image mode due to different startup timing
|
||||||
LogRecordData firstLog = exportedLogRecords.get(0);
|
LogRecordData firstLog = exportedLogRecords.get(0);
|
||||||
assertThat(firstLog.getBodyValue().asString())
|
assertThat(firstLog.getBodyValue().asString())
|
||||||
|
@ -228,6 +253,8 @@ class AbstractOtelSpringStarterSmokeTest extends AbstractSpringStarterSmokeTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void assertAdditionalMetrics() {}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void databaseQuery() {
|
void databaseQuery() {
|
||||||
testing.clearAllExportedData();
|
testing.clearAllExportedData();
|
||||||
|
|
|
@ -15,8 +15,6 @@ import org.springframework.web.bind.annotation.RestController;
|
||||||
public class OtelSpringStarterSmokeTestController {
|
public class OtelSpringStarterSmokeTestController {
|
||||||
|
|
||||||
public static final String PING = "/ping";
|
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 TEST_HISTOGRAM = "histogram-test-otel-spring-starter";
|
||||||
public static final String METER_SCOPE_NAME = "scope";
|
public static final String METER_SCOPE_NAME = "scope";
|
||||||
private final LongHistogram histogram;
|
private final LongHistogram histogram;
|
||||||
|
|
Loading…
Reference in New Issue