001package io.prometheus.client.hotspot;
002
003import io.prometheus.client.Collector;
004import io.prometheus.client.CounterMetricFamily;
005import io.prometheus.client.GaugeMetricFamily;
006
007import java.lang.management.ManagementFactory;
008import java.lang.management.ThreadMXBean;
009import java.util.ArrayList;
010import java.util.List;
011
012/**
013 * Exports metrics about JVM thread areas.
014 * <p>
015 * Example usage:
016 * <pre>
017 * {@code
018 *   new ThreadExports().register();
019 * }
020 * </pre>
021 * Example metrics being exported:
022 * <pre>
023 *   jvm_threads_current{} 300
024 *   jvm_threads_daemon{} 200
025 *   jvm_threads_peak{} 410
026 *   jvm_threads_started_total{} 1200
027 * </pre>
028 */
029public class ThreadExports extends Collector {
030  private final ThreadMXBean threadBean;
031
032  public ThreadExports() {
033    this(ManagementFactory.getThreadMXBean());
034  }
035
036  public ThreadExports(ThreadMXBean threadBean) {
037    this.threadBean = threadBean;
038  }
039
040  void addThreadMetrics(List<MetricFamilySamples> sampleFamilies) {
041    sampleFamilies.add(
042        new GaugeMetricFamily(
043          "jvm_threads_current",
044          "Current thread count of a JVM",
045          threadBean.getThreadCount()));
046
047    sampleFamilies.add(
048        new GaugeMetricFamily(
049          "jvm_threads_daemon",
050          "Daemon thread count of a JVM",
051          threadBean.getDaemonThreadCount()));
052
053    sampleFamilies.add(
054        new GaugeMetricFamily(
055          "jvm_threads_peak",
056          "Peak thread count of a JVM",
057          threadBean.getPeakThreadCount()));
058
059    sampleFamilies.add(
060        new CounterMetricFamily(
061          "jvm_threads_started_total",
062          "Started thread count of a JVM",
063          threadBean.getTotalStartedThreadCount()));
064
065    sampleFamilies.add(
066        new GaugeMetricFamily(
067        "jvm_threads_deadlocked",
068        "Cycles of JVM-threads that are in deadlock waiting to acquire object monitors or ownable synchronizers",
069        nullSafeArrayLength(threadBean.findDeadlockedThreads())));
070
071    sampleFamilies.add(
072        new GaugeMetricFamily(
073        "jvm_threads_deadlocked_monitor",
074        "Cycles of JVM-threads that are in deadlock waiting to acquire object monitors",
075        nullSafeArrayLength(threadBean.findMonitorDeadlockedThreads())));
076  }
077
078  private static double nullSafeArrayLength(long[] array) {
079    return null == array ? 0 : array.length;
080  }
081
082  public List<MetricFamilySamples> collect() {
083    List<MetricFamilySamples> mfs = new ArrayList<MetricFamilySamples>();
084    addThreadMetrics(mfs);
085    return mfs;
086  }
087}