All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.prometheus.client.hotspot.StandardExports Maven / Gradle / Ivy

package io.prometheus.client.hotspot;

import io.prometheus.client.Collector;
import io.prometheus.client.CounterMetricFamily;
import io.prometheus.client.GaugeMetricFamily;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.RuntimeMXBean;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Exports the standard exports common across all prometheus clients.
 * 

* This includes stats like CPU time spent and memory usage. *

* Example usage: *

 * {@code
 *   new StandardExports().register();
 * }
 * 
*/ public class StandardExports extends Collector { private static final Logger LOGGER = Logger.getLogger(StandardExports.class.getName()); private final StatusReader statusReader; private final OperatingSystemMXBean osBean; private final RuntimeMXBean runtimeBean; private final boolean linux; public StandardExports() { this(new StatusReader(), ManagementFactory.getOperatingSystemMXBean(), ManagementFactory.getRuntimeMXBean()); } StandardExports(StatusReader statusReader, OperatingSystemMXBean osBean, RuntimeMXBean runtimeBean) { this.statusReader = statusReader; this.osBean = osBean; this.runtimeBean = runtimeBean; this.linux = (osBean.getName().indexOf("Linux") == 0); } private final static double KB = 1024; @Override public List collect() { List mfs = new ArrayList(); try { // There exist at least 2 similar but unrelated UnixOperatingSystemMXBean interfaces, in // com.sun.management and com.ibm.lang.management. Hence use reflection and recursively go // through implemented interfaces until the method can be made accessible and invoked. Long processCpuTime = callLongGetter("getProcessCpuTime", osBean); mfs.add(new CounterMetricFamily("process_cpu_seconds_total", "Total user and system CPU time spent in seconds.", processCpuTime / NANOSECONDS_PER_SECOND)); } catch (Exception e) { LOGGER.log(Level.FINE,"Could not access process cpu time", e); } mfs.add(new GaugeMetricFamily("process_start_time_seconds", "Start time of the process since unix epoch in seconds.", runtimeBean.getStartTime() / MILLISECONDS_PER_SECOND)); // There exist at least 2 similar but unrelated UnixOperatingSystemMXBean interfaces, in // com.sun.management and com.ibm.lang.management. Hence use reflection and recursively go // through implemented interfaces until the method can be made accessible and invoked. try { Long openFdCount = callLongGetter("getOpenFileDescriptorCount", osBean); mfs.add(new GaugeMetricFamily( "process_open_fds", "Number of open file descriptors.", openFdCount)); Long maxFdCount = callLongGetter("getMaxFileDescriptorCount", osBean); mfs.add(new GaugeMetricFamily( "process_max_fds", "Maximum number of open file descriptors.", maxFdCount)); } catch (Exception e) { // Ignore, expected on non-Unix OSs. } // There's no standard Java or POSIX way to get memory stats, // so add support for just Linux for now. if (linux) { try { collectMemoryMetricsLinux(mfs); } catch (Exception e) { // If the format changes, log a warning and return what we can. LOGGER.warning(e.toString()); } } return mfs; } static Long callLongGetter(String getterName, Object obj) throws NoSuchMethodException, InvocationTargetException { return callLongGetter(obj.getClass().getMethod(getterName), obj); } /** * Attempts to call a method either directly or via one of the implemented interfaces. *

* A Method object refers to a specific method declared in a specific class. The first invocation * might happen with method == SomeConcreteClass.publicLongGetter() and will fail if * SomeConcreteClass is not public. We then recurse over all interfaces implemented by * SomeConcreteClass (or extended by those interfaces and so on) until we eventually invoke * callMethod() with method == SomePublicInterface.publicLongGetter(), which will then succeed. *

* There is a built-in assumption that the method will never return null (or, equivalently, that * it returns the primitive data type, i.e. {@code long} rather than {@code Long}). If this * assumption doesn't hold, the method might be called repeatedly and the returned value will be * the one produced by the last call. */ static Long callLongGetter(Method method, Object obj) throws InvocationTargetException { try { return (Long) method.invoke(obj); } catch (IllegalAccessException e) { // Expected, the declaring class or interface might not be public. } // Iterate over all implemented/extended interfaces and attempt invoking the method with the // same name and parameters on each. for (Class clazz : method.getDeclaringClass().getInterfaces()) { try { Method interfaceMethod = clazz.getMethod(method.getName(), method.getParameterTypes()); Long result = callLongGetter(interfaceMethod, obj); if (result != null) { return result; } } catch (NoSuchMethodException e) { // Expected, class might implement multiple, unrelated interfaces. } } return null; } void collectMemoryMetricsLinux(List mfs) { // statm/stat report in pages, and it's non-trivial to get pagesize from Java // so we parse status instead. BufferedReader br = null; try { br = statusReader.procSelfStatusReader(); String line; while ((line = br.readLine()) != null) { if (line.startsWith("VmSize:")) { mfs.add(new GaugeMetricFamily("process_virtual_memory_bytes", "Virtual memory size in bytes.", Float.parseFloat(line.split("\\s+")[1]) * KB)); } else if (line.startsWith("VmRSS:")) { mfs.add(new GaugeMetricFamily("process_resident_memory_bytes", "Resident memory size in bytes.", Float.parseFloat(line.split("\\s+")[1]) * KB)); } } } catch (IOException e) { LOGGER.fine(e.toString()); } finally { if (br != null) { try { br.close(); } catch (IOException e) { LOGGER.fine(e.toString()); } } } } static class StatusReader { BufferedReader procSelfStatusReader() throws FileNotFoundException { return new BufferedReader(new FileReader("/proc/self/status")); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy