001package nl.nlighten.prometheus.tomcat;
002
003import io.prometheus.client.Collector;
004import io.prometheus.client.GaugeMetricFamily;
005import javax.management.*;
006import java.lang.management.ManagementFactory;
007import java.util.ArrayList;
008import java.util.Collections;
009import java.util.List;
010import java.util.Set;
011
012/**
013 * Exports Tomcat <a href="https://tomcat.apache.org/tomcat-8.5-doc/jndi-datasource-examples-howto.html#Database_Connection_Pool_(DBCP_2)_Configurations">DBCP2-pool</a> metrics.
014 * <p>
015 * Example usage:
016 * <pre>
017 * {@code
018 *   new TomcatDbcp2PoolExports().register();
019 * }
020 * </pre>
021 * Example metrics being exported:
022 * <pre>
023 *    tomcat_dpcp2_connections_max{pool="jdbc/mypool"} 20.0
024 *    tomcat_dbcp2_connections_active_total{pool="jdbc/mypool"} 2.0
025 *    tomcat_dbcp2_connections_idle_total{pool="jdbc/mypool"} 6.0
026 * </pre>
027 */
028
029public class TomcatDbcp2PoolExports extends Collector {
030
031    public List<MetricFamilySamples> collect() {
032        List<MetricFamilySamples> mfs = new ArrayList<MetricFamilySamples>();
033        try {
034            final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
035            ObjectName filterName = new ObjectName("Tomcat:class=javax.sql.DataSource,type=DataSource,*");
036            Set<ObjectInstance> mBeans = server.queryMBeans(filterName, null);
037
038            if (mBeans.size() > 0) {
039                List<String> labelList = Collections.singletonList("pool");
040
041                GaugeMetricFamily maxActiveConnectionsGauge = new GaugeMetricFamily(
042                        "tomcat_dbcp2_connections_max",
043                        "Maximum number of active connections that can be allocated from this pool at the same time",
044                        labelList);
045
046                GaugeMetricFamily activeConnectionsGauge = new GaugeMetricFamily(
047                        "tomcat_dbcp2_connections_active_total",
048                        "Number of active connections allocated from this pool",
049                        labelList);
050
051                GaugeMetricFamily idleConnectionsGauge = new GaugeMetricFamily(
052                        "tomcat_dbcp2_connections_idle_total",
053                        "Number of idle connections in this pool",
054                        labelList);
055
056
057                for (final ObjectInstance mBean : mBeans) {
058                    if (mBean.getObjectName().getKeyProperty("connectionpool") == null){
059                        List<String> labelValueList = Collections.singletonList(mBean.getObjectName().getKeyProperty("name").replaceAll("[\"\\\\]", ""));
060
061                        maxActiveConnectionsGauge.addMetric(
062                                labelValueList,
063                                ((Integer) server.getAttribute(mBean.getObjectName(), "maxTotal")).doubleValue());
064
065                        activeConnectionsGauge.addMetric(
066                                labelValueList,
067                                ((Integer) server.getAttribute(mBean.getObjectName(), "numActive")).doubleValue());
068
069                        idleConnectionsGauge.addMetric(
070                                labelValueList,
071                                ((Integer) server.getAttribute(mBean.getObjectName(), "numIdle")).doubleValue());
072
073                    }
074
075                    mfs.add(maxActiveConnectionsGauge);
076                    mfs.add(activeConnectionsGauge);
077                    mfs.add(idleConnectionsGauge);
078                }
079            }
080        } catch (javax.management.AttributeNotFoundException e) {
081            // Can happen in exception cases where TomcatDbcp2PoolExports is configured with a TomcatJdcpPool configured
082        }
083        catch (Exception e) {
084            System.out.println ("####### " + e.getLocalizedMessage());
085            e.printStackTrace();
086        }
087        return mfs;
088    }
089
090    public static boolean isDbcp2Used() {
091        try {
092            final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
093            ObjectName filterName = new ObjectName("tomcat.jdbc:class=org.apache.tomcat.jdbc.pool.DataSource,type=ConnectionPool,*");
094            Set<ObjectInstance> mBeans = server.queryMBeans(filterName, null);
095            return !mBeans.isEmpty();
096        } catch (Exception e) {
097            e.printStackTrace();
098        }
099        return false;
100    }
101
102}