From e3d15fc6113c8cf3ea3778a5ad73340cdbc2a6cc Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Thu, 21 Jul 2022 16:19:10 -0500 Subject: [PATCH] Gc time histogram --- .../instrumentation/runtimemetrics/Gc.java | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/Gc.java diff --git a/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/Gc.java b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/Gc.java new file mode 100644 index 000000000000..45eda9e4de5d --- /dev/null +++ b/instrumentation/runtime-metrics/library/src/main/java/io/opentelemetry/instrumentation/runtimemetrics/Gc.java @@ -0,0 +1,89 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.runtimemetrics; + +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.LongHistogram; +import io.opentelemetry.api.metrics.Meter; +import java.lang.management.GarbageCollectorMXBean; +import java.lang.management.ManagementFactory; +import java.util.List; +import javax.management.Notification; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.openmbean.CompositeData; + +public final class Gc { + + // Visible for testing + static final Gc INSTANCE = new Gc(); + + private static final AttributeKey GC_KEY = AttributeKey.stringKey("gc"); + private static final AttributeKey CAUSE_KEY = AttributeKey.stringKey("cause"); + private static final AttributeKey ACTION_KEY = AttributeKey.stringKey("action"); + + private static final NotificationFilter GC_FILTER = + notification -> + notification + .getType() + .equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION); + + public static void registerObservers(OpenTelemetry openTelemetry) { + INSTANCE.registerObservers(openTelemetry, ManagementFactory.getGarbageCollectorMXBeans()); + } + + // Visible for testing + void registerObservers(OpenTelemetry openTelemetry, List gcBeans) { + Meter meter = openTelemetry.getMeter("io.opentelemetry.runtime-metrics"); + + LongHistogram gcTime = + meter + .histogramBuilder("process.runtime.jvm.gc.time") + .setDescription("Time spent performing JVM garbage collection actions") + .setUnit("ms") + .ofLongs() + .build(); + + for (GarbageCollectorMXBean gcBean : ManagementFactory.getGarbageCollectorMXBeans()) { + if (!(gcBean instanceof NotificationEmitter)) { + continue; + } + NotificationEmitter notificationEmitter = (NotificationEmitter) gcBean; + notificationEmitter.addNotificationListener( + new GcNotificationListener(gcTime), GC_FILTER, null); + } + } + + private static final class GcNotificationListener implements NotificationListener { + + private final LongHistogram gcTime; + + private GcNotificationListener(LongHistogram gcTime) { + this.gcTime = gcTime; + } + + @Override + public void handleNotification(Notification notification, Object handback) { + GarbageCollectionNotificationInfo notificationInfo = + GarbageCollectionNotificationInfo.from((CompositeData) notification.getUserData()); + gcTime.record( + notificationInfo.getGcInfo().getDuration(), + Attributes.of( + GC_KEY, + notificationInfo.getGcName(), + CAUSE_KEY, + notificationInfo.getGcCause(), + ACTION_KEY, + notificationInfo.getGcAction())); + } + } + + private Gc() {} +}