From b6b92ba937e3a5aa86ae3ae1b4f45ea25824f05f Mon Sep 17 00:00:00 2001 From: Rui Figueira Date: Mon, 19 Mar 2018 20:34:28 +0000 Subject: [PATCH 1/2] Add auto-configuration for Hibernate metrics All Hibernate entityManagerFactories are automatically instrumented and their statistics are included into Micrometer using its HibernateMetrics binder. Closes gh-12550 --- .../pom.xml | 10 + .../HibernateMetricsAutoConfiguration.java | 89 ++++++++ .../main/resources/META-INF/spring.factories | 1 + ...ibernateMetricsAutoConfigurationTests.java | 191 ++++++++++++++++++ .../metrics/test/MetricsIntegrationTests.java | 2 + .../metrics/test/MetricsRun.java | 2 + .../asciidoc/production-ready-features.adoc | 19 ++ 7 files changed, 314 insertions(+) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml index ef0ecf425de..b0f71dccdc6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml @@ -172,6 +172,11 @@ javax.servlet-api true + + org.hibernate + hibernate-core + true + net.sf.ehcache ehcache @@ -440,6 +445,11 @@ jsonassert test + + org.springframework + spring-orm + test + org.springframework.data spring-data-elasticsearch diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java new file mode 100644 index 00000000000..d3150479c14 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java @@ -0,0 +1,89 @@ +/* + * Copyright 2012-2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa; + +import java.util.Collections; +import java.util.Map; + +import javax.persistence.EntityManagerFactory; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.binder.jpa.HibernateMetrics; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.StringUtils; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for metrics on all available + * Hibernate {@link EntityManagerFactory entityManagerFactories} with statistics enabled. + *

+ * {@link HibernateMetrics} can only monitor Hibernate {@link EntityManagerFactory} + * instances with statistics enabled (for instance, by setting JPA property + * hibernate.generate_statistics to true). + * + * @author Rui Figueira + */ +@Configuration +@AutoConfigureAfter({ MetricsAutoConfiguration.class, HibernateJpaAutoConfiguration.class, + SimpleMetricsExportAutoConfiguration.class }) +@ConditionalOnBean({ EntityManagerFactory.class, MeterRegistry.class }) +public class HibernateMetricsAutoConfiguration { + + private static final String ENTITY_MANAGER_FACTORY_SUFFIX = "entityManagerFactory"; + + private final MeterRegistry registry; + + public HibernateMetricsAutoConfiguration(MeterRegistry registry) { + this.registry = registry; + } + + @Autowired + public void bindEntityManagerFactoriesToRegistry( + Map entityManagerFactories) { + entityManagerFactories.forEach(this::maybeBindEntityManagerFactoryToRegistry); + } + + private void maybeBindEntityManagerFactoryToRegistry(String beanName, + EntityManagerFactory entityManagerFactory) { + String entityManagerFactoryName = getEntityManagerFactoryName(beanName); + // HibernateMetrics internally checks if statistics are enabled before binding + new HibernateMetrics(entityManagerFactory, entityManagerFactoryName, + Collections.emptyList()).bindTo(this.registry); + } + + /** + * Get the name of a {@link EntityManagerFactory} based on its {@code beanName}. + * @param beanName the name of the {@link EntityManagerFactory} bean + * @return a name for the given entity manager factory + */ + private String getEntityManagerFactoryName(String beanName) { + if (beanName.length() > ENTITY_MANAGER_FACTORY_SUFFIX.length() && StringUtils + .endsWithIgnoreCase(beanName, ENTITY_MANAGER_FACTORY_SUFFIX)) { + return beanName.substring(0, + beanName.length() - ENTITY_MANAGER_FACTORY_SUFFIX.length()); + } + return beanName; + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index 60dabb05a23..01ba105602e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -49,6 +49,7 @@ org.springframework.boot.actuate.autoconfigure.metrics.export.signalfx.SignalFxM org.springframework.boot.actuate.autoconfigure.metrics.export.statsd.StatsdMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront.WavefrontMetricsExportAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa.HibernateMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java new file mode 100644 index 00000000000..338b291aa68 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java @@ -0,0 +1,191 @@ +/* + * Copyright 2012-2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa; + +import java.util.HashMap; +import java.util.Map; + +import javax.persistence.Entity; +import javax.persistence.EntityManagerFactory; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.PersistenceException; +import javax.sql.DataSource; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import org.hibernate.SessionFactory; +import org.junit.Test; +import org.mockito.ArgumentMatchers; + +import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link HibernateMetricsAutoConfiguration}. + * + * @author Rui Figueira + */ +public class HibernateMetricsAutoConfigurationTests { + + private ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .with(MetricsRun.simple()) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + HibernateJpaAutoConfiguration.class, + HibernateMetricsAutoConfiguration.class)) + .withUserConfiguration(BaseConfiguration.class).withPropertyValues( + "spring.jpa.properties.hibernate.generate_statistics:true"); + + @Test + public void autoConfiguredEntityManagerFactoryWithStatsIsInstrumented() { + this.contextRunner.run((context) -> { + context.getBean(EntityManagerFactory.class).unwrap(SessionFactory.class); + MeterRegistry registry = context.getBean(MeterRegistry.class); + registry.get("hibernate.statements") + .tags("entityManagerFactory", "entityManagerFactory").meter(); + }); + } + + @Test + public void autoConfiguredEntityManagerFactoryWithoutStatsIsNotInstrumented() { + this.contextRunner + .withPropertyValues( + "spring.jpa.properties.hibernate.generate_statistics:false") + .run((context) -> { + context.getBean(EntityManagerFactory.class) + .unwrap(SessionFactory.class); + MeterRegistry registry = context.getBean(MeterRegistry.class); + assertThat(registry.find("hibernate.statements").meter()).isNull(); + }); + } + + @Test + public void entityManagerFactoryInstrumentationCanBeDisabled() { + this.contextRunner.withPropertyValues("management.metrics.enable.hibernate=false") + .run((context) -> { + context.getBean(EntityManagerFactory.class) + .unwrap(SessionFactory.class); + MeterRegistry registry = context.getBean(MeterRegistry.class); + assertThat(registry.find("hibernate.statements").meter()).isNull(); + }); + } + + @Test + public void allEntityManagerFactoriesCanBeInstrumented() { + this.contextRunner + .withUserConfiguration(TwoEntityManagerFactoriesConfiguration.class) + .run((context) -> { + context.getBean("firstEntityManagerFactory", + EntityManagerFactory.class).unwrap(SessionFactory.class); + context.getBean("secondOne", EntityManagerFactory.class) + .unwrap(SessionFactory.class); + MeterRegistry registry = context.getBean(MeterRegistry.class); + registry.get("hibernate.statements") + .tags("entityManagerFactory", "first").meter(); + registry.get("hibernate.statements") + .tags("entityManagerFactory", "secondOne").meter(); + }); + } + + @Test + public void entityManagerFactoryInstrumentationIsDisabledIfNotHibernateSessionFactory() { + this.contextRunner + .withUserConfiguration( + NonHibernateEntityManagerFactoryConfiguration.class) + .run((context) -> { + // ensure EntityManagerFactory is not an Hibernate SessionFactory + assertThatThrownBy(() -> context.getBean(EntityManagerFactory.class) + .unwrap(SessionFactory.class)) + .isInstanceOf(PersistenceException.class); + MeterRegistry registry = context.getBean(MeterRegistry.class); + assertThat(registry.find("hibernate.statements").meter()).isNull(); + }); + } + + @Configuration + static class BaseConfiguration { + + @Bean + public SimpleMeterRegistry simpleMeterRegistry() { + return new SimpleMeterRegistry(); + } + + } + + @Entity + static class MyEntity { + + @Id + @GeneratedValue + private Long id; + } + + @Configuration + static class TwoEntityManagerFactoriesConfiguration { + + private static final Class[] PACKAGE_CLASSES = new Class[] { + MyEntity.class }; + + @Primary + @Bean + public LocalContainerEntityManagerFactoryBean firstEntityManagerFactory( + DataSource ds) { + return createSessionFactory(ds); + } + + @Bean + public LocalContainerEntityManagerFactoryBean secondOne(DataSource ds) { + return createSessionFactory(ds); + } + + private LocalContainerEntityManagerFactoryBean createSessionFactory( + DataSource ds) { + Map jpaProperties = new HashMap<>(); + jpaProperties.put("hibernate.generate_statistics", "true"); + EntityManagerFactoryBuilder builder = new EntityManagerFactoryBuilder( + new HibernateJpaVendorAdapter(), jpaProperties, null); + return builder.dataSource(ds).packages(PACKAGE_CLASSES).build(); + } + } + + @Configuration + static class NonHibernateEntityManagerFactoryConfiguration { + + @Bean + public EntityManagerFactory entityManagerFactory() { + EntityManagerFactory mockedFactory = mock(EntityManagerFactory.class); + // enforces JPA contract + given(mockedFactory.unwrap(ArgumentMatchers.>any())) + .willThrow(PersistenceException.class); + return mockedFactory; + } + } +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java index 6a5beebe004..0abe5f1f4bb 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java @@ -38,6 +38,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfigu import org.springframework.boot.actuate.autoconfigure.metrics.amqp.RabbitMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.cache.CacheMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa.HibernateMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration; @@ -143,6 +144,7 @@ public class MetricsIntegrationTests { @ImportAutoConfiguration({ MetricsAutoConfiguration.class, RabbitMetricsAutoConfiguration.class, CacheMetricsAutoConfiguration.class, DataSourcePoolMetricsAutoConfiguration.class, + HibernateMetricsAutoConfiguration.class, RestTemplateMetricsAutoConfiguration.class, WebFluxMetricsAutoConfiguration.class, WebMvcMetricsAutoConfiguration.class, JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java index 67dffadea39..fa35d78a8ae 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java @@ -37,6 +37,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.signalfx.Si import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.statsd.StatsdMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa.HibernateMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration; @@ -75,6 +76,7 @@ public final class MetricsRun { MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class, RabbitMetricsAutoConfiguration.class, CacheMetricsAutoConfiguration.class, DataSourcePoolMetricsAutoConfiguration.class, + HibernateMetricsAutoConfiguration.class, RestTemplateMetricsAutoConfiguration.class, WebFluxMetricsAutoConfiguration.class, WebMvcMetricsAutoConfiguration.class); 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 1a4dd9cda79..71fae7e69d5 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 @@ -1774,6 +1774,25 @@ Auto-configuration will enable the instrumentation of all available RabbitMQ con factories with a metric named `rabbitmq`. +[[production-ready-metrics-hibernate]] +==== Hibernate Metrics +Auto-configuration enables the instrumentation of all available Hibernate +`EntityManagerFactory` objects that have statistics enabled with a metric named +`hibernate`. + +Metrics are also tagged by the name of the `EntityManagerFactory` that is derived from +the bean name. + +To enable statistics on Hibernate `EntityManagerFactory` instances, JPA property `hibernate.generate_statistics` must be set to `true`. For example, on the default +`EntityManagerFactory`, you need to set the following property: + +.application.properties +[source,properties,indent=0] +---- + spring.jpa.properties.hibernate.generate_statistics=true +---- + + [[production-ready-metrics-custom]] === Registering custom metrics From a85998f4c338639f130b5a4d821bd38847e42188 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 17 Apr 2018 13:41:42 +0200 Subject: [PATCH 2/2] Polish "Add auto-configuration for Hibernate metrics" Closes gh-12550 --- .../pom.xml | 10 +++---- .../HibernateMetricsAutoConfiguration.java | 14 ++++----- .../metrics/orm/jpa/package-info.java | 20 +++++++++++++ ...ibernateMetricsAutoConfigurationTests.java | 30 ++++++++++++------- .../asciidoc/production-ready-features.adoc | 24 ++++++++------- 5 files changed, 64 insertions(+), 34 deletions(-) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/package-info.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml index b0f71dccdc6..f8c2c72029a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml @@ -172,11 +172,6 @@ javax.servlet-api true - - org.hibernate - hibernate-core - true - net.sf.ehcache ehcache @@ -238,6 +233,11 @@ jersey-container-servlet-core true + + org.hibernate + hibernate-core + true + org.hibernate.validator hibernate-validator diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java index d3150479c14..024e8278a06 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfiguration.java @@ -30,23 +30,22 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.Simp import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.context.annotation.Configuration; import org.springframework.util.StringUtils; /** * {@link EnableAutoConfiguration Auto-configuration} for metrics on all available - * Hibernate {@link EntityManagerFactory entityManagerFactories} with statistics enabled. - *

- * {@link HibernateMetrics} can only monitor Hibernate {@link EntityManagerFactory} - * instances with statistics enabled (for instance, by setting JPA property - * hibernate.generate_statistics to true). + * Hibernate {@link EntityManagerFactory} instances that have statistics enabled. * * @author Rui Figueira + * @author Stephane Nicoll */ @Configuration @AutoConfigureAfter({ MetricsAutoConfiguration.class, HibernateJpaAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class }) +@ConditionalOnClass({ EntityManagerFactory.class, MeterRegistry.class }) @ConditionalOnBean({ EntityManagerFactory.class, MeterRegistry.class }) public class HibernateMetricsAutoConfiguration { @@ -61,13 +60,12 @@ public class HibernateMetricsAutoConfiguration { @Autowired public void bindEntityManagerFactoriesToRegistry( Map entityManagerFactories) { - entityManagerFactories.forEach(this::maybeBindEntityManagerFactoryToRegistry); + entityManagerFactories.forEach(this::bindEntityManagerFactoryToRegistry); } - private void maybeBindEntityManagerFactoryToRegistry(String beanName, + private void bindEntityManagerFactoryToRegistry(String beanName, EntityManagerFactory entityManagerFactory) { String entityManagerFactoryName = getEntityManagerFactoryName(beanName); - // HibernateMetrics internally checks if statistics are enabled before binding new HibernateMetrics(entityManagerFactory, entityManagerFactoryName, Collections.emptyList()).bindTo(this.registry); } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/package-info.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/package-info.java new file mode 100644 index 00000000000..ecb62032914 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2018 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Auto-configuration for JDBC metrics. + */ +package org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java index 338b291aa68..beff4b29646 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/orm/jpa/HibernateMetricsAutoConfigurationTests.java @@ -61,17 +61,18 @@ public class HibernateMetricsAutoConfigurationTests { .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, HibernateMetricsAutoConfiguration.class)) - .withUserConfiguration(BaseConfiguration.class).withPropertyValues( - "spring.jpa.properties.hibernate.generate_statistics:true"); + .withUserConfiguration(BaseConfiguration.class); @Test public void autoConfiguredEntityManagerFactoryWithStatsIsInstrumented() { - this.contextRunner.run((context) -> { - context.getBean(EntityManagerFactory.class).unwrap(SessionFactory.class); - MeterRegistry registry = context.getBean(MeterRegistry.class); - registry.get("hibernate.statements") - .tags("entityManagerFactory", "entityManagerFactory").meter(); - }); + this.contextRunner + .withPropertyValues( + "spring.jpa.properties.hibernate.generate_statistics:true") + .run((context) -> { + MeterRegistry registry = context.getBean(MeterRegistry.class); + registry.get("hibernate.statements") + .tags("entityManagerFactory", "entityManagerFactory").meter(); + }); } @Test @@ -89,7 +90,8 @@ public class HibernateMetricsAutoConfigurationTests { @Test public void entityManagerFactoryInstrumentationCanBeDisabled() { - this.contextRunner.withPropertyValues("management.metrics.enable.hibernate=false") + this.contextRunner.withPropertyValues("management.metrics.enable.hibernate=false", + "spring.jpa.properties.hibernate.generate_statistics:true") .run((context) -> { context.getBean(EntityManagerFactory.class) .unwrap(SessionFactory.class); @@ -101,6 +103,8 @@ public class HibernateMetricsAutoConfigurationTests { @Test public void allEntityManagerFactoriesCanBeInstrumented() { this.contextRunner + .withPropertyValues( + "spring.jpa.properties.hibernate.generate_statistics:true") .withUserConfiguration(TwoEntityManagerFactoriesConfiguration.class) .run((context) -> { context.getBean("firstEntityManagerFactory", @@ -118,13 +122,15 @@ public class HibernateMetricsAutoConfigurationTests { @Test public void entityManagerFactoryInstrumentationIsDisabledIfNotHibernateSessionFactory() { this.contextRunner + .withPropertyValues( + "spring.jpa.properties.hibernate.generate_statistics:true") .withUserConfiguration( NonHibernateEntityManagerFactoryConfiguration.class) .run((context) -> { // ensure EntityManagerFactory is not an Hibernate SessionFactory assertThatThrownBy(() -> context.getBean(EntityManagerFactory.class) .unwrap(SessionFactory.class)) - .isInstanceOf(PersistenceException.class); + .isInstanceOf(PersistenceException.class); MeterRegistry registry = context.getBean(MeterRegistry.class); assertThat(registry.find("hibernate.statements").meter()).isNull(); }); @@ -146,6 +152,7 @@ public class HibernateMetricsAutoConfigurationTests { @Id @GeneratedValue private Long id; + } @Configuration @@ -174,6 +181,7 @@ public class HibernateMetricsAutoConfigurationTests { new HibernateJpaVendorAdapter(), jpaProperties, null); return builder.dataSource(ds).packages(PACKAGE_CLASSES).build(); } + } @Configuration @@ -187,5 +195,7 @@ public class HibernateMetricsAutoConfigurationTests { .willThrow(PersistenceException.class); return mockedFactory; } + } + } 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 71fae7e69d5..e006f6f37dd 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 @@ -1768,32 +1768,34 @@ Also, Hikari-specific metrics are exposed with a `hikaricp` prefix. Each metric by the name of the Pool (can be controlled with `spring.datasource.name`). -[[production-ready-metrics-rabbitmq]] -==== RabbitMQ Metrics -Auto-configuration will enable the instrumentation of all available RabbitMQ connection -factories with a metric named `rabbitmq`. - [[production-ready-metrics-hibernate]] ==== Hibernate Metrics Auto-configuration enables the instrumentation of all available Hibernate -`EntityManagerFactory` objects that have statistics enabled with a metric named +`EntityManagerFactory` instances that have statistics enabled with a metric named `hibernate`. -Metrics are also tagged by the name of the `EntityManagerFactory` that is derived from +Metrics are also tagged by the name of the `EntityManagerFactory` that is derived from the bean name. -To enable statistics on Hibernate `EntityManagerFactory` instances, JPA property `hibernate.generate_statistics` must be set to `true`. For example, on the default -`EntityManagerFactory`, you need to set the following property: +To enable statistics, the standardJPA property `hibernate.generate_statistics` must be +set to `true`. You can enable that on the auto-configured `EntityManagerFactory` as shown +in the following example: -.application.properties [source,properties,indent=0] ---- - spring.jpa.properties.hibernate.generate_statistics=true + spring.jpa.properties.hibernate.generate_statistics=true ---- +[[production-ready-metrics-rabbitmq]] +==== RabbitMQ Metrics +Auto-configuration will enable the instrumentation of all available RabbitMQ connection +factories with a metric named `rabbitmq`. + + + [[production-ready-metrics-custom]] === Registering custom metrics To register custom metrics, inject `MeterRegistry` into your component, as shown in the