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 38b9cb7c7e01..872c364af235 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 @@ -18,7 +18,9 @@ import java.util.Collections; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import org.springframework.util.Assert; @@ -27,6 +29,7 @@ * * @author Vedran Pavic * @author Stephane Nicoll + * @author Eddú Meléndez * @since 2.1.0 */ public class DefaultHealthIndicatorRegistry implements HealthIndicatorRegistry { @@ -82,6 +85,20 @@ public HealthIndicator get(String name) { } } + @Override + public Map get(List names) { + Assert.notEmpty(names, "Name must not be empty"); + synchronized (this.monitor) { + return names.stream() + .map((name) -> this.healthIndicators.entrySet().stream() + .filter((entry) -> entry.getKey().equals(name)) + .collect(Collectors.toMap(Map.Entry::getKey, + Map.Entry::getValue))) + .flatMap((map) -> map.entrySet().stream()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + } + @Override public Map getAll() { synchronized (this.monitor) { diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java index 2692da774727..73d1b92f1bc2 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java @@ -16,6 +16,10 @@ package org.springframework.boot.actuate.health; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.Map; + import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.Selector; @@ -28,6 +32,7 @@ * @author Christian Dupuis * @author Andy Wilkinson * @author Stephane Nicoll + * @author Eddú Meléndez * @since 2.0.0 */ @Endpoint(id = "health") @@ -63,6 +68,14 @@ public Health healthForComponent(@Selector String component) { return (indicator != null) ? indicator.health() : null; } + @ReadOperation + public Health healthForComponents(@Selector String... components) { + HealthAggregator aggregator = new OrderedHealthAggregator(); + Map healths = getNestedHealthIndicators(this.healthIndicator, + components); + return aggregator.aggregate(healths); + } + /** * Return the {@link Health} of a particular {@code instance} managed by the specified * {@code component} or {@code null} if that particular component is not a @@ -88,4 +101,19 @@ private HealthIndicator getNestedHealthIndicator(HealthIndicator healthIndicator return null; } + private Map getNestedHealthIndicators(HealthIndicator healthIndicator, + String... names) { + if (healthIndicator instanceof CompositeHealthIndicator) { + Map healthIndicators = ((CompositeHealthIndicator) healthIndicator) + .getRegistry().get(Arrays.asList(names)); + + Map healths = new LinkedHashMap<>(); + for (Map.Entry entry : healthIndicators.entrySet()) { + healths.put(entry.getKey(), entry.getValue().health()); + } + return healths; + } + return null; + } + } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java index 9b4df6af9b68..b96bd2faa961 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicatorRegistry.java @@ -16,6 +16,7 @@ package org.springframework.boot.actuate.health; +import java.util.List; import java.util.Map; /** @@ -26,6 +27,7 @@ * @author Andy Wilkinson * @author Vedran Pavic * @author Stephane Nicoll + * @author Eddú Meléndez * @since 2.1.0 */ public interface HealthIndicatorRegistry { @@ -57,6 +59,8 @@ public interface HealthIndicatorRegistry { */ HealthIndicator get(String name); + Map get(List names); + /** * Returns a snapshot of the registered health indicators and their names. The * contents of the map do not reflect subsequent changes to the registry. diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java index 788ce2b21fd4..79a2b086bc34 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java @@ -32,6 +32,7 @@ * @author Christian Dupuis * @author Andy Wilkinson * @author Stephane Nicoll + * @author Eddú Meléndez */ public class HealthEndpointTests { @@ -107,6 +108,22 @@ public void statusForComponentInstanceThatIsNotACompositeReturnNull() { assertThat(health).isNull(); } + @Test + public void callSpecificComponents() { + Map healthIndicators = new HashMap<>(); + healthIndicators.put("one", one); + healthIndicators.put("two", two); + HealthEndpoint endpoint = new HealthEndpoint( + createHealthIndicator(healthIndicators)); + Health health = endpoint.healthForComponents("one", "two"); + assertThat(health.getStatus()).isEqualTo(Status.UP); + assertThat(health.getDetails()).containsOnlyKeys("one", "two"); + Health upHealth = (Health) health.getDetails().get("one"); + assertThat(upHealth.getDetails()).containsOnly(entry("first", "1")); + Health upAgainHealth = (Health) health.getDetails().get("two"); + assertThat(upAgainHealth.getDetails()).containsOnly(entry("second", "2")); + } + private HealthIndicator createHealthIndicator( Map healthIndicators) { return new CompositeHealthIndicator(new OrderedHealthAggregator(),