Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions instrumentation/runtime-telemetry/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
| `otel.instrumentation.runtime-telemetry.emit-experimental-telemetry` | Boolean | `false` | Enable the capture of experimental metrics. |
| `otel.instrumentation.runtime-telemetry-java17.enable-all` | Boolean | `false` | Enable the capture of all JFR based metrics. |
| `otel.instrumentation.runtime-telemetry-java17.enabled` | Boolean | `false` | Enable the capture of JFR based metrics. |
| `otel.instrumentation.runtime-telemetry.jvm-gc-cause-attribute-enabled` | Boolean | `false` | Enable the capture of the jvm.gc.cause attribute within the jvm.gc.duration metric.
| `otel.instrumentation.runtime-telemetry.package-emitter.enabled` | Boolean | `false` | Enable creating events for JAR libraries used by the application. |
| `otel.instrumentation.runtime-telemetry.package-emitter.jars-per-second` | Integer | 10 | The number of JAR files processed per second. |
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@

import com.sun.management.GarbageCollectionNotificationInfo;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil;
import io.opentelemetry.instrumentation.runtimemetrics.java8.internal.JmxRuntimeMetricsUtil;
import io.opentelemetry.semconv.JvmAttributes;
import java.lang.management.GarbageCollectorMXBean;
Expand Down Expand Up @@ -125,11 +127,23 @@ public void handleNotification(Notification notification, Object unused) {

String gcName = notificationInfo.getGcName();
String gcAction = notificationInfo.getGcAction();
String gcCause = notificationInfo.getGcCause();
double duration = notificationInfo.getGcInfo().getDuration() / MILLIS_PER_S;

gcDuration.record(
duration,
Attributes.of(JvmAttributes.JVM_GC_NAME, gcName, JvmAttributes.JVM_GC_ACTION, gcAction));
boolean enableJvmGcCauseAttribute =
ConfigPropertiesUtil.getBoolean(
"otel.instrumentation.runtime-telemetry.jvm-gc-cause-attribute-enabled", false);
Attributes gcAttributes =
enableJvmGcCauseAttribute
? Attributes.of(
JvmAttributes.JVM_GC_NAME,
gcName,
JvmAttributes.JVM_GC_ACTION,
gcAction,
AttributeKey.stringKey("jvm.gc.cause"),
gcCause)
: Attributes.of(
JvmAttributes.JVM_GC_NAME, gcName, JvmAttributes.JVM_GC_ACTION, gcAction);
gcDuration.record(duration, gcAttributes);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junitpioneer.jupiter.SetSystemProperty;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
Expand All @@ -48,6 +49,9 @@ class GarbageCollectorTest {

@Captor private ArgumentCaptor<NotificationListener> listenerCaptor;

@SetSystemProperty(
key = "otel.instrumentation.runtime-telemetry.jvm-gc-cause-attribute-enabled",
value = "true")
@Test
void registerObservers() {
GarbageCollector.registerObservers(
Expand All @@ -60,11 +64,13 @@ void registerObservers() {
NotificationListener listener = listenerCaptor.getValue();

listener.handleNotification(
createTestNotification("G1 Young Generation", "end of minor GC", 10), null);
createTestNotification("G1 Young Generation", "end of minor GC", "Allocation Failure", 10),
null);
listener.handleNotification(
createTestNotification("G1 Young Generation", "end of minor GC", 12), null);
createTestNotification("G1 Young Generation", "end of minor GC", "Allocation Failure", 12),
null);
listener.handleNotification(
createTestNotification("G1 Old Generation", "end of major GC", 11), null);
createTestNotification("G1 Old Generation", "end of major GC", "System.gc()", 11), null);

testing.waitAndAssertMetrics(
"io.opentelemetry.runtime-telemetry-java8",
Expand All @@ -87,6 +93,7 @@ void registerObservers() {
Attributes.builder()
.put("jvm.gc.name", "G1 Young Generation")
.put("jvm.gc.action", "end of minor GC")
.put("jvm.gc.cause", "Allocation Failure")
.build())
.hasBucketBoundaries(GC_DURATION_BUCKETS),
point ->
Expand All @@ -97,16 +104,18 @@ void registerObservers() {
Attributes.builder()
.put("jvm.gc.name", "G1 Old Generation")
.put("jvm.gc.action", "end of major GC")
.put("jvm.gc.cause", "System.gc()")
.build())
.hasBucketBoundaries(GC_DURATION_BUCKETS)))));
}

private static Notification createTestNotification(
String gcName, String gcAction, long duration) {
String gcName, String gcAction, String gcCause, long duration) {
GarbageCollectionNotificationInfo gcNotificationInfo =
mock(GarbageCollectionNotificationInfo.class);
when(gcNotificationInfo.getGcName()).thenReturn(gcName);
when(gcNotificationInfo.getGcAction()).thenReturn(gcAction);
when(gcNotificationInfo.getGcCause()).thenReturn(gcCause);
GcInfo gcInfo = mock(GcInfo.class);
when(gcInfo.getDuration()).thenReturn(duration);
when(gcNotificationInfo.getGcInfo()).thenReturn(gcInfo);
Expand Down
Loading