Skip to content

Commit f7168cf

Browse files
committed
Add GC pause duration histogram
1 parent b7741a0 commit f7168cf

File tree

2 files changed

+49
-1
lines changed

2 files changed

+49
-1
lines changed

prometheus-metrics-instrumentation-jvm/src/main/java/io/prometheus/metrics/instrumentation/jvm/JvmGarbageCollectorMetrics.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.prometheus.metrics.instrumentation.jvm;
22

3+
import com.sun.management.GarbageCollectionNotificationInfo;
34
import io.prometheus.metrics.config.PrometheusProperties;
5+
import io.prometheus.metrics.core.metrics.Histogram;
46
import io.prometheus.metrics.core.metrics.SummaryWithCallback;
57
import io.prometheus.metrics.model.registry.PrometheusRegistry;
68
import io.prometheus.metrics.model.snapshots.Quantiles;
@@ -9,6 +11,8 @@
911
import java.lang.management.ManagementFactory;
1012
import java.util.List;
1113
import javax.annotation.Nullable;
14+
import javax.management.NotificationEmitter;
15+
import javax.management.openmbean.CompositeData;
1216

1317
/**
1418
* JVM Garbage Collector metrics. The {@link JvmGarbageCollectorMetrics} are registered as part of
@@ -39,6 +43,7 @@
3943
public class JvmGarbageCollectorMetrics {
4044

4145
private static final String JVM_GC_COLLECTION_SECONDS = "jvm_gc_collection_seconds";
46+
private static final String JVM_GC_DURATION_SECONDS = "jvm_gc_duration_seconds";
4247

4348
private final PrometheusProperties config;
4449
private final List<GarbageCollectorMXBean> garbageCollectorBeans;
@@ -67,6 +72,47 @@ private void register(PrometheusRegistry registry) {
6772
}
6873
})
6974
.register(registry);
75+
76+
registerGCDurationHistogram(registry);
77+
}
78+
79+
private void registerGCDurationHistogram(PrometheusRegistry registry) {
80+
double[] buckets = {0.01, 0.1, 1, 10};
81+
82+
Histogram gcDurationHistogram =
83+
Histogram.builder(config)
84+
.name(JVM_GC_DURATION_SECONDS)
85+
.help("JVM GC pause duration histogram.")
86+
.unit(Unit.SECONDS)
87+
.labelNames("gc", "action", "cause")
88+
.classicUpperBounds(buckets)
89+
.register(registry);
90+
91+
for (GarbageCollectorMXBean gcBean : garbageCollectorBeans) {
92+
93+
if (!(gcBean instanceof NotificationEmitter)) {
94+
continue;
95+
}
96+
97+
NotificationEmitter notificationEmitter = (NotificationEmitter) gcBean;
98+
99+
notificationEmitter.addNotificationListener(
100+
(notification, handback) -> {
101+
if (!GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION.equals(
102+
notification.getType())) {
103+
return;
104+
}
105+
106+
GarbageCollectionNotificationInfo info =
107+
GarbageCollectionNotificationInfo.from((CompositeData) notification.getUserData());
108+
109+
gcDurationHistogram
110+
.labelValues(info.getGcName(), info.getGcAction(), info.getGcCause())
111+
.observe(Unit.millisToSeconds(info.getGcInfo().getDuration()));
112+
},
113+
null,
114+
null);
115+
}
70116
}
71117

72118
public static Builder builder() {

prometheus-metrics-instrumentation-jvm/src/test/java/io/prometheus/metrics/instrumentation/jvm/JvmGarbageCollectorMetricsTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ public void testGoodCase() throws IOException {
5858
@Test
5959
public void testIgnoredMetricNotScraped() {
6060
MetricNameFilter filter =
61-
MetricNameFilter.builder().nameMustNotBeEqualTo("jvm_gc_collection_seconds").build();
61+
MetricNameFilter.builder()
62+
.nameMustNotBeEqualTo("jvm_gc_collection_seconds", "jvm_gc_duration_seconds")
63+
.build();
6264

6365
PrometheusRegistry registry = new PrometheusRegistry();
6466
JvmGarbageCollectorMetrics.builder()

0 commit comments

Comments
 (0)