diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/jdbc/DataSourcePoolMetrics.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/jdbc/DataSourcePoolMetrics.java index 1e3676c412..92cf4243b2 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/jdbc/DataSourcePoolMetrics.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/jdbc/DataSourcePoolMetrics.java @@ -66,6 +66,7 @@ public class DataSourcePoolMetrics implements MeterBinder { public void bindTo(MeterRegistry registry) { if (this.metadataProvider.getDataSourcePoolMetadata(this.dataSource) != null) { bindPoolMetadata(registry, "active", DataSourcePoolMetadata::getActive); + bindPoolMetadata(registry, "idle", DataSourcePoolMetadata::getIdle); bindPoolMetadata(registry, "max", DataSourcePoolMetadata::getMax); bindPoolMetadata(registry, "min", DataSourcePoolMetadata::getMin); } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index c2d2385d46..297b0cf05c 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -2023,8 +2023,8 @@ is required. A `CacheMetricsRegistrar` bean is made available to make that proce ==== DataSource Metrics Auto-configuration enables the instrumentation of all available `DataSource` objects with a metric named `jdbc`. Data source instrumentation results in gauges representing the -currently active, maximum allowed, and minimum allowed connections in the pool. Each of -these gauges has a name that is prefixed by `jdbc`. +currently active, idle, maximum allowed, and minimum allowed connections in the pool. Each +of these gauges has a name that is prefixed by `jdbc`. Metrics are also tagged by the name of the `DataSource` computed based on the bean name. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/metadata/CommonsDbcp2DataSourcePoolMetadata.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/metadata/CommonsDbcp2DataSourcePoolMetadata.java index ca1508fc8b..7262a45f1b 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/metadata/CommonsDbcp2DataSourcePoolMetadata.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/metadata/CommonsDbcp2DataSourcePoolMetadata.java @@ -37,6 +37,11 @@ public class CommonsDbcp2DataSourcePoolMetadata extends AbstractDataSourcePoolMe return getDataSource().getNumActive(); } + @Override + public Integer getIdle() { + return getDataSource().getNumIdle(); + } + @Override public Integer getMax() { return getDataSource().getMaxTotal(); diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/metadata/DataSourcePoolMetadata.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/metadata/DataSourcePoolMetadata.java index d0e7028dbc..6e8a2e7e67 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/metadata/DataSourcePoolMetadata.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/metadata/DataSourcePoolMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import javax.sql.DataSource; * {@link DataSource} implementations. * * @author Stephane Nicoll + * @author Artsiom Yudovin * @since 2.0.0 */ public interface DataSourcePoolMetadata { @@ -49,6 +50,17 @@ public interface DataSourcePoolMetadata { */ Integer getActive(); + /** + * Return the number of established but idle connections. Can also return {@code null} + * if that information is not available. + * @return the number of established but idle connections or {@code null} + * @since 2.2.0 + * @see #getActive() + */ + default Integer getIdle() { + return null; + } + /** * Return the maximum number of active connections that can be allocated at the same * time or {@code -1} if there is no limit. Can also return {@code null} if that diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/metadata/HikariDataSourcePoolMetadata.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/metadata/HikariDataSourcePoolMetadata.java index bd9b1f93f3..70a7af12a2 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/metadata/HikariDataSourcePoolMetadata.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/metadata/HikariDataSourcePoolMetadata.java @@ -45,6 +45,16 @@ public class HikariDataSourcePoolMetadata extends AbstractDataSourcePoolMetadata } } + @Override + public Integer getIdle() { + try { + return getHikariPool().getIdleConnections(); + } + catch (Exception ex) { + return null; + } + } + private HikariPool getHikariPool() { return (HikariPool) new DirectFieldAccessor(getDataSource()).getPropertyValue("pool"); } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/metadata/TomcatDataSourcePoolMetadata.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/metadata/TomcatDataSourcePoolMetadata.java index 4202315a5c..fc5d0bc707 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/metadata/TomcatDataSourcePoolMetadata.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/metadata/TomcatDataSourcePoolMetadata.java @@ -37,6 +37,11 @@ public class TomcatDataSourcePoolMetadata extends AbstractDataSourcePoolMetadata return (pool != null) ? pool.getActive() : 0; } + @Override + public Integer getIdle() { + return getDataSource().getNumIdle(); + } + @Override public Integer getMax() { return getDataSource().getMaxActive(); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/AbstractDataSourcePoolMetadataTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/AbstractDataSourcePoolMetadataTests.java index 5f43bf056b..c8023ad258 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/AbstractDataSourcePoolMetadataTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/AbstractDataSourcePoolMetadataTests.java @@ -29,11 +29,13 @@ import static org.assertj.core.api.Assertions.assertThat; * * @param the data source pool metadata type * @author Stephane Nicoll + * @author Artsiom Yudovin */ abstract class AbstractDataSourcePoolMetadataTests> { /** - * Return a data source metadata instance with a min size of 0 and max size of 2. + * Return a data source metadata instance with a min size of 0 and max size of 2. Idle + * connections are not reclaimed immediately. * @return the data source metadata */ protected abstract D getDataSourceMetadata(); @@ -67,6 +69,13 @@ abstract class AbstractDataSourcePoolMetadataTests) (connection) -> null); + assertThat(getDataSourceMetadata().getIdle()).isEqualTo(Integer.valueOf(1)); + } + @Test void getPoolSizeTwoConnections() { final JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSourceMetadata().getDataSource()); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/CommonsDbcp2DataSourcePoolMetadataTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/CommonsDbcp2DataSourcePoolMetadataTests.java index 5f4c911d1f..2207eb82a6 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/CommonsDbcp2DataSourcePoolMetadataTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/CommonsDbcp2DataSourcePoolMetadataTests.java @@ -83,6 +83,7 @@ class CommonsDbcp2DataSourcePoolMetadataTests BasicDataSource dataSource = createDataSource(); dataSource.setMinIdle(minSize); dataSource.setMaxTotal(maxSize); + dataSource.setMinEvictableIdleTimeMillis(5000); return new CommonsDbcp2DataSourcePoolMetadata(dataSource); } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/HikariDataSourcePoolMetadataTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/HikariDataSourcePoolMetadataTests.java index 70d91b248d..4618f6406b 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/HikariDataSourcePoolMetadataTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/HikariDataSourcePoolMetadataTests.java @@ -54,6 +54,7 @@ public class HikariDataSourcePoolMetadataTests HikariDataSource dataSource = initializeBuilder().type(HikariDataSource.class).build(); dataSource.setMinimumIdle(minSize); dataSource.setMaximumPoolSize(maxSize); + dataSource.setIdleTimeout(5000); return dataSource; } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/TomcatDataSourcePoolMetadataTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/TomcatDataSourcePoolMetadataTests.java index ca642b639f..50713417e0 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/TomcatDataSourcePoolMetadataTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/jdbc/metadata/TomcatDataSourcePoolMetadataTests.java @@ -54,6 +54,7 @@ public class TomcatDataSourcePoolMetadataTests DataSource dataSource = initializeBuilder().type(DataSource.class).build(); dataSource.setMinIdle(minSize); dataSource.setMaxActive(maxSize); + dataSource.setMinEvictableIdleTimeMillis(5000); // Avoid warnings dataSource.setInitialSize(minSize);