001package io.prometheus.client.hotspot;
002
003import io.prometheus.client.Collector;
004import io.prometheus.client.GaugeMetricFamily;
005
006import java.lang.management.ManagementFactory;
007import java.lang.reflect.InvocationTargetException;
008import java.lang.reflect.Method;
009import java.util.ArrayList;
010import java.util.Collections;
011import java.util.List;
012import java.util.logging.Logger;
013
014/**
015 * Exports metrics about JVM buffers.
016 *
017 * Can be replaced with a simple access once JDK 1.7 compatibility is baseline.
018 *
019 */
020public class BufferPoolsExports extends Collector {
021
022    private static final Logger LOGGER = Logger.getLogger(BufferPoolsExports.class.getName());
023
024    private final List<Object> bufferPoolMXBeans = new ArrayList<Object>();
025    private Method getName;
026    private Method getMemoryUsed;
027    private Method getTotalCapacity;
028    private Method getCount;
029
030    public BufferPoolsExports() {
031        try {
032            final Class<?> bufferPoolMXBeanClass = Class.forName("java.lang.management.BufferPoolMXBean");
033            bufferPoolMXBeans.addAll(accessBufferPoolMXBeans(bufferPoolMXBeanClass));
034
035            getName = bufferPoolMXBeanClass.getMethod("getName");
036            getMemoryUsed = bufferPoolMXBeanClass.getMethod("getMemoryUsed");
037            getTotalCapacity = bufferPoolMXBeanClass.getMethod("getTotalCapacity");
038            getCount = bufferPoolMXBeanClass.getMethod("getCount");
039
040        } catch (ClassNotFoundException e) {
041            LOGGER.fine("BufferPoolMXBean not available, no metrics for buffer pools will be exported");
042        } catch (NoSuchMethodException e) {
043            LOGGER.fine("Can not get necessary accessor from BufferPoolMXBean: " + e.getMessage());
044        }
045    }
046
047    private static List<Object> accessBufferPoolMXBeans(final Class<?> bufferPoolMXBeanClass) {
048        try {
049            final Method getPlatformMXBeansMethod = ManagementFactory.class.getMethod("getPlatformMXBeans", Class.class);
050            final Object listOfBufferPoolMXBeanInstances = getPlatformMXBeansMethod.invoke(null, bufferPoolMXBeanClass);
051
052            return (List<Object>) listOfBufferPoolMXBeanInstances;
053
054        } catch (NoSuchMethodException e) {
055            LOGGER.fine("ManagementFactory.getPlatformMXBeans not available, no metrics for buffer pools will be exported");
056            return Collections.emptyList();
057        } catch (IllegalAccessException e) {
058            LOGGER.fine("ManagementFactory.getPlatformMXBeans not accessible, no metrics for buffer pools will be exported");
059            return Collections.emptyList();
060        } catch (InvocationTargetException e) {
061            LOGGER.warning("ManagementFactory.getPlatformMXBeans could not be invoked, no metrics for buffer pools will be exported");
062            return Collections.emptyList();
063        }
064    }
065
066    @Override
067    public List<MetricFamilySamples> collect() {
068        List<MetricFamilySamples> mfs = new ArrayList<MetricFamilySamples>();
069        GaugeMetricFamily used = new GaugeMetricFamily(
070                "jvm_buffer_pool_used_bytes",
071                "Used bytes of a given JVM buffer pool.",
072                Collections.singletonList("pool"));
073        mfs.add(used);
074        GaugeMetricFamily capacity = new GaugeMetricFamily(
075                "jvm_buffer_pool_capacity_bytes",
076                "Bytes capacity of a given JVM buffer pool.",
077                Collections.singletonList("pool"));
078        mfs.add(capacity);
079        GaugeMetricFamily buffers = new GaugeMetricFamily(
080                "jvm_buffer_pool_used_buffers",
081                "Used buffers of a given JVM buffer pool.",
082                Collections.singletonList("pool"));
083        mfs.add(buffers);
084        for (final Object pool : bufferPoolMXBeans) {
085            used.addMetric(
086                    Collections.singletonList(getName(pool)),
087                    callLongMethond(getMemoryUsed,pool));
088            capacity.addMetric(
089                    Collections.singletonList(getName(pool)),
090                    callLongMethond(getTotalCapacity,pool));
091            buffers.addMetric(
092                    Collections.singletonList(getName(pool)),
093                    callLongMethond(getCount,pool));
094        }
095        return mfs;
096    }
097
098    private long callLongMethond(final Method method, final Object pool) {
099        try {
100            return (Long)method.invoke(pool);
101        } catch (IllegalAccessException e) {
102            LOGGER.fine("Couldn't call " + method.getName() + ": " + e.getMessage());
103        } catch (InvocationTargetException e) {
104            LOGGER.fine("Couldn't call " + method.getName() + ": " + e.getMessage());
105        }
106        return 0L;
107    }
108
109    private String getName(final Object pool) {
110        try {
111            return (String)getName.invoke(pool);
112        } catch (IllegalAccessException e) {
113            LOGGER.fine("Couldn't call getName " + e.getMessage());
114        } catch (InvocationTargetException e) {
115            LOGGER.fine("Couldn't call getName " + e.getMessage());
116        }
117        return "<unknown>";
118    }
119
120
121
122}