package com.orbitz.monitoring.lib.timertask; import static java.lang.management.ManagementFactory.getGarbageCollectorMXBeans; import com.orbitz.monitoring.api.Monitor; import com.orbitz.monitoring.api.MonitoringLevel; import com.orbitz.monitoring.api.monitor.EventMonitor; import java.lang.management.GarbageCollectorMXBean; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.MemoryPoolMXBean; import java.lang.management.MemoryType; import java.lang.management.MemoryUsage; import java.lang.management.ThreadMXBean; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; /** * VMStatTimerTask uses jdk5 MXBeans access garbage collection and thread stats. EventMonitors * named GarbageCollectorStats and ThreadStats are fired containing the stats as attributes. * * @since 3.5 * * @author Matt O'Keefe */ public class VMStatTimerTask extends MonitorEmittingTimerTask { // 2 ^ 20 = 1024 * 1024 = 1048576 private static final int BASE_2_EXP_MEGABYTE = 20; private final Map<String,AtomicLong> gc; public VMStatTimerTask() { super(); gc = new HashMap<String,AtomicLong>(8); for (GarbageCollectorMXBean garbageCollectorMXBean : getGarbageCollectorMXBeans()) { final String name = garbageCollectorMXBean.getName(); gc.put(name + ".count", new AtomicLong()); gc.put(name + ".time", new AtomicLong()); } } /** * The action to be performed by this timer task. */ public Collection<Monitor> emitMonitors() { Set<Monitor> monitors = new HashSet<Monitor>(); for (GarbageCollectorMXBean garbageCollectorMXBean : getGarbageCollectorMXBeans()) { String name = garbageCollectorMXBean.getName(); long count = setGCAndGetDelta(name + ".count", garbageCollectorMXBean.getCollectionCount()); long time = setGCAndGetDelta(name + ".time", garbageCollectorMXBean.getCollectionTime()); monitors.add(fireJvmStat("GarbageCollector." + name, count, time)); } ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); monitors.add(fireJvmStat("Thread", (long) threadBean.getThreadCount())); MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); long objectPendingFinalizationCount = memoryMXBean.getObjectPendingFinalizationCount(); monitors.add(fireJvmStat("Memory.objectPendingFinalization", objectPendingFinalizationCount)); monitors.add(fireJvmStat("Memory.Heap.memoryUsage", memoryMXBean.getHeapMemoryUsage())); monitors.add(fireJvmStat("Memory.NonHeap.memoryUsage", memoryMXBean.getNonHeapMemoryUsage())); for (MemoryPoolMXBean memoryPoolMXBean: ManagementFactory.getMemoryPoolMXBeans()) { String type = (MemoryType.HEAP == memoryPoolMXBean.getType()) ? "Heap" : "NonHeap"; String name = "Memory." + type + ".Pool." + memoryPoolMXBean.getName(); monitors.add(fireJvmStat(name + ".memoryUsage", memoryPoolMXBean.getUsage())); MemoryUsage usage = memoryPoolMXBean.getCollectionUsage(); if (usage != null) { monitors.add(fireJvmStat(name + ".memoryCollectionUsage", toMegaBytes(usage.getUsed()))); } } return monitors; } // calculates a gc delta value private long setGCAndGetDelta(final String key, final long newValue) { final long oldValue = gc.get(key).getAndSet(newValue); return newValue - oldValue; } // convert a number from bytes to megabytes private long toMegaBytes(final long number) { return number >> BASE_2_EXP_MEGABYTE; } // get the percentage used private double getUsedPercentage(MemoryUsage usage) { return (100.0 * usage.getUsed()) / usage.getMax(); } // fire JvmStats monitor; sets the name, type, count, time and percent private EventMonitor fireJvmStat(String type, MemoryUsage usage) { long usedMegaBytes = toMegaBytes(usage.getUsed()); double usedPercentage = getUsedPercentage(usage); return fireJvmStat(type, usedMegaBytes, null, usedPercentage); } private EventMonitor fireJvmStat(String type, Long count) { return fireJvmStat(type, count, null, null); } private EventMonitor fireJvmStat(String type, Long count, Long time) { return fireJvmStat(type, count, time, null); } private EventMonitor fireJvmStat(String type, Long count, Long time, Double percent) { final EventMonitor monitor = new EventMonitor("JvmStats", MonitoringLevel.ESSENTIAL); monitor.set("type", type); if (count != null) { monitor.set("count", count); } if (time != null) { monitor.set("time", time); } if (percent != null) { monitor.set("percent", percent); } monitor.fire(); return monitor; } }