Fix prometheus histogram metric tracker for multiple pools (#1692)

* Add support for multiple prometheus histogram metric trackers

* Add tests
pull/1716/head
Vladislav Golub 4 years ago committed by GitHub
parent 0561309e32
commit 28cb7c0961
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -20,6 +20,12 @@ import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.Counter;
import io.prometheus.client.Histogram;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.zaxxer.hikari.metrics.prometheus.PrometheusMetricsTrackerFactory.*;
import static com.zaxxer.hikari.metrics.prometheus.PrometheusMetricsTrackerFactory.RegistrationStatus.REGISTERED;
/**
* Alternative Prometheus metrics tracker using a Histogram instead of Summary
* <p>
@ -56,12 +62,19 @@ class PrometheusHistogramMetricsTracker implements IMetricsTracker
.create();
}
private final static Map<CollectorRegistry, RegistrationStatus> registrationStatuses = new ConcurrentHashMap<>();
private final String poolName;
private final HikariCPCollector hikariCPCollector;
private final Histogram.Child elapsedAcquiredHistogramChild;
private final Histogram.Child elapsedBorrowedHistogramChild;
private final Histogram.Child elapsedCreationHistogramChild;
PrometheusHistogramMetricsTracker(String poolName, CollectorRegistry collectorRegistry) {
PrometheusHistogramMetricsTracker(String poolName, CollectorRegistry collectorRegistry, HikariCPCollector hikariCPCollector) {
registerMetrics(collectorRegistry);
this.poolName = poolName;
this.hikariCPCollector = hikariCPCollector;
this.connectionTimeoutCounterChild = CONNECTION_TIMEOUT_COUNTER.labels(poolName);
this.elapsedAcquiredHistogramChild = ELAPSED_ACQUIRED_HISTOGRAM.labels(poolName);
this.elapsedBorrowedHistogramChild = ELAPSED_BORROWED_HISTOGRAM.labels(poolName);
@ -69,10 +82,12 @@ class PrometheusHistogramMetricsTracker implements IMetricsTracker
}
private void registerMetrics(CollectorRegistry collectorRegistry) {
CONNECTION_TIMEOUT_COUNTER.register(collectorRegistry);
ELAPSED_ACQUIRED_HISTOGRAM.register(collectorRegistry);
ELAPSED_BORROWED_HISTOGRAM.register(collectorRegistry);
ELAPSED_CREATION_HISTOGRAM.register(collectorRegistry);
if (registrationStatuses.putIfAbsent(collectorRegistry, REGISTERED) == null) {
CONNECTION_TIMEOUT_COUNTER.register(collectorRegistry);
ELAPSED_ACQUIRED_HISTOGRAM.register(collectorRegistry);
ELAPSED_BORROWED_HISTOGRAM.register(collectorRegistry);
ELAPSED_CREATION_HISTOGRAM.register(collectorRegistry);
}
}
@Override
@ -94,4 +109,13 @@ class PrometheusHistogramMetricsTracker implements IMetricsTracker
public void recordConnectionTimeout() {
connectionTimeoutCounterChild.inc();
}
@Override
public void close() {
hikariCPCollector.remove(poolName);
CONNECTION_TIMEOUT_COUNTER.remove(poolName);
ELAPSED_ACQUIRED_HISTOGRAM.remove(poolName);
ELAPSED_BORROWED_HISTOGRAM.remove(poolName);
ELAPSED_CREATION_HISTOGRAM.remove(poolName);
}
}

@ -19,8 +19,15 @@ package com.zaxxer.hikari.metrics.prometheus;
import com.zaxxer.hikari.metrics.IMetricsTracker;
import com.zaxxer.hikari.metrics.MetricsTrackerFactory;
import com.zaxxer.hikari.metrics.PoolStats;
import com.zaxxer.hikari.metrics.prometheus.PrometheusMetricsTrackerFactory.RegistrationStatus;
import io.prometheus.client.Collector;
import io.prometheus.client.CollectorRegistry;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.zaxxer.hikari.metrics.prometheus.PrometheusMetricsTrackerFactory.RegistrationStatus.*;
/**
* <pre>{@code
* HikariConfig config = new HikariConfig();
@ -29,16 +36,18 @@ import io.prometheus.client.CollectorRegistry;
*/
public class PrometheusHistogramMetricsTrackerFactory implements MetricsTrackerFactory {
private HikariCPCollector collector;
private final static Map<CollectorRegistry, RegistrationStatus> registrationStatuses = new ConcurrentHashMap<>();
private final HikariCPCollector collector = new HikariCPCollector();
private CollectorRegistry collectorRegistry;
private final CollectorRegistry collectorRegistry;
/**
* Default Constructor. The Hikari metrics are registered to the default
* collector registry ({@code CollectorRegistry.defaultRegistry}).
*/
public PrometheusHistogramMetricsTrackerFactory() {
this.collectorRegistry = CollectorRegistry.defaultRegistry;
this(CollectorRegistry.defaultRegistry);
}
/**
@ -51,17 +60,14 @@ public class PrometheusHistogramMetricsTrackerFactory implements MetricsTrackerF
@Override
public IMetricsTracker create(String poolName, PoolStats poolStats) {
getCollector().add(poolName, poolStats);
return new PrometheusHistogramMetricsTracker(poolName, this.collectorRegistry);
registerCollector(this.collector, this.collectorRegistry);
this.collector.add(poolName, poolStats);
return new PrometheusHistogramMetricsTracker(poolName, this.collectorRegistry, this.collector);
}
/**
* initialize and register collector if it isn't initialized yet
*/
private HikariCPCollector getCollector() {
if (collector == null) {
collector = new HikariCPCollector().register(this.collectorRegistry);
private void registerCollector(Collector collector, CollectorRegistry collectorRegistry) {
if (registrationStatuses.putIfAbsent(collectorRegistry, REGISTERED) == null) {
collector.register(collectorRegistry);
}
return collector;
}
}

@ -49,9 +49,9 @@ public class PrometheusMetricsTrackerFactory implements MetricsTrackerFactory
private final CollectorRegistry collectorRegistry;
public enum RegistrationStatus
enum RegistrationStatus
{
REGISTERED;
REGISTERED
}
/**

@ -32,24 +32,26 @@ import static org.junit.Assert.assertThat;
public class PrometheusHistogramMetricsTrackerTest {
private CollectorRegistry collectorRegistry;
private CollectorRegistry defaultCollectorRegistry;
private CollectorRegistry customCollectorRegistry;
private static final String POOL_LABEL_NAME = "pool";
private static final String[] LABEL_NAMES = {POOL_LABEL_NAME};
@Before
public void setupCollectorRegistry(){
this.collectorRegistry = new CollectorRegistry();
public void setupCollectorRegistry() {
this.defaultCollectorRegistry = new CollectorRegistry();
this.customCollectorRegistry = new CollectorRegistry();
}
@Test
public void recordConnectionTimeout() throws Exception {
HikariConfig config = newHikariConfig();
config.setMetricsTrackerFactory(new PrometheusHistogramMetricsTrackerFactory(collectorRegistry));
config.setMetricsTrackerFactory(new PrometheusHistogramMetricsTrackerFactory(defaultCollectorRegistry));
config.setJdbcUrl("jdbc:h2:mem:");
config.setMaximumPoolSize(2);
config.setConnectionTimeout(250);
String[] labelNames = {POOL_LABEL_NAME};
String[] labelValues = {config.getPoolName()};
try (HikariDataSource hikariDataSource = new HikariDataSource(config)) {
@ -60,9 +62,9 @@ public class PrometheusHistogramMetricsTrackerTest {
}
}
Double total = collectorRegistry.getSampleValue(
Double total = defaultCollectorRegistry.getSampleValue(
"hikaricp_connection_timeout_total",
labelNames,
LABEL_NAMES,
labelValues
);
assertThat(total, is(1.0));
@ -85,57 +87,87 @@ public class PrometheusHistogramMetricsTrackerTest {
}
@Test
public void testMultiplePoolName() throws Exception {
String[] labelNames = {POOL_LABEL_NAME};
HikariConfig config = newHikariConfig();
config.setMetricsTrackerFactory(new PrometheusHistogramMetricsTrackerFactory(collectorRegistry));
config.setPoolName("first");
config.setJdbcUrl("jdbc:h2:mem:");
config.setMaximumPoolSize(2);
config.setConnectionTimeout(250);
String[] labelValues1 = {config.getPoolName()};
public void testMultiplePoolNameWithOneCollectorRegistry()
{
HikariConfig configFirstPool = newHikariConfig();
configFirstPool.setMetricsTrackerFactory(new PrometheusHistogramMetricsTrackerFactory(defaultCollectorRegistry));
configFirstPool.setPoolName("first");
configFirstPool.setJdbcUrl("jdbc:h2:mem:");
configFirstPool.setMaximumPoolSize(2);
configFirstPool.setConnectionTimeout(250);
HikariConfig configSecondPool = newHikariConfig();
configSecondPool.setMetricsTrackerFactory(new PrometheusHistogramMetricsTrackerFactory(defaultCollectorRegistry));
configSecondPool.setPoolName("second");
configSecondPool.setJdbcUrl("jdbc:h2:mem:");
configSecondPool.setMaximumPoolSize(4);
configSecondPool.setConnectionTimeout(250);
String[] labelValuesFirstPool = {configFirstPool.getPoolName()};
String[] labelValuesSecondPool = {configSecondPool.getPoolName()};
try (HikariDataSource ignoredFirstPool = new HikariDataSource(configFirstPool)) {
assertThat(defaultCollectorRegistry.getSampleValue(
"hikaricp_connection_timeout_total", LABEL_NAMES, labelValuesFirstPool),
is(0.0));
try (HikariDataSource ignoredSecondPool = new HikariDataSource(configSecondPool)) {
assertThat(defaultCollectorRegistry.getSampleValue(
"hikaricp_connection_timeout_total", LABEL_NAMES, labelValuesSecondPool),
is(0.0));
}
}
}
try (HikariDataSource ignored = new HikariDataSource(config)) {
assertThat(collectorRegistry.getSampleValue(
"hikaricp_connection_timeout_total",
labelNames,
labelValues1), is(0.0));
CollectorRegistry collectorRegistry2 = new CollectorRegistry();
HikariConfig config2 = newHikariConfig();
config2.setMetricsTrackerFactory(new PrometheusHistogramMetricsTrackerFactory(collectorRegistry2));
config2.setPoolName("second");
config2.setJdbcUrl("jdbc:h2:mem:");
config2.setMaximumPoolSize(4);
config2.setConnectionTimeout(250);
String[] labelValues2 = {config2.getPoolName()};
try (HikariDataSource ignored2 = new HikariDataSource(config2)) {
assertThat(collectorRegistry2.getSampleValue(
"hikaricp_connection_timeout_total",
labelNames,
labelValues2), is(0.0));
@Test
public void testMultiplePoolNameWithDifferentCollectorRegistries()
{
HikariConfig configFirstPool = newHikariConfig();
configFirstPool.setMetricsTrackerFactory(new PrometheusHistogramMetricsTrackerFactory(defaultCollectorRegistry));
configFirstPool.setPoolName("first");
configFirstPool.setJdbcUrl("jdbc:h2:mem:");
configFirstPool.setMaximumPoolSize(2);
configFirstPool.setConnectionTimeout(250);
HikariConfig configSecondPool = newHikariConfig();
configSecondPool.setMetricsTrackerFactory(new PrometheusHistogramMetricsTrackerFactory(customCollectorRegistry));
configSecondPool.setPoolName("second");
configSecondPool.setJdbcUrl("jdbc:h2:mem:");
configSecondPool.setMaximumPoolSize(4);
configSecondPool.setConnectionTimeout(250);
String[] labelValuesFirstPool = {configFirstPool.getPoolName()};
String[] labelValuesSecondPool = {configSecondPool.getPoolName()};
try (HikariDataSource ignoredFirstPool = new HikariDataSource(configFirstPool)) {
assertThat(defaultCollectorRegistry.getSampleValue(
"hikaricp_connection_timeout_total", LABEL_NAMES, labelValuesFirstPool),
is(0.0));
try (HikariDataSource ignoredSecondPool = new HikariDataSource(configSecondPool)) {
assertThat(customCollectorRegistry.getSampleValue(
"hikaricp_connection_timeout_total", LABEL_NAMES, labelValuesSecondPool),
is(0.0));
}
}
}
private void checkSummaryMetricFamily(String metricName) {
HikariConfig config = newHikariConfig();
config.setMetricsTrackerFactory(new PrometheusHistogramMetricsTrackerFactory(collectorRegistry));
config.setMetricsTrackerFactory(new PrometheusHistogramMetricsTrackerFactory(defaultCollectorRegistry));
config.setJdbcUrl("jdbc:h2:mem:");
try (HikariDataSource ignored = new HikariDataSource(config)) {
Double count = collectorRegistry.getSampleValue(
Double count = defaultCollectorRegistry.getSampleValue(
metricName + "_count",
new String[]{POOL_LABEL_NAME},
LABEL_NAMES,
new String[]{config.getPoolName()}
);
assertNotNull(count);
Double sum = collectorRegistry.getSampleValue(
Double sum = defaultCollectorRegistry.getSampleValue(
metricName + "_sum",
new String[]{POOL_LABEL_NAME},
LABEL_NAMES,
new String[]{config.getPoolName()}
);
assertNotNull(sum);

Loading…
Cancel
Save