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