Skip to content

Commit

Permalink
Specify ...jvm.gc.duration buckets using advice API
Browse files Browse the repository at this point in the history
  • Loading branch information
Mateusz Rzeszutek committed May 15, 2023
1 parent c660a80 commit 02c8d9e
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 16 deletions.
1 change: 1 addition & 0 deletions instrumentation/runtime-metrics/library/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ plugins {

dependencies {
implementation(project(":instrumentation-api"))
implementation("io.opentelemetry:opentelemetry-extension-incubator")

testImplementation("io.opentelemetry:opentelemetry-sdk-metrics")
testImplementation(project(":testing-common"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@

package io.opentelemetry.instrumentation.runtimemetrics;

import static java.util.Collections.emptyList;

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.DoubleHistogram;
import io.opentelemetry.api.metrics.DoubleHistogramBuilder;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.extension.incubator.metrics.ExtendedDoubleHistogramBuilder;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.logging.Logger;
import javax.management.Notification;
Expand All @@ -35,6 +40,8 @@ public final class GarbageCollector {

private static final Logger logger = Logger.getLogger(GarbageCollector.class.getName());

private static final double MILLIS_PER_S = TimeUnit.SECONDS.toMillis(1);

private static final AttributeKey<String> GC_KEY = AttributeKey.stringKey("gc");
private static final AttributeKey<String> ACTION_KEY = AttributeKey.stringKey("action");

Expand Down Expand Up @@ -66,43 +73,52 @@ static void registerObservers(
Function<Notification, GarbageCollectionNotificationInfo> notificationInfoExtractor) {
Meter meter = RuntimeMetricsUtil.getMeter(openTelemetry);

LongHistogram gcTime =
DoubleHistogramBuilder gcDurationBuilder =
meter
.histogramBuilder("process.runtime.jvm.gc.duration")
.setDescription("Duration of JVM garbage collection actions")
.setUnit("ms")
.ofLongs()
.build();
.setUnit("s");
setGcDurationBuckets(gcDurationBuilder);
DoubleHistogram gcDuration = gcDurationBuilder.build();

for (GarbageCollectorMXBean gcBean : gcBeans) {
if (!(gcBean instanceof NotificationEmitter)) {
continue;
}
NotificationEmitter notificationEmitter = (NotificationEmitter) gcBean;
notificationEmitter.addNotificationListener(
new GcNotificationListener(gcTime, notificationInfoExtractor), GC_FILTER, null);
new GcNotificationListener(gcDuration, notificationInfoExtractor), GC_FILTER, null);
}
}

private static void setGcDurationBuckets(DoubleHistogramBuilder builder) {
if (!(builder instanceof ExtendedDoubleHistogramBuilder)) {
// that shouldn't really happen
return;
}
((ExtendedDoubleHistogramBuilder) builder)
.setAdvice(advice -> advice.setExplicitBucketBoundaries(emptyList()));
}

private static final class GcNotificationListener implements NotificationListener {

private final LongHistogram gcTime;
private final DoubleHistogram gcDuration;
private final Function<Notification, GarbageCollectionNotificationInfo>
notificationInfoExtractor;

private GcNotificationListener(
LongHistogram gcTime,
DoubleHistogram gcDuration,
Function<Notification, GarbageCollectionNotificationInfo> notificationInfoExtractor) {
this.gcTime = gcTime;
this.gcDuration = gcDuration;
this.notificationInfoExtractor = notificationInfoExtractor;
}

@Override
public void handleNotification(Notification notification, Object unused) {
GarbageCollectionNotificationInfo notificationInfo =
notificationInfoExtractor.apply(notification);
gcTime.record(
notificationInfo.getGcInfo().getDuration(),
gcDuration.record(
notificationInfo.getGcInfo().getDuration() / MILLIS_PER_S,
Attributes.of(
GC_KEY, notificationInfo.getGcName(), ACTION_KEY, notificationInfo.getGcAction()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,28 +72,30 @@ void registerObservers() {
assertThat(metricData)
.hasInstrumentationScope(EXPECTED_SCOPE)
.hasDescription("Duration of JVM garbage collection actions")
.hasUnit("ms")
.hasUnit("s")
.hasHistogramSatisfying(
histogram ->
histogram.hasPointsSatisfying(
point ->
point
.hasCount(2)
.hasSum(22)
.hasSum(0.022)
.hasAttributes(
Attributes.builder()
.put("gc", "G1 Young Generation")
.put("action", "end of minor GC")
.build()),
.build())
.hasBucketBoundaries(),
point ->
point
.hasCount(1)
.hasSum(11)
.hasSum(0.011)
.hasAttributes(
Attributes.builder()
.put("gc", "G1 Old Generation")
.put("action", "end of major GC")
.build())))));
.build())
.hasBucketBoundaries()))));
}

private static Notification createTestNotification(
Expand Down

0 comments on commit 02c8d9e

Please sign in to comment.