Do not require DataSourcePoolMetrics to auto-configure Hikari meters

Closes gh-13330
This commit is contained in:
Andy Wilkinson 2018-06-01 17:55:43 +01:00
parent 27267a7090
commit 68cd27c47b
2 changed files with 103 additions and 45 deletions

View File

@ -50,44 +50,50 @@ import org.springframework.util.StringUtils;
@Configuration @Configuration
@AutoConfigureAfter({ MetricsAutoConfiguration.class, DataSourceAutoConfiguration.class, @AutoConfigureAfter({ MetricsAutoConfiguration.class, DataSourceAutoConfiguration.class,
SimpleMetricsExportAutoConfiguration.class }) SimpleMetricsExportAutoConfiguration.class })
@ConditionalOnBean({ DataSource.class, DataSourcePoolMetadataProvider.class, @ConditionalOnBean({ DataSource.class, MeterRegistry.class })
MeterRegistry.class })
public class DataSourcePoolMetricsAutoConfiguration { public class DataSourcePoolMetricsAutoConfiguration {
private static final String DATASOURCE_SUFFIX = "dataSource"; @Configuration
@ConditionalOnBean(DataSourcePoolMetadataProvider.class)
static class DataSourcePoolMetadataMetricsConfiguration {
private final MeterRegistry registry; private static final String DATASOURCE_SUFFIX = "dataSource";
private final Collection<DataSourcePoolMetadataProvider> metadataProviders; private final MeterRegistry registry;
public DataSourcePoolMetricsAutoConfiguration(MeterRegistry registry, private final Collection<DataSourcePoolMetadataProvider> metadataProviders;
Collection<DataSourcePoolMetadataProvider> metadataProviders) {
this.registry = registry;
this.metadataProviders = metadataProviders;
}
@Autowired DataSourcePoolMetadataMetricsConfiguration(MeterRegistry registry,
public void bindDataSourcesToRegistry(Map<String, DataSource> dataSources) { Collection<DataSourcePoolMetadataProvider> metadataProviders) {
dataSources.forEach(this::bindDataSourceToRegistry); this.registry = registry;
} this.metadataProviders = metadataProviders;
private void bindDataSourceToRegistry(String beanName, DataSource dataSource) {
String dataSourceName = getDataSourceName(beanName);
new DataSourcePoolMetrics(dataSource, this.metadataProviders, dataSourceName,
Collections.emptyList()).bindTo(this.registry);
}
/**
* Get the name of a DataSource based on its {@code beanName}.
* @param beanName the name of the data source bean
* @return a name for the given data source
*/
private String getDataSourceName(String beanName) {
if (beanName.length() > DATASOURCE_SUFFIX.length()
&& StringUtils.endsWithIgnoreCase(beanName, DATASOURCE_SUFFIX)) {
return beanName.substring(0, beanName.length() - DATASOURCE_SUFFIX.length());
} }
return beanName;
@Autowired
public void bindDataSourcesToRegistry(Map<String, DataSource> dataSources) {
dataSources.forEach(this::bindDataSourceToRegistry);
}
private void bindDataSourceToRegistry(String beanName, DataSource dataSource) {
String dataSourceName = getDataSourceName(beanName);
new DataSourcePoolMetrics(dataSource, this.metadataProviders, dataSourceName,
Collections.emptyList()).bindTo(this.registry);
}
/**
* Get the name of a DataSource based on its {@code beanName}.
* @param beanName the name of the data source bean
* @return a name for the given data source
*/
private String getDataSourceName(String beanName) {
if (beanName.length() > DATASOURCE_SUFFIX.length()
&& StringUtils.endsWithIgnoreCase(beanName, DATASOURCE_SUFFIX)) {
return beanName.substring(0,
beanName.length() - DATASOURCE_SUFFIX.length());
}
return beanName;
}
} }
@Configuration @Configuration

View File

@ -33,6 +33,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;
import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -53,22 +54,29 @@ public class DataSourcePoolMetricsAutoConfigurationTests {
private ApplicationContextRunner contextRunner = new ApplicationContextRunner() private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withPropertyValues("spring.datasource.generate-unique-name=true") .withPropertyValues("spring.datasource.generate-unique-name=true")
.with(MetricsRun.simple()) .with(MetricsRun.simple())
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, .withConfiguration(
DataSourcePoolMetricsAutoConfiguration.class)) AutoConfigurations.of(DataSourcePoolMetricsAutoConfiguration.class))
.withUserConfiguration(BaseConfiguration.class); .withUserConfiguration(BaseConfiguration.class);
@Test @Test
public void autoConfiguredDataSourceIsInstrumented() { public void autoConfiguredDataSourceIsInstrumented() {
this.contextRunner.run((context) -> { this.contextRunner
context.getBean(DataSource.class).getConnection().getMetaData(); .withConfiguration(
MeterRegistry registry = context.getBean(MeterRegistry.class); AutoConfigurations.of(DataSourceAutoConfiguration.class))
registry.get("jdbc.connections.max").tags("name", "dataSource").meter(); .run((context) -> {
}); context.getBean(DataSource.class).getConnection().getMetaData();
MeterRegistry registry = context.getBean(MeterRegistry.class);
registry.get("jdbc.connections.max").tags("name", "dataSource")
.meter();
});
} }
@Test @Test
public void dataSourceInstrumentationCanBeDisabled() { public void dataSourceInstrumentationCanBeDisabled() {
this.contextRunner.withPropertyValues("management.metrics.enable.jdbc=false") this.contextRunner
.withConfiguration(
AutoConfigurations.of(DataSourceAutoConfiguration.class))
.withPropertyValues("management.metrics.enable.jdbc=false")
.run((context) -> { .run((context) -> {
context.getBean(DataSource.class).getConnection().getMetaData(); context.getBean(DataSource.class).getConnection().getMetaData();
MeterRegistry registry = context.getBean(MeterRegistry.class); MeterRegistry registry = context.getBean(MeterRegistry.class);
@ -79,7 +87,10 @@ public class DataSourcePoolMetricsAutoConfigurationTests {
@Test @Test
public void allDataSourcesCanBeInstrumented() { public void allDataSourcesCanBeInstrumented() {
this.contextRunner.withUserConfiguration(TwoDataSourcesConfiguration.class) this.contextRunner
.withConfiguration(
AutoConfigurations.of(DataSourceAutoConfiguration.class))
.withUserConfiguration(TwoDataSourcesConfiguration.class)
.run((context) -> { .run((context) -> {
context.getBean("firstDataSource", DataSource.class).getConnection() context.getBean("firstDataSource", DataSource.class).getConnection()
.getMetaData(); .getMetaData();
@ -94,11 +105,14 @@ public class DataSourcePoolMetricsAutoConfigurationTests {
@Test @Test
public void autoConfiguredHikariDataSourceIsInstrumented() { public void autoConfiguredHikariDataSourceIsInstrumented() {
this.contextRunner.run((context) -> { this.contextRunner
context.getBean(DataSource.class).getConnection(); .withConfiguration(
MeterRegistry registry = context.getBean(MeterRegistry.class); AutoConfigurations.of(DataSourceAutoConfiguration.class))
registry.get("hikaricp.connections").meter(); .run((context) -> {
}); context.getBean(DataSource.class).getConnection();
MeterRegistry registry = context.getBean(MeterRegistry.class);
registry.get("hikaricp.connections").meter();
});
} }
@Test @Test
@ -106,6 +120,8 @@ public class DataSourcePoolMetricsAutoConfigurationTests {
this.contextRunner this.contextRunner
.withPropertyValues( .withPropertyValues(
"spring.datasource.schema:db/create-custom-schema.sql") "spring.datasource.schema:db/create-custom-schema.sql")
.withConfiguration(
AutoConfigurations.of(DataSourceAutoConfiguration.class))
.run((context) -> { .run((context) -> {
context.getBean(DataSource.class).getConnection(); context.getBean(DataSource.class).getConnection();
MeterRegistry registry = context.getBean(MeterRegistry.class); MeterRegistry registry = context.getBean(MeterRegistry.class);
@ -116,6 +132,8 @@ public class DataSourcePoolMetricsAutoConfigurationTests {
@Test @Test
public void hikariCanBeInstrumentedAfterThePoolHasBeenSealed() { public void hikariCanBeInstrumentedAfterThePoolHasBeenSealed() {
this.contextRunner.withUserConfiguration(HikariSealingConfiguration.class) this.contextRunner.withUserConfiguration(HikariSealingConfiguration.class)
.withConfiguration(
AutoConfigurations.of(DataSourceAutoConfiguration.class))
.run((context) -> { .run((context) -> {
assertThat(context).hasNotFailed(); assertThat(context).hasNotFailed();
context.getBean(DataSource.class).getConnection(); context.getBean(DataSource.class).getConnection();
@ -127,6 +145,8 @@ public class DataSourcePoolMetricsAutoConfigurationTests {
@Test @Test
public void hikariDataSourceInstrumentationCanBeDisabled() { public void hikariDataSourceInstrumentationCanBeDisabled() {
this.contextRunner.withPropertyValues("management.metrics.enable.hikaricp=false") this.contextRunner.withPropertyValues("management.metrics.enable.hikaricp=false")
.withConfiguration(
AutoConfigurations.of(DataSourceAutoConfiguration.class))
.run((context) -> { .run((context) -> {
context.getBean(DataSource.class).getConnection(); context.getBean(DataSource.class).getConnection();
MeterRegistry registry = context.getBean(MeterRegistry.class); MeterRegistry registry = context.getBean(MeterRegistry.class);
@ -137,6 +157,8 @@ public class DataSourcePoolMetricsAutoConfigurationTests {
@Test @Test
public void allHikariDataSourcesCanBeInstrumented() { public void allHikariDataSourcesCanBeInstrumented() {
this.contextRunner.withUserConfiguration(TwoHikariDataSourcesConfiguration.class) this.contextRunner.withUserConfiguration(TwoHikariDataSourcesConfiguration.class)
.withConfiguration(
AutoConfigurations.of(DataSourceAutoConfiguration.class))
.run((context) -> { .run((context) -> {
context.getBean("firstDataSource", DataSource.class).getConnection(); context.getBean("firstDataSource", DataSource.class).getConnection();
context.getBean("secondOne", DataSource.class).getConnection(); context.getBean("secondOne", DataSource.class).getConnection();
@ -151,6 +173,8 @@ public class DataSourcePoolMetricsAutoConfigurationTests {
@Test @Test
public void someHikariDataSourcesCanBeInstrumented() { public void someHikariDataSourcesCanBeInstrumented() {
this.contextRunner.withUserConfiguration(MixedDataSourcesConfiguration.class) this.contextRunner.withUserConfiguration(MixedDataSourcesConfiguration.class)
.withConfiguration(
AutoConfigurations.of(DataSourceAutoConfiguration.class))
.run((context) -> { .run((context) -> {
context.getBean("firstDataSource", DataSource.class).getConnection(); context.getBean("firstDataSource", DataSource.class).getConnection();
context.getBean("secondOne", DataSource.class).getConnection(); context.getBean("secondOne", DataSource.class).getConnection();
@ -161,6 +185,20 @@ public class DataSourcePoolMetricsAutoConfigurationTests {
}); });
} }
@Test
public void hikariDataSourceIsInstrumentedWithoutMetadataProvider() {
this.contextRunner.withUserConfiguration(OneHikariDataSourceConfiguration.class)
.run((context) -> {
assertThat(context)
.doesNotHaveBean(DataSourcePoolMetadataProvider.class);
context.getBean("hikariDataSource", DataSource.class).getConnection();
MeterRegistry registry = context.getBean(MeterRegistry.class);
assertThat(registry.get("hikaricp.connections").meter().getId()
.getTags())
.containsExactly(Tag.of("pool", "hikariDataSource"));
});
}
@Configuration @Configuration
static class BaseConfiguration { static class BaseConfiguration {
@ -214,6 +252,20 @@ public class DataSourcePoolMetricsAutoConfigurationTests {
} }
@Configuration
static class OneHikariDataSourceConfiguration {
@Bean
public DataSource hikariDataSource() {
String url = "jdbc:hsqldb:mem:test-" + UUID.randomUUID();
HikariDataSource hikariDataSource = DataSourceBuilder.create().url(url)
.type(HikariDataSource.class).build();
hikariDataSource.setPoolName("hikariDataSource");
return hikariDataSource;
}
}
@Configuration @Configuration
static class MixedDataSourcesConfiguration { static class MixedDataSourcesConfiguration {