package com.etsy.statsd.profiler.profilers; import com.google.common.collect.ImmutableMap; import com.etsy.statsd.profiler.Arguments; import com.etsy.statsd.profiler.Profiler; import com.etsy.statsd.profiler.reporter.Reporter; import java.lang.management.ManagementFactory; import java.util.Map; import java.util.concurrent.TimeUnit; import javax.management.Attribute; import javax.management.AttributeList; import javax.management.InstanceNotFoundException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.ReflectionException; /** * This profiler retrieves CPU values for the JVM and System from the "OperatingSystem" JMX Bean. * <p> * This profiler relies on a JMX bean that might not be available in all JVM implementations. * We know for sure it's available in Sun/Oracle's JRE 7+, but there are no guarantees it * will remain there for the foreseeable future. * * @see <a href="http://stackoverflow.com/questions/3044841/cpu-usage-mbean-on-sun-jvm">StackOverflow post</a> * * @author Alejandro Rivera */ public class CPULoadProfiler extends Profiler { public static final long PERIOD = 10; private static final Map<String, String> ATTRIBUTES_MAP = ImmutableMap.of("ProcessCpuLoad", "cpu.jvm", "SystemCpuLoad", "cpu.system"); private AttributeList list; public CPULoadProfiler(Reporter reporter, Arguments arguments) { super(reporter, arguments); try { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); ObjectName os = ObjectName.getInstance("java.lang:type=OperatingSystem"); list = mbs.getAttributes(os, ATTRIBUTES_MAP.keySet().toArray(new String[ATTRIBUTES_MAP.size()])); } catch (InstanceNotFoundException | ReflectionException | MalformedObjectNameException e) { list = null; } } /** * Profile memory usage and GC statistics */ @Override public void profile() { recordStats(); } @Override public void flushData() { recordStats(); } @Override public long getPeriod() { return PERIOD; } @Override public TimeUnit getTimeUnit() { return TimeUnit.SECONDS; } @Override protected void handleArguments(Arguments arguments) { /* No arguments needed */ } /** * Records all memory statistics */ private void recordStats() { if (list == null) { return; } Attribute att; Double value; String metric; for (Object o : list) { att = (Attribute) o; value = (Double) att.getValue(); if (value == null || value == -1.0) { continue; } metric = ATTRIBUTES_MAP.get(att.getName()); if (metric == null) { continue; } value = ((int) (value * 1000)) / 10.0d; // 0-100 with 1-decimal precision recordGaugeValue(metric, value); } } }