diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml
index ef0ecf425de..f8c2c72029a 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml
@@ -233,6 +233,11 @@
jersey-container-servlet-core
true
+
+ org.hibernate
+ hibernate-core
+ true
+
org.hibernate.validator
hibernate-validator
@@ -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..024e8278a06
--- /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,87 @@
+/*
+ * 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.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} 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 {
+
+ 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::bindEntityManagerFactoryToRegistry);
+ }
+
+ private void bindEntityManagerFactoryToRegistry(String beanName,
+ EntityManagerFactory entityManagerFactory) {
+ String entityManagerFactoryName = getEntityManagerFactoryName(beanName);
+ 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/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/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..beff4b29646
--- /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,201 @@
+/*
+ * 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);
+
+ @Test
+ public void autoConfiguredEntityManagerFactoryWithStatsIsInstrumented() {
+ 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
+ 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",
+ "spring.jpa.properties.hibernate.generate_statistics:true")
+ .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
+ .withPropertyValues(
+ "spring.jpa.properties.hibernate.generate_statistics:true")
+ .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
+ .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);
+ 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..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,6 +1768,27 @@ 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-hibernate]]
+==== Hibernate Metrics
+Auto-configuration enables the instrumentation of all available Hibernate
+`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
+the bean name.
+
+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:
+
+[source,properties,indent=0]
+----
+ spring.jpa.properties.hibernate.generate_statistics=true
+----
+
+
+
[[production-ready-metrics-rabbitmq]]
==== RabbitMQ Metrics
Auto-configuration will enable the instrumentation of all available RabbitMQ connection