diff options
author | Olli Virtanen <olli.virtanen@oath.com> | 2018-06-01 12:09:03 +0200 |
---|---|---|
committer | Olli Virtanen <olli.virtanen@oath.com> | 2018-06-01 12:09:03 +0200 |
commit | e5d6ee5899daca0644df14ef143678d43cd5b231 (patch) | |
tree | 3dcd83ec0f44f704e405fea5dd773a677198d0b2 /container-disc/src/main/java/com/yahoo/container/jdisc/metric/GarbageCollectionMetrics.java | |
parent | 5c57852b26126d72b080fb6e0893dc3d633c28c1 (diff) |
JVM Garbage collection metrics
Diffstat (limited to 'container-disc/src/main/java/com/yahoo/container/jdisc/metric/GarbageCollectionMetrics.java')
-rw-r--r-- | container-disc/src/main/java/com/yahoo/container/jdisc/metric/GarbageCollectionMetrics.java | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/metric/GarbageCollectionMetrics.java b/container-disc/src/main/java/com/yahoo/container/jdisc/metric/GarbageCollectionMetrics.java new file mode 100644 index 00000000000..49353332271 --- /dev/null +++ b/container-disc/src/main/java/com/yahoo/container/jdisc/metric/GarbageCollectionMetrics.java @@ -0,0 +1,94 @@ +package com.yahoo.container.jdisc.metric; + +import com.yahoo.jdisc.Metric; + +import java.lang.management.GarbageCollectorMXBean; +import java.lang.management.ManagementFactory; +import java.time.Clock; +import java.time.Duration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; + +/** + * @author ollivir + */ +public class GarbageCollectionMetrics { + private static final String GC_PREFIX = "jdisc.gc."; + private static final String GC_COUNT = GC_PREFIX + ".count"; + private static final String GC_TIME = GC_PREFIX + ".ms"; + private static final String DIMENSION_KEY = "gcName"; + + public static final long REPORTING_INTERVAL = Duration.ofSeconds(62).toMillis(); + + static class GcStats { + private final long when; + private final long count; + private final long ms; + + private GcStats(long when, long count, long ms) { + this.when = when; + this.count = count; + this.ms = ms; + } + } + + private Map<String, LinkedList<GcStats>> gcStatistics; + + private final Clock clock; + + public GarbageCollectionMetrics(Clock clock) { + this.clock = clock; + this.gcStatistics = new HashMap<>(); + collectGcStatistics(clock.millis()); + } + + private void collectGcStatistics(long now) { + for (GarbageCollectorMXBean gcBean : ManagementFactory.getGarbageCollectorMXBeans()) { + String gcName = gcBean.getName().replace(" ", ""); + GcStats stats = new GcStats(now, gcBean.getCollectionCount(), gcBean.getCollectionTime()); + + LinkedList<GcStats> window = gcStatistics.computeIfAbsent(gcName, anyName -> new LinkedList<>()); + window.addLast(stats); + } + } + + private void cleanStatistics(long now) { + long oldestToKeep = now - REPORTING_INTERVAL; + + for(Iterator<Map.Entry<String, LinkedList<GcStats>>> it = gcStatistics.entrySet().iterator(); it.hasNext(); ) { + Map.Entry<String, LinkedList<GcStats>> entry = it.next(); + LinkedList<GcStats> history = entry.getValue(); + while(history.isEmpty() == false && history.getFirst().when < oldestToKeep) { + history.removeFirst(); + } + if(history.isEmpty()) { + it.remove(); + } + } + } + + public void emitMetrics(Metric metric) { + long now = clock.millis(); + + collectGcStatistics(now); + cleanStatistics(now); + + for (Map.Entry<String, LinkedList<GcStats>> item : gcStatistics.entrySet()) { + GcStats reference = item.getValue().getFirst(); + GcStats latest = item.getValue().getLast(); + Map<String, String> contextData = new HashMap<>(); + contextData.put(DIMENSION_KEY, item.getKey()); + Metric.Context gcContext = metric.createContext(contextData); + + metric.set(GC_COUNT, latest.count - reference.count, gcContext); + metric.set(GC_TIME, latest.ms - reference.ms, gcContext); + } + } + + // partial exposure for testing + Map<String, LinkedList<GcStats>> getGcStatistics() { + return gcStatistics; + } +} |