|
1 | 1 | package io.prometheus.metrics.instrumentation.jvm; |
2 | 2 |
|
| 3 | +import com.sun.management.GarbageCollectionNotificationInfo; |
3 | 4 | import io.prometheus.metrics.config.PrometheusProperties; |
| 5 | +import io.prometheus.metrics.core.metrics.Histogram; |
4 | 6 | import io.prometheus.metrics.core.metrics.SummaryWithCallback; |
5 | 7 | import io.prometheus.metrics.model.registry.PrometheusRegistry; |
6 | 8 | import io.prometheus.metrics.model.snapshots.Quantiles; |
|
9 | 11 | import java.lang.management.ManagementFactory; |
10 | 12 | import java.util.List; |
11 | 13 | import javax.annotation.Nullable; |
| 14 | +import javax.management.NotificationEmitter; |
| 15 | +import javax.management.openmbean.CompositeData; |
12 | 16 |
|
13 | 17 | /** |
14 | 18 | * JVM Garbage Collector metrics. The {@link JvmGarbageCollectorMetrics} are registered as part of |
|
39 | 43 | public class JvmGarbageCollectorMetrics { |
40 | 44 |
|
41 | 45 | 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"; |
42 | 47 |
|
43 | 48 | private final PrometheusProperties config; |
44 | 49 | private final List<GarbageCollectorMXBean> garbageCollectorBeans; |
@@ -67,6 +72,47 @@ private void register(PrometheusRegistry registry) { |
67 | 72 | } |
68 | 73 | }) |
69 | 74 | .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 | + } |
70 | 116 | } |
71 | 117 |
|
72 | 118 | public static Builder builder() { |
|
0 commit comments