From a9a57e59515b5634b5565ad1d03326188dd90468 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Sun, 28 Apr 2019 14:58:39 +0300 Subject: [PATCH] Hacking See gh-14022 --- ...althEndpointWebExtensionConfiguration.java | 6 +-- .../HealthIndicatorAutoConfiguration.java | 47 +++++++++++++++-- .../health/HealthIndicatorProperties.java | 52 +++++++++++++------ .../health/DefaultGroupHealthIndicator.java | 32 ++++++++++++ .../DefaultGroupReactiveHealthIndicator.java | 33 ++++++++++++ .../DefaultHealthIndicatorRegistry.java | 9 +++- ...efaultReactiveHealthIndicatorRegistry.java | 9 +++- .../actuate/health/GroupHealthIndicator.java | 25 +++++++++ .../health/GroupReactiveHealthIndicator.java | 24 +++++++++ .../src/main/resources/application.properties | 9 ++++ 10 files changed, 219 insertions(+), 27 deletions(-) create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultGroupHealthIndicator.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultGroupReactiveHealthIndicator.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/GroupHealthIndicator.java create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/GroupReactiveHealthIndicator.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java index 77c2602c8c37..118b5ad3c56d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java @@ -51,10 +51,10 @@ class HealthEndpointWebExtensionConfiguration { @Bean @ConditionalOnMissingBean public HealthStatusHttpMapper createHealthStatusHttpMapper( - HealthIndicatorProperties healthIndicatorProperties) { + HealthIndicatorProperties properties) { HealthStatusHttpMapper statusHttpMapper = new HealthStatusHttpMapper(); - if (healthIndicatorProperties.getHttpMapping() != null) { - statusHttpMapper.addStatusMapping(healthIndicatorProperties.getHttpMapping()); + if (properties.getStatus().getHttpMapping() != null) { + statusHttpMapper.addStatusMapping(properties.getStatus().getHttpMapping()); } return statusHttpMapper; } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java index 0ab5521bfdaa..0cab7d4d6c13 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorAutoConfiguration.java @@ -16,11 +16,15 @@ package org.springframework.boot.actuate.autoconfigure.health; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.function.Function; import reactor.core.publisher.Flux; import org.springframework.boot.actuate.health.ApplicationHealthIndicator; +import org.springframework.boot.actuate.health.DefaultGroupHealthIndicator; +import org.springframework.boot.actuate.health.DefaultGroupReactiveHealthIndicator; import org.springframework.boot.actuate.health.HealthAggregator; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.HealthIndicatorRegistry; @@ -60,8 +64,8 @@ public ApplicationHealthIndicator applicationHealthIndicator() { public OrderedHealthAggregator healthAggregator( HealthIndicatorProperties properties) { OrderedHealthAggregator healthAggregator = new OrderedHealthAggregator(); - if (properties.getOrder() != null) { - healthAggregator.setStatusOrder(properties.getOrder()); + if (properties.getStatus().getOrder() != null) { + healthAggregator.setStatusOrder(properties.getStatus().getOrder()); } return healthAggregator; } @@ -69,8 +73,15 @@ public OrderedHealthAggregator healthAggregator( @Bean @ConditionalOnMissingBean(HealthIndicatorRegistry.class) public HealthIndicatorRegistry healthIndicatorRegistry( + HealthIndicatorProperties properties, HealthAggregator healthAggregator, ApplicationContext applicationContext) { - return HealthIndicatorRegistryBeans.get(applicationContext); + HealthIndicatorRegistry registry = HealthIndicatorRegistryBeans + .get(applicationContext); + extractGroups(properties, registry::get).forEach( + (groupName, groupHealthIndicators) -> registry.register(groupName, + new DefaultGroupHealthIndicator(healthAggregator, + groupHealthIndicators))); + return registry; } @Configuration(proxyBeanMethods = false) @@ -80,13 +91,41 @@ static class ReactiveHealthIndicatorConfiguration { @Bean @ConditionalOnMissingBean public ReactiveHealthIndicatorRegistry reactiveHealthIndicatorRegistry( + HealthIndicatorProperties properties, HealthAggregator healthAggregator, Map reactiveHealthIndicators, Map healthIndicators) { - return new ReactiveHealthIndicatorRegistryFactory() + ReactiveHealthIndicatorRegistry registry = new ReactiveHealthIndicatorRegistryFactory() .createReactiveHealthIndicatorRegistry(reactiveHealthIndicators, healthIndicators); + extractGroups(properties, registry::get).forEach( + (groupName, groupHealthIndicators) -> registry.register(groupName, + new DefaultGroupReactiveHealthIndicator(healthAggregator, + groupHealthIndicators))); + return registry; } } + private static Map> extractGroups( + HealthIndicatorProperties properties, + Function healthIndicatorByName) { + Map> groupDefinitions = new LinkedHashMap<>(); + properties.getGroups().forEach((groupName, indicatorNames) -> { + if (healthIndicatorByName.apply(groupName) != null) { + throw new IllegalArgumentException( + "Could not register health indicator group named '" + groupName + + "', an health indicator with that name is already registered"); + } + Map groupHealthIndicators = new LinkedHashMap<>(); + indicatorNames.forEach((name) -> { + T healthIndicator = healthIndicatorByName.apply(name); + if (healthIndicator != null) { + groupHealthIndicators.put(name, healthIndicator); + } + }); + groupDefinitions.put(groupName, groupHealthIndicators); + }); + return groupDefinitions; + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorProperties.java index 0f4d48545927..3c1bc53d52dd 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthIndicatorProperties.java @@ -28,32 +28,52 @@ * @author Christian Dupuis * @since 2.0.0 */ -@ConfigurationProperties(prefix = "management.health.status") +@ConfigurationProperties(prefix = "management.health") public class HealthIndicatorProperties { /** - * Comma-separated list of health statuses in order of severity. + * Health indicator groups. Each entry maps the name of a group with a list of health + * indicators to associate with the group. */ - private List order = null; + private final Map> groups = new HashMap<>(); - /** - * Mapping of health statuses to HTTP status codes. By default, registered health - * statuses map to sensible defaults (for example, UP maps to 200). - */ - private final Map httpMapping = new HashMap<>(); + private final Status status = new Status(); - public List getOrder() { - return this.order; + public Map> getGroups() { + return this.groups; } - public void setOrder(List statusOrder) { - if (statusOrder != null && !statusOrder.isEmpty()) { - this.order = statusOrder; - } + public Status getStatus() { + return this.status; } - public Map getHttpMapping() { - return this.httpMapping; + public static class Status { + + /** + * Comma-separated list of health statuses in order of severity. + */ + private List order = null; + + /** + * Mapping of health statuses to HTTP status codes. By default, registered health + * statuses map to sensible defaults (for example, UP maps to 200). + */ + private final Map httpMapping = new HashMap<>(); + + public List getOrder() { + return this.order; + } + + public void setOrder(List statusOrder) { + if (statusOrder != null && !statusOrder.isEmpty()) { + this.order = statusOrder; + } + } + + public Map getHttpMapping() { + return this.httpMapping; + } + } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultGroupHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultGroupHealthIndicator.java new file mode 100644 index 000000000000..ae8c386cd801 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultGroupHealthIndicator.java @@ -0,0 +1,32 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * https://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.health; + +import java.util.Map; + +/** + * @author Stephane Nicoll + */ +public class DefaultGroupHealthIndicator extends CompositeHealthIndicator + implements GroupHealthIndicator { + + public DefaultGroupHealthIndicator(HealthAggregator healthAggregator, + Map indicators) { + super(healthAggregator, indicators); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultGroupReactiveHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultGroupReactiveHealthIndicator.java new file mode 100644 index 000000000000..fc9fd2ea724a --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultGroupReactiveHealthIndicator.java @@ -0,0 +1,33 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * https://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.health; + +import java.util.Map; + +/** + * @author Stephane Nicoll + */ +public class DefaultGroupReactiveHealthIndicator extends CompositeReactiveHealthIndicator + implements GroupReactiveHealthIndicator { + + public DefaultGroupReactiveHealthIndicator(HealthAggregator healthAggregator, + Map healthIndicators) { + super(healthAggregator, + new DefaultReactiveHealthIndicatorRegistry(healthIndicators)); + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistry.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistry.java index 0f16f7740b44..bb3dd2be7515 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistry.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultHealthIndicatorRegistry.java @@ -85,8 +85,13 @@ public HealthIndicator get(String name) { @Override public Map getAll() { synchronized (this.monitor) { - return Collections - .unmodifiableMap(new LinkedHashMap<>(this.healthIndicators)); + Map allIndicators = new LinkedHashMap<>(); + this.healthIndicators.forEach((name, indicator) -> { + if (!(indicator instanceof GroupHealthIndicator)) { + allIndicators.put(name, indicator); + } + }); + return Collections.unmodifiableMap(allIndicators); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistry.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistry.java index b86e41febeac..958c7b59a3fe 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistry.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/DefaultReactiveHealthIndicatorRegistry.java @@ -88,8 +88,13 @@ public ReactiveHealthIndicator get(String name) { @Override public Map getAll() { synchronized (this.monitor) { - return Collections - .unmodifiableMap(new LinkedHashMap<>(this.healthIndicators)); + Map allIndicators = new LinkedHashMap<>(); + this.healthIndicators.forEach((name, indicator) -> { + if (!(indicator instanceof GroupReactiveHealthIndicator)) { + allIndicators.put(name, indicator); + } + }); + return Collections.unmodifiableMap(allIndicators); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/GroupHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/GroupHealthIndicator.java new file mode 100644 index 000000000000..77a807b05ff6 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/GroupHealthIndicator.java @@ -0,0 +1,25 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * https://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.health; + +/** + * @author Stephane Nicoll + * @since 2.2.0 + */ +public interface GroupHealthIndicator extends HealthIndicator { + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/GroupReactiveHealthIndicator.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/GroupReactiveHealthIndicator.java new file mode 100644 index 000000000000..3ee7a9f0c716 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/GroupReactiveHealthIndicator.java @@ -0,0 +1,24 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * https://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.health; + +/** + * + * @author Stephane Nicoll + */ +public interface GroupReactiveHealthIndicator extends ReactiveHealthIndicator { +} diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-actuator/src/main/resources/application.properties index 09413b04851a..cf1a94fdbfcb 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/main/resources/application.properties +++ b/spring-boot-samples/spring-boot-sample-actuator/src/main/resources/application.properties @@ -19,3 +19,12 @@ spring.jmx.enabled=true spring.jackson.serialization.write_dates_as_timestamps=false management.trace.http.include=request-headers,response-headers,principal,remote-address,session-id + + +management.health.groups.ready=diskSpace +management.health.groups.live=example,hello,db,unknown + + + + +management.endpoint.health.show-details=always \ No newline at end of file