Add prometheus support (#632)

pull/651/head
Tokuhiro Matsuno 9 years ago committed by Brett Wooldridge
parent 7d1fb2ea3a
commit 76cf343c8b

@ -47,6 +47,7 @@
<jndi.version>0.11.4.1</jndi.version>
<maven.release.version>2.5.3</maven.release.version>
<metrics.version>3.1.2</metrics.version>
<simpleclient.version>0.0.14</simpleclient.version>
<mockito.version>1.10.19</mockito.version>
<pax.exam.version>4.8.0</pax.exam.version>
<pax.url.version>2.4.5</pax.url.version>
@ -137,6 +138,13 @@
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient</artifactId>
<version>${simpleclient.version}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>simple-jndi</groupId>
<artifactId>simple-jndi</artifactId>

@ -0,0 +1,39 @@
package com.zaxxer.hikari.metrics.prometheus;
import com.zaxxer.hikari.metrics.PoolStats;
import io.prometheus.client.Collector;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
class HikariCPCollector extends Collector {
private final PoolStats poolStats;
private final List<String> labelNames;
private final List<String> labelValues;
HikariCPCollector(String poolName, PoolStats poolStats) {
this.poolStats = poolStats;
this.labelNames = Collections.singletonList("pool");
this.labelValues = Collections.singletonList(poolName);
}
@Override
public List<MetricFamilySamples> collect() {
return Arrays.asList(
createSample("hikaricp_active_connections", "Active connections", poolStats.getActiveConnections()),
createSample("hikaricp_idle_connections", "Idle connections", poolStats.getIdleConnections()),
createSample("hikaricp_pending_threads", "Pending threads", poolStats.getPendingThreads()),
createSample("hikaricp_connections", "The number of current connections", poolStats.getTotalConnections())
);
}
private MetricFamilySamples createSample(String name, String helpMessage, double value) {
List<MetricFamilySamples.Sample> samples = Collections.singletonList(new MetricFamilySamples.Sample(name,
labelNames,
labelValues,
value));
return new MetricFamilySamples(name, Type.GAUGE, helpMessage, samples);
}
}

@ -0,0 +1,52 @@
package com.zaxxer.hikari.metrics.prometheus;
import com.zaxxer.hikari.metrics.MetricsTracker;
import io.prometheus.client.Counter;
import io.prometheus.client.Summary;
class PrometheusMetricsTracker extends MetricsTracker {
private final Counter.Child connectionTimeoutCounter;
private final Summary.Child elapsedAcquiredSummary;
private final Summary.Child elapsedBorrowedSummary;
PrometheusMetricsTracker(String poolName) {
super();
Counter counter = Counter.build()
.name("hikaricp_connection_timeout_count")
.labelNames("pool")
.help("Connection timeout count")
.register();
this.connectionTimeoutCounter = counter.labels(poolName);
Summary elapsedAcquiredSummary = Summary.build()
.name("hikaricp_connection_acquired_nanos")
.labelNames("pool")
.help("Connection acquired time")
.register();
this.elapsedAcquiredSummary = elapsedAcquiredSummary.labels(poolName);
Summary elapsedBorrowedSummary = Summary.build()
.name("hikaricp_connection_usage_millis")
.labelNames("pool")
.help("Connection usage")
.register();
this.elapsedBorrowedSummary = elapsedBorrowedSummary.labels(poolName);
}
@Override
public void recordConnectionAcquiredNanos(long elapsedAcquiredNanos) {
elapsedAcquiredSummary.observe(elapsedAcquiredNanos);
}
@Override
public void recordConnectionUsageMillis(long elapsedBorrowedMillis) {
elapsedBorrowedSummary.observe(elapsedBorrowedMillis);
}
@Override
public void recordConnectionTimeout() {
connectionTimeoutCounter.inc();
}
}

@ -0,0 +1,19 @@
package com.zaxxer.hikari.metrics.prometheus;
import com.zaxxer.hikari.metrics.MetricsTracker;
import com.zaxxer.hikari.metrics.MetricsTrackerFactory;
import com.zaxxer.hikari.metrics.PoolStats;
/**
* <pre>{@code
* HikariConfig config = new HikariConfig();
* config.setMetricsTrackerFactory(new PrometheusMetricsTrackerFactory());
* }</pre>
*/
public class PrometheusMetricsTrackerFactory implements MetricsTrackerFactory {
@Override
public MetricsTracker create(String poolName, PoolStats poolStats) {
new HikariCPCollector(poolName, poolStats).register();
return new PrometheusMetricsTracker(poolName);
}
}

@ -0,0 +1,85 @@
package com.zaxxer.hikari.metrics.prometheus;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import io.prometheus.client.CollectorRegistry;
import org.junit.Test;
import java.sql.Connection;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
public class HikariCPCollectorTest {
@Test
public void noConnection() throws Exception {
HikariConfig config = new HikariConfig();
config.setPoolName("no_connection");
config.setMetricsTrackerFactory(new PrometheusMetricsTrackerFactory());
config.setJdbcUrl("jdbc:h2:mem:");
new HikariDataSource(config);
assertThat(getValue("hikaricp_active_connections", "no_connection"), is(0.0));
assertThat(getValue("hikaricp_idle_connections", "no_connection"), is(0.0));
assertThat(getValue("hikaricp_pending_threads", "no_connection"), is(0.0));
assertThat(getValue("hikaricp_connections", "no_connection"), is(0.0));
}
@Test
public void noConnectionWithoutPoolName() throws Exception {
HikariConfig config = new HikariConfig();
config.setMetricsTrackerFactory(new PrometheusMetricsTrackerFactory());
config.setJdbcUrl("jdbc:h2:mem:");
new HikariDataSource(config);
assertThat(getValue("hikaricp_active_connections", "HikariPool-1"), is(0.0));
assertThat(getValue("hikaricp_idle_connections", "HikariPool-1"), is(0.0));
assertThat(getValue("hikaricp_pending_threads", "HikariPool-1"), is(0.0));
assertThat(getValue("hikaricp_connections", "HikariPool-1"), is(0.0));
}
@Test
public void connection1() throws Exception {
HikariConfig config = new HikariConfig();
config.setPoolName("connection1");
config.setMetricsTrackerFactory(new PrometheusMetricsTrackerFactory());
config.setJdbcUrl("jdbc:h2:mem:");
HikariDataSource ds = new HikariDataSource(config);
Connection connection1 = ds.getConnection();
assertThat(getValue("hikaricp_active_connections", "connection1"), is(1.0));
assertThat(getValue("hikaricp_idle_connections", "connection1"), is(0.0));
assertThat(getValue("hikaricp_pending_threads", "connection1"), is(0.0));
assertThat(getValue("hikaricp_connections", "connection1"), is(1.0));
connection1.close();
}
@Test
public void connectionClosed() throws Exception {
HikariConfig config = new HikariConfig();
config.setPoolName("connectionClosed");
config.setMetricsTrackerFactory(new PrometheusMetricsTrackerFactory());
config.setJdbcUrl("jdbc:h2:mem:");
config.setMaximumPoolSize(20);
HikariDataSource ds = new HikariDataSource(config);
Connection connection1 = ds.getConnection();
connection1.close();
assertThat(getValue("hikaricp_active_connections", "connectionClosed"), is(0.0));
assertThat(getValue("hikaricp_idle_connections", "connectionClosed"), is(1.0));
assertThat(getValue("hikaricp_pending_threads", "connectionClosed"), is(0.0));
assertThat(getValue("hikaricp_connections", "connectionClosed"), is(1.0));
}
private double getValue(String name, String poolName) {
String[] labelNames = {"pool"};
String[] labelValues = {poolName};
return CollectorRegistry.defaultRegistry.getSampleValue(name, labelNames, labelValues);
}
}

@ -0,0 +1,60 @@
package com.zaxxer.hikari.metrics.prometheus;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import io.prometheus.client.CollectorRegistry;
import org.junit.Test;
import java.sql.Connection;
import java.sql.SQLTransientConnectionException;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
public class PrometheusMetricsTrackerTest {
@Test
public void recordConnectionTimeout() throws Exception {
String poolName = "record";
HikariConfig config = new HikariConfig();
config.setPoolName(poolName);
config.setMetricsTrackerFactory(new PrometheusMetricsTrackerFactory());
config.setJdbcUrl("jdbc:h2:mem:");
config.setMaximumPoolSize(1);
config.setConnectionTimeout(250);
String[] labelNames = {"pool"};
String[] labelValues = {poolName};
HikariDataSource hikariDataSource = new HikariDataSource(config);
Connection connection = hikariDataSource.getConnection();
try {
hikariDataSource.getConnection();
} catch (SQLTransientConnectionException ignored) {
}
connection.close();
assertThat(CollectorRegistry.defaultRegistry.getSampleValue(
"hikaricp_connection_timeout_count",
labelNames,
labelValues), is(1.0));
assertThat(CollectorRegistry.defaultRegistry.getSampleValue(
"hikaricp_connection_acquired_nanos_count",
labelNames,
labelValues), is(equalTo(1.0)));
assertTrue(CollectorRegistry.defaultRegistry.getSampleValue(
"hikaricp_connection_acquired_nanos_sum",
labelNames,
labelValues) > 0.0);
assertThat(CollectorRegistry.defaultRegistry.getSampleValue(
"hikaricp_connection_usage_millis_count",
labelNames,
labelValues), is(equalTo(1.0)));
assertTrue(CollectorRegistry.defaultRegistry.getSampleValue(
"hikaricp_connection_usage_millis_sum",
labelNames,
labelValues) > 0.0);
}
}
Loading…
Cancel
Save