From b569918db1c33847ce1d1464d7d78f692f289e99 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 28 Jul 2015 16:27:56 +0200 Subject: [PATCH] Add property to disable default health indicators Add a "management.health.defaults.enabled" property that controls whether the default health indicators are enabled. This allow to disable them all by default and still enable individual ones using their respective specific property. Closes gh-2298 --- .../ConditionalOnEnablednHealthIndicator.java | 47 ++++++++++ .../HealthIndicatorAutoConfiguration.java | 19 ++-- .../OnEnabledHealthIndicatorCondition.java | 69 ++++++++++++++ ...itional-spring-configuration-metadata.json | 6 ++ ...HealthIndicatorAutoConfigurationTests.java | 91 +++++++++++++------ .../appendix-application-properties.adoc | 1 + .../asciidoc/production-ready-features.adoc | 2 + 7 files changed, 195 insertions(+), 40 deletions(-) create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ConditionalOnEnablednHealthIndicator.java create mode 100644 spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledHealthIndicatorCondition.java diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ConditionalOnEnablednHealthIndicator.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ConditionalOnEnablednHealthIndicator.java new file mode 100644 index 00000000000..9fc81792ca8 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ConditionalOnEnablednHealthIndicator.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2015 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; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Conditional; + +/** + * {@link Conditional} that checks whether or not a default health indicator is enabled. + * Matches if the value of the {@code management.health..enabled} property is + * {@code true}. Otherwise , matches if the value of the + * {@code management.health.defaults.enabled} property is {@code true} or if it is not + * configured. + * + * @author Stephane Nicoll + * @since 1.3.0 + */ +@Conditional(OnEnabledHealthIndicatorCondition.class) +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +public @interface ConditionalOnEnablednHealthIndicator { + + /** + * The name of the health indicator. + * @return the name of the health indicator + */ + String value(); + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java index e5c37cfc196..2e9ec60eb4f 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfiguration.java @@ -49,7 +49,6 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadata; @@ -151,7 +150,7 @@ public class HealthIndicatorAutoConfiguration { @Configuration @ConditionalOnBean(DataSource.class) - @ConditionalOnProperty(prefix = "management.health.db", name = "enabled", matchIfMissing = true) + @ConditionalOnEnablednHealthIndicator("db") public static class DataSourcesHealthIndicatorConfiguration extends CompositeHealthIndicatorConfiguration implements InitializingBean { @@ -191,7 +190,7 @@ public class HealthIndicatorAutoConfiguration { @Configuration @ConditionalOnBean(MongoTemplate.class) - @ConditionalOnProperty(prefix = "management.health.mongo", name = "enabled", matchIfMissing = true) + @ConditionalOnEnablednHealthIndicator("mongo") public static class MongoHealthIndicatorConfiguration extends CompositeHealthIndicatorConfiguration { @@ -208,7 +207,7 @@ public class HealthIndicatorAutoConfiguration { @Configuration @ConditionalOnBean(RedisConnectionFactory.class) - @ConditionalOnProperty(prefix = "management.health.redis", name = "enabled", matchIfMissing = true) + @ConditionalOnEnablednHealthIndicator("redis") public static class RedisHealthIndicatorConfiguration extends CompositeHealthIndicatorConfiguration { @@ -226,7 +225,7 @@ public class HealthIndicatorAutoConfiguration { @Configuration @ConditionalOnBean(RabbitTemplate.class) - @ConditionalOnProperty(prefix = "management.health.rabbit", name = "enabled", matchIfMissing = true) + @ConditionalOnEnablednHealthIndicator("rabbit") public static class RabbitHealthIndicatorConfiguration extends CompositeHealthIndicatorConfiguration { @@ -243,7 +242,7 @@ public class HealthIndicatorAutoConfiguration { @Configuration @ConditionalOnBean(SolrServer.class) - @ConditionalOnProperty(prefix = "management.health.solr", name = "enabled", matchIfMissing = true) + @ConditionalOnEnablednHealthIndicator("solr") public static class SolrHealthIndicatorConfiguration extends CompositeHealthIndicatorConfiguration { @@ -259,7 +258,7 @@ public class HealthIndicatorAutoConfiguration { } @Configuration - @ConditionalOnProperty(prefix = "management.health.diskspace", name = "enabled", matchIfMissing = true) + @ConditionalOnEnablednHealthIndicator("diskspace") public static class DiskSpaceHealthIndicatorConfiguration { @Bean @@ -278,7 +277,7 @@ public class HealthIndicatorAutoConfiguration { @Configuration @ConditionalOnBean(JavaMailSenderImpl.class) - @ConditionalOnProperty(prefix = "management.health.mail", name = "enabled", matchIfMissing = true) + @ConditionalOnEnablednHealthIndicator("mail") public static class MailHealthIndicatorConfiguration extends CompositeHealthIndicatorConfiguration { @@ -296,7 +295,7 @@ public class HealthIndicatorAutoConfiguration { @Configuration @ConditionalOnBean(ConnectionFactory.class) - @ConditionalOnProperty(prefix = "management.health.jms", name = "enabled", matchIfMissing = true) + @ConditionalOnEnablednHealthIndicator("jms") public static class JmsHealthIndicatorConfiguration extends CompositeHealthIndicatorConfiguration { @@ -313,7 +312,7 @@ public class HealthIndicatorAutoConfiguration { @Configuration @ConditionalOnBean(Client.class) - @ConditionalOnProperty(prefix = "management.health.elasticsearch", name = "enabled", matchIfMissing = true) + @ConditionalOnEnablednHealthIndicator("elasticsearch") @EnableConfigurationProperties(ElasticsearchHealthIndicatorProperties.class) public static class ElasticsearchHealthIndicatorConfiguration extends CompositeHealthIndicatorConfiguration { diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledHealthIndicatorCondition.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledHealthIndicatorCondition.java new file mode 100644 index 00000000000..8be076a6899 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledHealthIndicatorCondition.java @@ -0,0 +1,69 @@ +/* + * Copyright 2012-2015 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; + +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.boot.bind.RelaxedPropertyResolver; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.type.AnnotatedTypeMetadata; + +/** + * {@link Condition} that checks if a health indicator is enabled. + * + * @author Stephane Nicoll + * @since 1.3.0 + */ +class OnEnabledHealthIndicatorCondition extends SpringBootCondition { + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { + AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(metadata + .getAnnotationAttributes(ConditionalOnEnablednHealthIndicator.class.getName())); + + String endpointName = annotationAttributes.getString("value"); + ConditionOutcome outcome = determineHealthIndicatorOutcome(endpointName, context); + if (outcome != null) { + return outcome; + } + return determineDefaultIndicatorsOutcome(context); + } + + private ConditionOutcome determineHealthIndicatorOutcome(String endpointName, + ConditionContext context) { + RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( + context.getEnvironment(), "management.health." + endpointName + "."); + if (resolver.containsProperty("enabled")) { + boolean match = resolver.getProperty("enabled", Boolean.class, + true); + return new ConditionOutcome(match, "The health indicator " + endpointName + + " is " + (match ? "enabled" : "disabled")); + } + return null; + } + + private ConditionOutcome determineDefaultIndicatorsOutcome(ConditionContext context) { + RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( + context.getEnvironment(), "management.health.defaults."); + boolean match = Boolean.valueOf(resolver.getProperty("enabled", "true")); + return new ConditionOutcome(match, "All default health indicators are " + + (match ? "enabled" : "disabled") + " by default"); + } + +} diff --git a/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json index b871e2f7841..b44a288420b 100644 --- a/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -58,6 +58,12 @@ "description": "Enable database health check.", "defaultValue": true }, + { + "name": "management.health.defaults.enabled", + "type": "java.lang.Boolean", + "description": "Enable default health indicators.", + "defaultValue": true + }, { "name": "management.health.diskspace.enabled", "type": "java.lang.Boolean", diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java index 44acde2eb6a..52fd7bf9182 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java @@ -17,16 +17,15 @@ package org.springframework.boot.actuate.autoconfigure; import java.util.Map; - import javax.sql.DataSource; import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.springframework.boot.actuate.health.ApplicationHealthIndicator; import org.springframework.boot.actuate.health.DataSourceHealthIndicator; import org.springframework.boot.actuate.health.DiskSpaceHealthIndicator; import org.springframework.boot.actuate.health.ElasticsearchHealthIndicator; +import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.JmsHealthIndicator; import org.springframework.boot.actuate.health.MailHealthIndicator; @@ -55,6 +54,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; /** * Tests for {@link HealthIndicatorAutoConfiguration}. @@ -65,14 +65,7 @@ import static org.junit.Assert.assertEquals; */ public class HealthIndicatorAutoConfigurationTests { - private AnnotationConfigApplicationContext context; - - @Before - public void setup() { - this.context = new AnnotationConfigApplicationContext(); - this.context.register(EndpointAutoConfiguration.class); - this.context.refresh(); - } + private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); @After public void close() { @@ -83,7 +76,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void defaultHealthIndicator() { - this.context = new AnnotationConfigApplicationContext(); this.context.register(HealthIndicatorAutoConfiguration.class, ManagementServerProperties.class); EnvironmentTestUtils.addEnvironment(this.context, @@ -96,9 +88,52 @@ public class HealthIndicatorAutoConfigurationTests { .getClass()); } + @Test + public void defaultHealthIndicatorsDisabled() { + this.context.register(HealthIndicatorAutoConfiguration.class, + ManagementServerProperties.class); + EnvironmentTestUtils.addEnvironment(this.context, + "management.health.defaults.enabled:false"); + this.context.refresh(); + Map beans = this.context + .getBeansOfType(HealthIndicator.class); + assertEquals(1, beans.size()); + assertEquals(ApplicationHealthIndicator.class, beans.values().iterator().next() + .getClass()); + } + + @Test + public void defaultHealthIndicatorsDisabledWithCustomOne() { + this.context.register(CustomHealthIndicator.class, + HealthIndicatorAutoConfiguration.class, + ManagementServerProperties.class); + EnvironmentTestUtils.addEnvironment(this.context, + "management.health.defaults.enabled:false"); + this.context.refresh(); + Map beans = this.context + .getBeansOfType(HealthIndicator.class); + assertEquals(1, beans.size()); + assertSame(this.context.getBean("customHealthIndicator"), beans.values(). + iterator().next()); + } + + @Test + public void defaultHealthIndicatorsDisabledButOne() { + this.context.register(HealthIndicatorAutoConfiguration.class, + ManagementServerProperties.class); + EnvironmentTestUtils.addEnvironment(this.context, + "management.health.enabled:false", + "management.health.diskspace.enabled:true"); + this.context.refresh(); + Map beans = this.context + .getBeansOfType(HealthIndicator.class); + assertEquals(1, beans.size()); + assertEquals(DiskSpaceHealthIndicator.class, beans.values().iterator().next() + .getClass()); + } + @Test public void redisHealthIndicator() { - this.context = new AnnotationConfigApplicationContext(); this.context.register(RedisAutoConfiguration.class, ManagementServerProperties.class, HealthIndicatorAutoConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, @@ -113,7 +148,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void notRedisHealthIndicator() { - this.context = new AnnotationConfigApplicationContext(); this.context.register(RedisAutoConfiguration.class, ManagementServerProperties.class, HealthIndicatorAutoConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, @@ -129,7 +163,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void mongoHealthIndicator() { - this.context = new AnnotationConfigApplicationContext(); this.context.register(MongoAutoConfiguration.class, ManagementServerProperties.class, MongoDataAutoConfiguration.class, HealthIndicatorAutoConfiguration.class); @@ -145,7 +178,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void notMongoHealthIndicator() { - this.context = new AnnotationConfigApplicationContext(); this.context.register(MongoAutoConfiguration.class, ManagementServerProperties.class, MongoDataAutoConfiguration.class, HealthIndicatorAutoConfiguration.class); @@ -162,7 +194,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void combinedHealthIndicator() { - this.context = new AnnotationConfigApplicationContext(); this.context.register(MongoAutoConfiguration.class, RedisAutoConfiguration.class, MongoDataAutoConfiguration.class, SolrAutoConfiguration.class, HealthIndicatorAutoConfiguration.class); @@ -174,7 +205,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void dataSourceHealthIndicator() { - this.context = new AnnotationConfigApplicationContext(); this.context.register(EmbeddedDataSourceConfiguration.class, ManagementServerProperties.class, HealthIndicatorAutoConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, @@ -189,7 +219,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void dataSourceHealthIndicatorWithCustomValidationQuery() { - this.context = new AnnotationConfigApplicationContext(); this.context.register(PropertyPlaceholderAutoConfiguration.class, ManagementServerProperties.class, DataSourceProperties.class, DataSourceConfig.class, @@ -210,7 +239,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void notDataSourceHealthIndicator() { - this.context = new AnnotationConfigApplicationContext(); this.context.register(EmbeddedDataSourceConfiguration.class, ManagementServerProperties.class, HealthIndicatorAutoConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, @@ -226,7 +254,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void rabbitHealthIndicator() { - this.context = new AnnotationConfigApplicationContext(); this.context.register(RabbitAutoConfiguration.class, ManagementServerProperties.class, HealthIndicatorAutoConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, @@ -241,7 +268,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void notRabbitHealthIndicator() { - this.context = new AnnotationConfigApplicationContext(); this.context.register(RabbitAutoConfiguration.class, ManagementServerProperties.class, HealthIndicatorAutoConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, @@ -257,7 +283,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void solrHeathIndicator() { - this.context = new AnnotationConfigApplicationContext(); this.context.register(SolrAutoConfiguration.class, ManagementServerProperties.class, HealthIndicatorAutoConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, @@ -272,7 +297,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void notSolrHeathIndicator() { - this.context = new AnnotationConfigApplicationContext(); this.context.register(SolrAutoConfiguration.class, ManagementServerProperties.class, HealthIndicatorAutoConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, @@ -288,7 +312,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void diskSpaceHealthIndicator() { - this.context = new AnnotationConfigApplicationContext(); this.context.register(HealthIndicatorAutoConfiguration.class); this.context.refresh(); Map beans = this.context @@ -300,7 +323,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void mailHealthIndicator() { - this.context = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(this.context, "spring.mail.host:smtp.acme.org", "management.health.diskspace.enabled:false"); @@ -317,7 +339,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void notMailHealthIndicator() { - this.context = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(this.context, "spring.mail.host:smtp.acme.org", "management.health.mail.enabled:false", "management.health.diskspace.enabled:false"); @@ -334,7 +355,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void jmsHealthIndicator() { - this.context = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(this.context, "management.health.diskspace.enabled:false"); this.context.register(ActiveMQAutoConfiguration.class, @@ -350,7 +370,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void notJmsHealthIndicator() { - this.context = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(this.context, "management.health.jms.enabled:false", "management.health.diskspace.enabled:false"); @@ -367,7 +386,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void elasticSearchHealthIndicator() { - this.context = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(this.context, "spring.data.elasticsearch.properties.path.data:target/data", "spring.data.elasticsearch.properties.path.logs:target/logs", @@ -385,7 +403,6 @@ public class HealthIndicatorAutoConfigurationTests { @Test public void notElasticSearchHealthIndicator() { - this.context = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(this.context, "management.health.elasticsearch.enabled:false", "spring.data.elasticsearch.properties.path.data:target/data", @@ -416,4 +433,18 @@ public class HealthIndicatorAutoConfigurationTests { } + @Configuration + protected static class CustomHealthIndicator { + + @Bean + public HealthIndicator customHealthIndicator() { + return new HealthIndicator() { + @Override + public Health health() { + return Health.down().build(); + } + }; + } + } + } diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 6190bffc7aa..b2667875c17 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -716,6 +716,7 @@ content into your application; rather pick only the properties that you need. management.health.elasticsearch.enabled=true management.health.elasticsearch.indices= # comma-separated index names management.health.elasticsearch.response-timeout=100 # the time, in milliseconds, to wait for a response from the cluster + management.health.defaults.enabled=true # enable default health indicators management.health.diskspace.enabled=true management.health.diskspace.path=. management.health.diskspace.threshold=10485760 diff --git a/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index bae135bd3d3..579b79391bc 100644 --- a/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -260,6 +260,8 @@ The following `HealthIndicators` are auto-configured by Spring Boot when appropr |Checks that a Solr server is up. |=== +TIP: It is possible to disable them all using the `management.health.defaults.enabled` +property. ==== Writing custom HealthIndicators