001package nl.nlighten.prometheus.tomcat;
002
003import io.prometheus.client.Collector;
004import io.prometheus.client.GaugeMetricFamily;
005
006import javax.management.MBeanServer;
007import javax.management.ObjectInstance;
008import javax.management.ObjectName;
009import java.lang.management.ManagementFactory;
010import java.util.*;
011
012/**
013 * Exports Tomcat <a href="http://tomcat.apache.org/tomcat-8.5-doc/jdbc-pool.html">jdbc-pool</a> metrics.
014 * <p>
015 * Example usage:
016 * <pre>
017 * {@code
018 *   new TomcatJdbcPoolExports().register();
019 * }
020 * </pre>
021 * Example metrics being exported:
022 * <pre>
023 *    tomcat_jdbc_connections_max{pool="jdbc/mypool"} 20.0
024 *    tomcat_jdbc_connections_active_total{pool="jdbc/mypool"} 2.0
025 *    tomcat_jdbc_connections_idle_total{pool="jdbc/mypool"} 6.0
026 *    tomcat_jdbc_connections_total{pool="jdbc/mypool"} 8.0
027 *    tomcat_jdbc_connections_threadswaiting_total{pool="jdbc/mypool"} 0.0
028 * </pre>
029 */
030
031public class TomcatJdbcPoolExports extends Collector {
032
033    public List<MetricFamilySamples> collect() {
034        List<MetricFamilySamples> mfs = new ArrayList<MetricFamilySamples>();
035        try {
036            final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
037            ObjectName filterName = new ObjectName("tomcat.jdbc:class=org.apache.tomcat.jdbc.pool.DataSource,type=ConnectionPool,*");
038            Set<ObjectInstance> mBeans = server.queryMBeans(filterName, null);
039
040            if (mBeans.size() > 0) {
041                List<String> labelList = Collections.singletonList("pool");
042
043                GaugeMetricFamily maxActiveConnectionsGauge = new GaugeMetricFamily(
044                        "tomcat_jdbc_connections_max",
045                        "Maximum number of active connections that can be allocated from this pool at the same time",
046                        labelList);
047
048                GaugeMetricFamily activeConnectionsGauge = new GaugeMetricFamily(
049                        "tomcat_jdbc_connections_active_total",
050                        "Number of active connections allocated from this pool",
051                        labelList);
052
053                GaugeMetricFamily idleConnectionsGauge = new GaugeMetricFamily(
054                        "tomcat_jdbc_connections_idle_total",
055                        "Number of idle connections in this pool",
056                        labelList);
057
058                GaugeMetricFamily totalConnectionsGauge = new GaugeMetricFamily(
059                        "tomcat_jdbc_connections_total",
060                        "Total number of connections in this pool",
061                        labelList);
062
063                GaugeMetricFamily waitingThreadsCountGauge = new GaugeMetricFamily(
064                        "tomcat_jdbc_waitingthreads_total",
065                        "Number of threads waiting for connections from this pool",
066                        labelList);
067
068                for (final ObjectInstance mBean : mBeans) {
069                    List<String> labelValueList = Collections.singletonList(mBean.getObjectName().getKeyProperty("name").replaceAll("[\"\\\\]", ""));
070
071                    maxActiveConnectionsGauge.addMetric(
072                            labelValueList,
073                            ((Integer) server.getAttribute(mBean.getObjectName(), "MaxActive")).doubleValue());
074
075                    activeConnectionsGauge.addMetric(
076                            labelValueList,
077                            ((Integer) server.getAttribute(mBean.getObjectName(), "Active")).doubleValue());
078
079                    idleConnectionsGauge.addMetric(
080                            labelValueList,
081                            ((Integer) server.getAttribute(mBean.getObjectName(), "Idle")).doubleValue());
082
083                    totalConnectionsGauge.addMetric(
084                            labelValueList,
085                            ((Integer) server.getAttribute(mBean.getObjectName(), "Size")).doubleValue());
086
087                    waitingThreadsCountGauge.addMetric(
088                            labelValueList,
089                            ((Integer) server.getAttribute(mBean.getObjectName(), "WaitCount")).doubleValue());
090                }
091
092                mfs.add(maxActiveConnectionsGauge);
093                mfs.add(activeConnectionsGauge);
094                mfs.add(idleConnectionsGauge);
095                mfs.add(totalConnectionsGauge);
096                mfs.add(waitingThreadsCountGauge);
097            }
098        } catch (Exception e) {
099            e.printStackTrace();
100        }
101        return mfs;
102    }
103
104    public static boolean isTomcatJdbcUsed() {
105        try {
106            final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
107            ObjectName filterName = new ObjectName("tomcat.jdbc:class=org.apache.tomcat.jdbc.pool.DataSource,type=ConnectionPool,*");
108            Set<ObjectInstance> mBeans = server.queryMBeans(filterName, null);
109            return !mBeans.isEmpty();
110        } catch (Exception e) {
111            e.printStackTrace();
112        }
113        return false;
114    }
115
116}