parent
3ecbbce773
commit
3ca1e91cde
|
@ -95,6 +95,7 @@ include "spring-boot-project:spring-boot-gson"
|
|||
include "spring-boot-project:spring-boot-h2console"
|
||||
include "spring-boot-project:spring-boot-hateoas"
|
||||
include "spring-boot-project:spring-boot-hazelcast"
|
||||
include "spring-boot-project:spring-boot-health"
|
||||
include "spring-boot-project:spring-boot-hibernate"
|
||||
include "spring-boot-project:spring-boot-http-client"
|
||||
include "spring-boot-project:spring-boot-http-converter"
|
||||
|
|
|
@ -28,10 +28,11 @@ description = "Spring Boot Actuator AutoConfigure"
|
|||
dependencies {
|
||||
api(project(":spring-boot-project:spring-boot-actuator"))
|
||||
api(project(":spring-boot-project:spring-boot-autoconfigure"))
|
||||
|
||||
|
||||
implementation("com.fasterxml.jackson.core:jackson-databind")
|
||||
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
|
||||
|
||||
optional(project(":spring-boot-project:spring-boot-health"))
|
||||
optional(project(":spring-boot-project:spring-boot-web-server"))
|
||||
|
||||
optional("com.fasterxml.jackson.core:jackson-databind")
|
||||
|
|
|
@ -23,8 +23,10 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
|
|||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.availability.ApplicationAvailability;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
|
@ -35,6 +37,7 @@ import org.springframework.context.annotation.Bean;
|
|||
* @since 2.3.2
|
||||
*/
|
||||
@AutoConfiguration(after = ApplicationAvailabilityAutoConfiguration.class)
|
||||
@ConditionalOnClass(Health.class)
|
||||
public class AvailabilityHealthContributorAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
|
|
|
@ -23,10 +23,12 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
|||
import org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.availability.ApplicationAvailability;
|
||||
import org.springframework.boot.cloud.CloudPlatform;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
|
@ -42,6 +44,7 @@ import org.springframework.core.type.AnnotatedTypeMetadata;
|
|||
*/
|
||||
@AutoConfiguration(after = { AvailabilityHealthContributorAutoConfiguration.class,
|
||||
ApplicationAvailabilityAutoConfiguration.class })
|
||||
@ConditionalOnClass(Health.class)
|
||||
@Conditional(AvailabilityProbesAutoConfiguration.ProbesCondition.class)
|
||||
public class AvailabilityProbesAutoConfiguration {
|
||||
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
package org.springframework.boot.actuate.autoconfigure.endpoint.jackson;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
@ -28,6 +31,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProp
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Endpoint Jackson support.
|
||||
|
@ -39,6 +43,8 @@ import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
|||
@SuppressWarnings("removal")
|
||||
public class JacksonEndpointAutoConfiguration {
|
||||
|
||||
private static final String CONTRIBUTED_HEALTH = "org.springframework.boot.health.contributor.ContributedHealth";
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBooleanProperty(name = "management.endpoints.jackson.isolated-object-mapper", matchIfMissing = true)
|
||||
@ConditionalOnClass({ ObjectMapper.class, Jackson2ObjectMapperBuilder.class })
|
||||
|
@ -49,7 +55,24 @@ public class JacksonEndpointAutoConfiguration {
|
|||
SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS)
|
||||
.serializationInclusion(Include.NON_NULL)
|
||||
.build();
|
||||
return () -> objectMapper;
|
||||
Set<Class<?>> supportedTypes = new HashSet<>(EndpointObjectMapper.DEFAULT_SUPPORTED_TYPES);
|
||||
if (ClassUtils.isPresent(CONTRIBUTED_HEALTH, null)) {
|
||||
supportedTypes.add(ClassUtils.resolveClassName(CONTRIBUTED_HEALTH, null));
|
||||
}
|
||||
return new EndpointObjectMapper() {
|
||||
|
||||
@Override
|
||||
public ObjectMapper get() {
|
||||
return objectMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Class<?>> getSupportedTypes() {
|
||||
return supportedTypes;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.autoconfigure.health;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.actuate.health.DefaultHealthContributorRegistry;
|
||||
import org.springframework.boot.actuate.health.HealthContributor;
|
||||
import org.springframework.boot.actuate.health.HealthContributorRegistry;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An auto-configured {@link HealthContributorRegistry} that ensures registered indicators
|
||||
* do not clash with groups names.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class AutoConfiguredHealthContributorRegistry extends DefaultHealthContributorRegistry {
|
||||
|
||||
private final Collection<String> groupNames;
|
||||
|
||||
AutoConfiguredHealthContributorRegistry(Map<String, HealthContributor> contributors,
|
||||
Collection<String> groupNames) {
|
||||
super(contributors);
|
||||
this.groupNames = groupNames;
|
||||
contributors.keySet().forEach(this::assertDoesNotClashWithGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerContributor(String name, HealthContributor contributor) {
|
||||
assertDoesNotClashWithGroup(name);
|
||||
super.registerContributor(name, contributor);
|
||||
}
|
||||
|
||||
private void assertDoesNotClashWithGroup(String name) {
|
||||
Assert.state(!this.groupNames.contains(name),
|
||||
() -> "HealthContributor with name \"" + name + "\" clashes with group");
|
||||
}
|
||||
|
||||
}
|
|
@ -18,11 +18,11 @@ package org.springframework.boot.actuate.autoconfigure.health;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -93,7 +93,7 @@ class AutoConfiguredHealthEndpointGroups implements HealthEndpointGroups, Additi
|
|||
private Map<String, HealthEndpointGroup> createGroups(Map<String, Group> groupProperties, BeanFactory beanFactory,
|
||||
StatusAggregator defaultStatusAggregator, HttpCodeStatusMapper defaultHttpCodeStatusMapper,
|
||||
Show defaultShowComponents, Show defaultShowDetails, Set<String> defaultRoles) {
|
||||
Map<String, HealthEndpointGroup> groups = new LinkedHashMap<>();
|
||||
Map<String, HealthEndpointGroup> groups = new TreeMap<>();
|
||||
groupProperties.forEach((groupName, group) -> {
|
||||
Status status = group.getStatus();
|
||||
Show showComponents = (group.getShowComponents() != null) ? group.getShowComponents()
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.autoconfigure.health;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.actuate.health.DefaultReactiveHealthContributorRegistry;
|
||||
import org.springframework.boot.actuate.health.HealthContributorRegistry;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthContributor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An auto-configured {@link HealthContributorRegistry} that ensures registered indicators
|
||||
* do not clash with groups names.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class AutoConfiguredReactiveHealthContributorRegistry extends DefaultReactiveHealthContributorRegistry {
|
||||
|
||||
private final Collection<String> groupNames;
|
||||
|
||||
AutoConfiguredReactiveHealthContributorRegistry(Map<String, ReactiveHealthContributor> contributors,
|
||||
Collection<String> groupNames) {
|
||||
super(contributors);
|
||||
this.groupNames = groupNames;
|
||||
contributors.keySet().forEach(this::assertDoesNotClashWithGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerContributor(String name, ReactiveHealthContributor contributor) {
|
||||
assertDoesNotClashWithGroup(name);
|
||||
super.registerContributor(name, contributor);
|
||||
}
|
||||
|
||||
private void assertDoesNotClashWithGroup(String name) {
|
||||
Assert.state(!this.groupNames.contains(name),
|
||||
() -> "ReactiveHealthContributor with name \"" + name + "\" clashes with group");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.autoconfigure.health;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
||||
import org.springframework.boot.health.registry.HealthContributorNameValidator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link HealthContributorNameValidator} to ensure names don't clash with groups.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class GroupsHealthContributorNameValidator implements HealthContributorNameValidator {
|
||||
|
||||
private final Set<String> groupNames;
|
||||
|
||||
GroupsHealthContributorNameValidator(HealthEndpointGroups groups) {
|
||||
this.groupNames = (groups != null) ? groups.getNames() : Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(String name) throws IllegalStateException {
|
||||
Assert.state(!this.groupNames.contains(name),
|
||||
() -> "HealthContributor with name \"" + name + "\" clashes with group");
|
||||
}
|
||||
|
||||
}
|
|
@ -20,7 +20,10 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.condition.Conditi
|
|||
import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
|
@ -32,11 +35,14 @@ import org.springframework.context.annotation.Import;
|
|||
* @author Scott Frederick
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@AutoConfiguration(
|
||||
afterName = "org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration")
|
||||
@ConditionalOnClass(Health.class)
|
||||
@ConditionalOnBean(type = "org.springframework.boot.health.registry.HealthContributorRegistry")
|
||||
@ConditionalOnAvailableEndpoint(HealthEndpoint.class)
|
||||
@EnableConfigurationProperties(HealthEndpointProperties.class)
|
||||
@Import({ HealthEndpointConfiguration.class, ReactiveHealthEndpointConfiguration.class,
|
||||
HealthEndpointWebExtensionConfiguration.class, HealthEndpointReactiveWebExtensionConfiguration.class })
|
||||
@Import({ HealthEndpointConfiguration.class, HealthEndpointWebExtensionConfiguration.class,
|
||||
HealthEndpointReactiveWebExtensionConfiguration.class })
|
||||
public class HealthEndpointAutoConfiguration {
|
||||
|
||||
}
|
||||
|
|
|
@ -16,39 +16,27 @@
|
|||
|
||||
package org.springframework.boot.actuate.autoconfigure.health;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.actuate.health.CompositeHealthContributor;
|
||||
import org.springframework.boot.actuate.health.CompositeReactiveHealthContributor;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthContributor;
|
||||
import org.springframework.boot.actuate.health.HealthContributorRegistry;
|
||||
import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroupsPostProcessor;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HttpCodeStatusMapper;
|
||||
import org.springframework.boot.actuate.health.NamedContributor;
|
||||
import org.springframework.boot.actuate.health.NamedContributors;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthContributor;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.SimpleHttpCodeStatusMapper;
|
||||
import org.springframework.boot.actuate.health.SimpleStatusAggregator;
|
||||
import org.springframework.boot.actuate.health.StatusAggregator;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.health.contributor.HealthContributors;
|
||||
import org.springframework.boot.health.registry.HealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
|
@ -80,14 +68,9 @@ class HealthEndpointConfiguration {
|
|||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
HealthContributorRegistry healthContributorRegistry(ApplicationContext applicationContext,
|
||||
HealthEndpointGroups groups, Map<String, HealthContributor> healthContributors,
|
||||
Map<String, ReactiveHealthContributor> reactiveHealthContributors) {
|
||||
if (ClassUtils.isPresent("reactor.core.publisher.Flux", applicationContext.getClassLoader())) {
|
||||
healthContributors.putAll(new AdaptedReactiveHealthContributors(reactiveHealthContributors).get());
|
||||
}
|
||||
return new AutoConfiguredHealthContributorRegistry(healthContributors, groups.getNames());
|
||||
GroupsHealthContributorNameValidator groupsHealthContributorNameValidator(
|
||||
ObjectProvider<HealthEndpointGroups> healthEndpointGroups) {
|
||||
return new GroupsHealthContributorNameValidator(healthEndpointGroups.getIfAvailable());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -99,9 +82,11 @@ class HealthEndpointConfiguration {
|
|||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
HealthEndpoint healthEndpoint(HealthContributorRegistry registry, HealthEndpointGroups groups,
|
||||
HealthEndpointProperties properties) {
|
||||
return new HealthEndpoint(registry, groups, properties.getLogging().getSlowIndicatorThreshold());
|
||||
HealthEndpoint healthEndpoint(HealthContributorRegistry halthContributorRegistry,
|
||||
ObjectProvider<ReactiveHealthContributorRegistry> reactiveHealthContributorRegistry,
|
||||
HealthEndpointGroups groups, HealthEndpointProperties properties) {
|
||||
return new HealthEndpoint(halthContributorRegistry, reactiveHealthContributorRegistry.getIfAvailable(), groups,
|
||||
properties.getLogging().getSlowIndicatorThreshold());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -140,82 +125,6 @@ class HealthEndpointConfiguration {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapter to expose {@link ReactiveHealthContributor} beans as
|
||||
* {@link HealthContributor} instances.
|
||||
*/
|
||||
private static class AdaptedReactiveHealthContributors {
|
||||
|
||||
private final Map<String, HealthContributor> adapted;
|
||||
|
||||
AdaptedReactiveHealthContributors(Map<String, ReactiveHealthContributor> reactiveContributors) {
|
||||
Map<String, HealthContributor> adapted = new LinkedHashMap<>();
|
||||
reactiveContributors.forEach((name, contributor) -> adapted.put(name, adapt(contributor)));
|
||||
this.adapted = Collections.unmodifiableMap(adapted);
|
||||
}
|
||||
|
||||
private HealthContributor adapt(ReactiveHealthContributor contributor) {
|
||||
if (contributor instanceof ReactiveHealthIndicator healthIndicator) {
|
||||
return adapt(healthIndicator);
|
||||
}
|
||||
if (contributor instanceof CompositeReactiveHealthContributor healthContributor) {
|
||||
return adapt(healthContributor);
|
||||
}
|
||||
throw new IllegalStateException("Unsupported ReactiveHealthContributor type " + contributor.getClass());
|
||||
}
|
||||
|
||||
private HealthIndicator adapt(ReactiveHealthIndicator indicator) {
|
||||
return new HealthIndicator() {
|
||||
|
||||
@Override
|
||||
public Health getHealth(boolean includeDetails) {
|
||||
return indicator.getHealth(includeDetails).block();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Health health() {
|
||||
return indicator.health().block();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private CompositeHealthContributor adapt(CompositeReactiveHealthContributor composite) {
|
||||
return new CompositeHealthContributor() {
|
||||
|
||||
@Override
|
||||
public Iterator<NamedContributor<HealthContributor>> iterator() {
|
||||
Iterator<NamedContributor<ReactiveHealthContributor>> iterator = composite.iterator();
|
||||
return new Iterator<>() {
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedContributor<HealthContributor> next() {
|
||||
NamedContributor<ReactiveHealthContributor> next = iterator.next();
|
||||
return NamedContributor.of(next.getName(), adapt(next.getContributor()));
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public HealthContributor getContributor(String name) {
|
||||
return adapt(composite.getContributor(name));
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
Map<String, HealthContributor> get() {
|
||||
return this.adapted;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link SmartInitializingSingleton} that validates health endpoint group membership,
|
||||
* throwing a {@link NoSuchHealthContributorException} if an included or excluded
|
||||
|
@ -264,10 +173,10 @@ class HealthEndpointConfiguration {
|
|||
int pathOffset = 0;
|
||||
Object contributor = this.registry;
|
||||
while (pathOffset < path.length) {
|
||||
if (!(contributor instanceof NamedContributors)) {
|
||||
if (!(contributor instanceof HealthContributors)) {
|
||||
return false;
|
||||
}
|
||||
contributor = ((NamedContributors<?>) contributor).getContributor(path[pathOffset]);
|
||||
contributor = ((HealthContributors) contributor).getContributor(path[pathOffset]);
|
||||
pathOffset++;
|
||||
}
|
||||
return (contributor != null);
|
||||
|
|
|
@ -16,16 +16,18 @@
|
|||
|
||||
package org.springframework.boot.actuate.autoconfigure.health;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
|
||||
import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthContributorRegistry;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthEndpointWebExtension;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.boot.health.registry.HealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
@ -45,9 +47,11 @@ class HealthEndpointReactiveWebExtensionConfiguration {
|
|||
@ConditionalOnMissingBean
|
||||
@ConditionalOnBean(HealthEndpoint.class)
|
||||
ReactiveHealthEndpointWebExtension reactiveHealthEndpointWebExtension(
|
||||
ReactiveHealthContributorRegistry reactiveHealthContributorRegistry, HealthEndpointGroups groups,
|
||||
ReactiveHealthContributorRegistry reactiveHealthContributorRegistry,
|
||||
ObjectProvider<HealthContributorRegistry> healthContributorRegistry, HealthEndpointGroups groups,
|
||||
HealthEndpointProperties properties) {
|
||||
return new ReactiveHealthEndpointWebExtension(reactiveHealthContributorRegistry, groups,
|
||||
return new ReactiveHealthEndpointWebExtension(reactiveHealthContributorRegistry,
|
||||
healthContributorRegistry.getIfAvailable(), groups,
|
||||
properties.getLogging().getSlowIndicatorThreshold());
|
||||
}
|
||||
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
|
||||
package org.springframework.boot.actuate.autoconfigure.health;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
|
||||
import org.springframework.boot.actuate.health.HealthContributorRegistry;
|
||||
import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointWebExtension;
|
||||
|
@ -26,6 +26,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.boot.health.registry.HealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
@ -45,8 +47,10 @@ class HealthEndpointWebExtensionConfiguration {
|
|||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
HealthEndpointWebExtension healthEndpointWebExtension(HealthContributorRegistry healthContributorRegistry,
|
||||
ObjectProvider<ReactiveHealthContributorRegistry> reactiveHealthContributorRegistry,
|
||||
HealthEndpointGroups groups, HealthEndpointProperties properties) {
|
||||
return new HealthEndpointWebExtension(healthContributorRegistry, groups,
|
||||
return new HealthEndpointWebExtension(healthContributorRegistry,
|
||||
reactiveHealthContributorRegistry.getIfAvailable(), groups,
|
||||
properties.getLogging().getSlowIndicatorThreshold());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.autoconfigure.health;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.OnEndpointElementCondition;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
|
||||
/**
|
||||
* {@link Condition} that checks if a health indicator is enabled.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class OnEnabledHealthIndicatorCondition extends OnEndpointElementCondition {
|
||||
|
||||
OnEnabledHealthIndicatorCondition() {
|
||||
super("management.health.", ConditionalOnEnabledHealthIndicator.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.autoconfigure.health;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.boot.actuate.health.HealthContributor;
|
||||
import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthContributor;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthContributorRegistry;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Configuration for reactive {@link HealthEndpoint} infrastructure beans.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see HealthEndpointAutoConfiguration
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(Flux.class)
|
||||
@ConditionalOnBean(HealthEndpoint.class)
|
||||
class ReactiveHealthEndpointConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ReactiveHealthContributorRegistry reactiveHealthContributorRegistry(
|
||||
Map<String, HealthContributor> healthContributors,
|
||||
Map<String, ReactiveHealthContributor> reactiveHealthContributors, HealthEndpointGroups groups) {
|
||||
Map<String, ReactiveHealthContributor> allContributors = new LinkedHashMap<>(reactiveHealthContributors);
|
||||
healthContributors.forEach((name, contributor) -> allContributors.computeIfAbsent(name,
|
||||
(key) -> ReactiveHealthContributor.adapt(contributor)));
|
||||
return new AutoConfiguredReactiveHealthContributorRegistry(allContributors, groups.getNames());
|
||||
}
|
||||
|
||||
}
|
|
@ -16,13 +16,14 @@
|
|||
|
||||
package org.springframework.boot.actuate.autoconfigure.ssl;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.actuate.ssl.SslHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.info.SslInfo;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
@ -33,7 +34,9 @@ import org.springframework.context.annotation.Bean;
|
|||
* @author Jonatan Ivanov
|
||||
* @since 3.4.0
|
||||
*/
|
||||
@AutoConfiguration(before = HealthContributorAutoConfiguration.class)
|
||||
@AutoConfiguration(
|
||||
beforeName = "org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration")
|
||||
@ConditionalOnClass(Health.class)
|
||||
@ConditionalOnEnabledHealthIndicator("ssl")
|
||||
@EnableConfigurationProperties(SslHealthIndicatorProperties.class)
|
||||
public class SslHealthContributorAutoConfiguration {
|
||||
|
|
|
@ -16,13 +16,14 @@
|
|||
|
||||
package org.springframework.boot.actuate.autoconfigure.system;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.actuate.system.DiskSpaceHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
|
@ -33,7 +34,9 @@ import org.springframework.context.annotation.Bean;
|
|||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@AutoConfiguration(before = HealthContributorAutoConfiguration.class)
|
||||
@AutoConfiguration(
|
||||
beforeName = "org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration")
|
||||
@ConditionalOnClass(Health.class)
|
||||
@ConditionalOnEnabledHealthIndicator("diskspace")
|
||||
@EnableConfigurationProperties(DiskSpaceHealthIndicatorProperties.class)
|
||||
public class DiskSpaceHealthContributorAutoConfiguration {
|
||||
|
|
|
@ -11,7 +11,6 @@ org.springframework.boot.actuate.autoconfigure.endpoint.jackson.JacksonEndpointA
|
|||
org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.info.InfoContributorAutoConfiguration
|
||||
org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.springframework.boot.actuate.availability.ReadinessStateHealthIndicat
|
|||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration;
|
||||
import org.springframework.boot.availability.ApplicationAvailability;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
|
@ -60,6 +61,13 @@ class AvailabilityProbesAutoConfigurationTests {
|
|||
.run(this::hasProbesBeans);
|
||||
}
|
||||
|
||||
@Test
|
||||
void probesWhenPropertyEnabledButNoHealthDependencyDoesNotAddBeans() {
|
||||
this.contextRunner.withPropertyValues("management.endpoint.health.probes.enabled=true")
|
||||
.withClassLoader(new FilteredClassLoader("org.springframework.boot.health"))
|
||||
.run(this::doesNotHaveProbeBeans);
|
||||
}
|
||||
|
||||
@Test
|
||||
void probesWhenKubernetesAndPropertyDisabledAddsNotBeans() {
|
||||
this.contextRunner
|
||||
|
|
|
@ -25,13 +25,13 @@ import org.junit.jupiter.api.Test;
|
|||
|
||||
import org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
|
||||
import org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpoint;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
|
||||
import org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
|
|
@ -31,11 +31,12 @@ import org.springframework.boot.actuate.audit.InMemoryAuditEventRepository;
|
|||
import org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.context.ShutdownEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
|
||||
import org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -53,7 +54,8 @@ class JmxEndpointIntegrationTests {
|
|||
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class, EndpointAutoConfiguration.class,
|
||||
JmxEndpointAutoConfiguration.class, HealthContributorAutoConfiguration.class))
|
||||
JmxEndpointAutoConfiguration.class, HealthContributorRegistryAutoConfiguration.class,
|
||||
HealthContributorAutoConfiguration.class))
|
||||
.withUserConfiguration(HttpExchangeRepositoryConfiguration.class, AuditEventRepositoryConfiguration.class)
|
||||
.withPropertyValues("spring.jmx.enabled=true")
|
||||
.withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class,
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.autoconfigure.health;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.health.HealthContributor;
|
||||
import org.springframework.boot.actuate.health.HealthContributorRegistry;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link AutoConfiguredHealthContributorRegistry}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class AutoConfiguredHealthContributorRegistryTests {
|
||||
|
||||
@Test
|
||||
void createWhenContributorsClashesWithGroupNameThrowsException() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> new AutoConfiguredHealthContributorRegistry(
|
||||
Collections.singletonMap("boot", mock(HealthContributor.class)), Arrays.asList("spring", "boot")))
|
||||
.withMessage("HealthContributor with name \"boot\" clashes with group");
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerContributorWithGroupNameThrowsException() {
|
||||
HealthContributorRegistry registry = new AutoConfiguredHealthContributorRegistry(Collections.emptyMap(),
|
||||
Arrays.asList("spring", "boot"));
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> registry.registerContributor("spring", mock(HealthContributor.class)))
|
||||
.withMessage("HealthContributor with name \"spring\" clashes with group");
|
||||
}
|
||||
|
||||
}
|
|
@ -31,10 +31,10 @@ import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
|||
import org.springframework.boot.actuate.health.HttpCodeStatusMapper;
|
||||
import org.springframework.boot.actuate.health.SimpleHttpCodeStatusMapper;
|
||||
import org.springframework.boot.actuate.health.SimpleStatusAggregator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.actuate.health.StatusAggregator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.autoconfigure.health;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthContributor;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthContributorRegistry;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link AutoConfiguredReactiveHealthContributorRegistry}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class AutoConfiguredReactiveHealthContributorRegistryTests {
|
||||
|
||||
@Test
|
||||
void createWhenContributorsClashesWithGroupNameThrowsException() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> new AutoConfiguredReactiveHealthContributorRegistry(
|
||||
Collections.singletonMap("boot", mock(ReactiveHealthContributor.class)),
|
||||
Arrays.asList("spring", "boot")))
|
||||
.withMessage("ReactiveHealthContributor with name \"boot\" clashes with group");
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerContributorWithGroupNameThrowsException() {
|
||||
ReactiveHealthContributorRegistry registry = new AutoConfiguredReactiveHealthContributorRegistry(
|
||||
Collections.emptyMap(), Arrays.asList("spring", "boot"));
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> registry.registerContributor("spring", mock(ReactiveHealthContributor.class)))
|
||||
.withMessage("ReactiveHealthContributor with name \"spring\" clashes with group");
|
||||
}
|
||||
|
||||
}
|
|
@ -30,26 +30,30 @@ import org.springframework.boot.actuate.endpoint.ApiVersion;
|
|||
import org.springframework.boot.actuate.endpoint.SecurityContext;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.actuate.health.CompositeHealthContributor;
|
||||
import org.springframework.boot.actuate.health.DefaultHealthContributorRegistry;
|
||||
import org.springframework.boot.actuate.health.DefaultReactiveHealthContributorRegistry;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthComponent;
|
||||
import org.springframework.boot.actuate.health.HealthContributorRegistry;
|
||||
import org.springframework.boot.actuate.health.CompositeHealthDescriptor;
|
||||
import org.springframework.boot.actuate.health.HealthDescriptor;
|
||||
import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroupsPostProcessor;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointWebExtension;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HttpCodeStatusMapper;
|
||||
import org.springframework.boot.actuate.health.NamedContributor;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthContributorRegistry;
|
||||
import org.springframework.boot.actuate.health.IndicatedHealthDescriptor;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthEndpointWebExtension;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.actuate.health.StatusAggregator;
|
||||
import org.springframework.boot.actuate.health.SystemHealth;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;
|
||||
import org.springframework.boot.health.contributor.CompositeHealthContributor;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthContributors;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.health.contributor.ReactiveHealthContributors;
|
||||
import org.springframework.boot.health.contributor.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.boot.health.registry.DefaultHealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.DefaultReactiveHealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.HealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
||||
|
@ -74,14 +78,14 @@ class HealthEndpointAutoConfigurationTests {
|
|||
|
||||
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withUserConfiguration(HealthIndicatorsConfiguration.class)
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(HealthContributorAutoConfiguration.class, HealthEndpointAutoConfiguration.class));
|
||||
.withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class,
|
||||
HealthContributorRegistryAutoConfiguration.class, HealthContributorAutoConfiguration.class));
|
||||
|
||||
private final ReactiveWebApplicationContextRunner reactiveContextRunner = new ReactiveWebApplicationContextRunner()
|
||||
.withUserConfiguration(HealthIndicatorsConfiguration.class)
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(HealthContributorAutoConfiguration.class, HealthEndpointAutoConfiguration.class,
|
||||
WebEndpointAutoConfiguration.class, EndpointAutoConfiguration.class));
|
||||
.withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class,
|
||||
HealthContributorRegistryAutoConfiguration.class, HealthContributorAutoConfiguration.class,
|
||||
WebEndpointAutoConfiguration.class, EndpointAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void runWhenHealthEndpointIsDisabledDoesNotCreateBeans() {
|
||||
|
@ -89,9 +93,7 @@ class HealthEndpointAutoConfigurationTests {
|
|||
assertThat(context).doesNotHaveBean(StatusAggregator.class);
|
||||
assertThat(context).doesNotHaveBean(HttpCodeStatusMapper.class);
|
||||
assertThat(context).doesNotHaveBean(HealthEndpointGroups.class);
|
||||
assertThat(context).doesNotHaveBean(HealthContributorRegistry.class);
|
||||
assertThat(context).doesNotHaveBean(HealthEndpoint.class);
|
||||
assertThat(context).doesNotHaveBean(ReactiveHealthContributorRegistry.class);
|
||||
assertThat(context).doesNotHaveBean(HealthEndpointWebExtension.class);
|
||||
assertThat(context).doesNotHaveBean(ReactiveHealthEndpointWebExtension.class);
|
||||
});
|
||||
|
@ -192,8 +194,8 @@ class HealthEndpointAutoConfigurationTests {
|
|||
void runCreatesHealthContributorRegistryContainingHealthBeans() {
|
||||
this.contextRunner.run((context) -> {
|
||||
HealthContributorRegistry registry = context.getBean(HealthContributorRegistry.class);
|
||||
Object[] names = registry.stream().map(NamedContributor::getName).toArray();
|
||||
assertThat(names).containsExactlyInAnyOrder("simple", "additional", "ping", "reactive");
|
||||
Object[] names = registry.stream().map(HealthContributors.Entry::name).toArray();
|
||||
assertThat(names).containsExactlyInAnyOrder("simple", "additional", "ping");
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -202,7 +204,7 @@ class HealthEndpointAutoConfigurationTests {
|
|||
ClassLoader classLoader = new FilteredClassLoader(Mono.class, Flux.class);
|
||||
this.contextRunner.withClassLoader(classLoader).run((context) -> {
|
||||
HealthContributorRegistry registry = context.getBean(HealthContributorRegistry.class);
|
||||
Object[] names = registry.stream().map(NamedContributor::getName).toArray();
|
||||
Object[] names = registry.stream().map(HealthContributors.Entry::name).toArray();
|
||||
assertThat(names).containsExactlyInAnyOrder("simple", "additional", "ping");
|
||||
});
|
||||
}
|
||||
|
@ -211,7 +213,7 @@ class HealthEndpointAutoConfigurationTests {
|
|||
void runWhenHasHealthContributorRegistryBeanDoesNotCreateAdditionalRegistry() {
|
||||
this.contextRunner.withUserConfiguration(HealthContributorRegistryConfiguration.class).run((context) -> {
|
||||
HealthContributorRegistry registry = context.getBean(HealthContributorRegistry.class);
|
||||
Object[] names = registry.stream().map(NamedContributor::getName).toArray();
|
||||
Object[] names = registry.stream().map(HealthContributors.Entry::name).toArray();
|
||||
assertThat(names).isEmpty();
|
||||
});
|
||||
}
|
||||
|
@ -220,8 +222,8 @@ class HealthEndpointAutoConfigurationTests {
|
|||
void runCreatesHealthEndpoint() {
|
||||
this.contextRunner.withPropertyValues("management.endpoint.health.show-details=always").run((context) -> {
|
||||
HealthEndpoint endpoint = context.getBean(HealthEndpoint.class);
|
||||
Health health = (Health) endpoint.healthForPath("simple");
|
||||
assertThat(health.getDetails()).containsEntry("counter", 42);
|
||||
IndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) endpoint.healthForPath("simple");
|
||||
assertThat(descriptor.getDetails()).containsEntry("counter", 42);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -234,11 +236,12 @@ class HealthEndpointAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void runCreatesReactiveHealthContributorRegistryContainingAdaptedBeans() {
|
||||
void runCreatesReactiveHealthContributorRegistryContainingReactiveHealthBeans() {
|
||||
this.reactiveContextRunner.run((context) -> {
|
||||
ReactiveHealthContributorRegistry registry = context.getBean(ReactiveHealthContributorRegistry.class);
|
||||
Object[] names = registry.stream().map(NamedContributor::getName).toArray();
|
||||
assertThat(names).containsExactlyInAnyOrder("simple", "additional", "reactive", "ping");
|
||||
ReactiveHealthContributorRegistry reactiveRegistry = context
|
||||
.getBean(ReactiveHealthContributorRegistry.class);
|
||||
Object[] names = reactiveRegistry.stream().map(ReactiveHealthContributors.Entry::name).toArray();
|
||||
assertThat(names).containsExactlyInAnyOrder("reactive");
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -247,7 +250,7 @@ class HealthEndpointAutoConfigurationTests {
|
|||
this.reactiveContextRunner.withUserConfiguration(ReactiveHealthContributorRegistryConfiguration.class)
|
||||
.run((context) -> {
|
||||
ReactiveHealthContributorRegistry registry = context.getBean(ReactiveHealthContributorRegistry.class);
|
||||
Object[] names = registry.stream().map(NamedContributor::getName).toArray();
|
||||
Object[] names = registry.stream().map(ReactiveHealthContributors.Entry::name).toArray();
|
||||
assertThat(names).isEmpty();
|
||||
});
|
||||
}
|
||||
|
@ -256,11 +259,11 @@ class HealthEndpointAutoConfigurationTests {
|
|||
void runCreatesHealthEndpointWebExtension() {
|
||||
this.contextRunner.run((context) -> {
|
||||
HealthEndpointWebExtension webExtension = context.getBean(HealthEndpointWebExtension.class);
|
||||
WebEndpointResponse<HealthComponent> response = webExtension.health(ApiVersion.V3,
|
||||
WebEndpointResponse<HealthDescriptor> response = webExtension.health(ApiVersion.V3,
|
||||
WebServerNamespace.SERVER, SecurityContext.NONE, true, "simple");
|
||||
Health health = (Health) response.getBody();
|
||||
IndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) response.getBody();
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
assertThat(health.getDetails()).containsEntry("counter", 42);
|
||||
assertThat(descriptor.getDetails()).containsEntry("counter", 42);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -268,7 +271,7 @@ class HealthEndpointAutoConfigurationTests {
|
|||
void runWhenHasHealthEndpointWebExtensionBeanDoesNotCreateExtraHealthEndpointWebExtension() {
|
||||
this.contextRunner.withUserConfiguration(HealthEndpointWebExtensionConfiguration.class).run((context) -> {
|
||||
HealthEndpointWebExtension webExtension = context.getBean(HealthEndpointWebExtension.class);
|
||||
WebEndpointResponse<HealthComponent> response = webExtension.health(ApiVersion.V3,
|
||||
WebEndpointResponse<HealthDescriptor> response = webExtension.health(ApiVersion.V3,
|
||||
WebServerNamespace.SERVER, SecurityContext.NONE, true, "simple");
|
||||
assertThat(response).isNull();
|
||||
});
|
||||
|
@ -278,10 +281,10 @@ class HealthEndpointAutoConfigurationTests {
|
|||
void runCreatesReactiveHealthEndpointWebExtension() {
|
||||
this.reactiveContextRunner.run((context) -> {
|
||||
ReactiveHealthEndpointWebExtension webExtension = context.getBean(ReactiveHealthEndpointWebExtension.class);
|
||||
Mono<WebEndpointResponse<? extends HealthComponent>> response = webExtension.health(ApiVersion.V3,
|
||||
Mono<WebEndpointResponse<? extends HealthDescriptor>> response = webExtension.health(ApiVersion.V3,
|
||||
WebServerNamespace.SERVER, SecurityContext.NONE, true, "simple");
|
||||
Health health = (Health) (response.block().getBody());
|
||||
assertThat(health.getDetails()).containsEntry("counter", 42);
|
||||
IndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) (response.block().getBody());
|
||||
assertThat(descriptor.getDetails()).containsEntry("counter", 42);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -291,7 +294,7 @@ class HealthEndpointAutoConfigurationTests {
|
|||
.run((context) -> {
|
||||
ReactiveHealthEndpointWebExtension webExtension = context
|
||||
.getBean(ReactiveHealthEndpointWebExtension.class);
|
||||
Mono<WebEndpointResponse<? extends HealthComponent>> response = webExtension.health(ApiVersion.V3,
|
||||
Mono<WebEndpointResponse<? extends HealthDescriptor>> response = webExtension.health(ApiVersion.V3,
|
||||
WebServerNamespace.SERVER, SecurityContext.NONE, true, "simple");
|
||||
assertThat(response).isNull();
|
||||
});
|
||||
|
@ -312,12 +315,12 @@ class HealthEndpointAutoConfigurationTests {
|
|||
void runWithIndicatorsInParentContextFindsIndicators() {
|
||||
new ApplicationContextRunner().withUserConfiguration(HealthIndicatorsConfiguration.class)
|
||||
.run((parent) -> new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(HealthContributorAutoConfiguration.class,
|
||||
HealthEndpointAutoConfiguration.class))
|
||||
.withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class,
|
||||
HealthContributorRegistryAutoConfiguration.class, HealthContributorAutoConfiguration.class))
|
||||
.withParent(parent)
|
||||
.run((context) -> {
|
||||
HealthComponent health = context.getBean(HealthEndpoint.class).health();
|
||||
Map<String, HealthComponent> components = ((SystemHealth) health).getComponents();
|
||||
HealthDescriptor descriptor = context.getBean(HealthEndpoint.class).health();
|
||||
Map<String, HealthDescriptor> components = ((CompositeHealthDescriptor) descriptor).getComponents();
|
||||
assertThat(components).containsKeys("additional", "ping", "simple");
|
||||
}));
|
||||
}
|
||||
|
@ -326,17 +329,24 @@ class HealthEndpointAutoConfigurationTests {
|
|||
void runWithReactiveContextAndIndicatorsInParentContextFindsIndicators() {
|
||||
new ApplicationContextRunner().withUserConfiguration(HealthIndicatorsConfiguration.class)
|
||||
.run((parent) -> new ReactiveWebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(HealthContributorAutoConfiguration.class,
|
||||
HealthEndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class))
|
||||
.withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class,
|
||||
HealthContributorRegistryAutoConfiguration.class, HealthContributorAutoConfiguration.class,
|
||||
WebEndpointAutoConfiguration.class, EndpointAutoConfiguration.class))
|
||||
.withParent(parent)
|
||||
.run((context) -> {
|
||||
HealthComponent health = context.getBean(HealthEndpoint.class).health();
|
||||
Map<String, HealthComponent> components = ((SystemHealth) health).getComponents();
|
||||
HealthDescriptor descriptor = context.getBean(HealthEndpoint.class).health();
|
||||
Map<String, HealthDescriptor> components = ((CompositeHealthDescriptor) descriptor).getComponents();
|
||||
assertThat(components).containsKeys("additional", "ping", "simple");
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void runWithClashingGroupNameThrowsException() {
|
||||
this.contextRunner.withPropertyValues("management.endpoint.health.group.ping.include=*")
|
||||
.run((context) -> assertThat(context).getFailure()
|
||||
.hasMessageContaining("HealthContributor with name \"ping\" clashes with group"));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class HealthIndicatorsConfiguration {
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.junit.jupiter.api.Test;
|
|||
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointConfiguration.HealthEndpointGroupMembershipValidator.NoSuchHealthContributorException;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||
import org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
@ -34,8 +35,8 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
*/
|
||||
class NoSuchHealthContributorFailureAnalyzerTests {
|
||||
|
||||
private final ApplicationContextRunner runner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class));
|
||||
private final ApplicationContextRunner runner = new ApplicationContextRunner().withConfiguration(AutoConfigurations
|
||||
.of(HealthEndpointAutoConfiguration.class, HealthContributorRegistryAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void analyzesMissingRequiredConfiguration() throws Throwable {
|
||||
|
|
|
@ -22,12 +22,13 @@ import java.util.List;
|
|||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.ssl.SslHealthContributorAutoConfigurationTests.CustomSslInfoConfiguration.CustomSslHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.actuate.ssl.SslHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;
|
||||
import org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.boot.info.SslInfo;
|
||||
import org.springframework.boot.info.SslInfo.CertificateChainInfo;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
|
@ -47,8 +48,8 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
class SslHealthContributorAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(SslHealthContributorAutoConfiguration.class, SslAutoConfiguration.class))
|
||||
.withConfiguration(AutoConfigurations.of(SslHealthContributorAutoConfiguration.class,
|
||||
HealthContributorRegistryAutoConfiguration.class, SslAutoConfiguration.class))
|
||||
.withPropertyValues("server.ssl.bundle=ssltest",
|
||||
"spring.ssl.bundle.jks.ssltest.keystore.location=classpath:test.jks");
|
||||
|
||||
|
|
|
@ -18,9 +18,9 @@ package org.springframework.boot.actuate.autoconfigure.system;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.actuate.system.DiskSpaceHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.util.unit.DataSize;
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ dependencies {
|
|||
testImplementation(project(":spring-boot-project:spring-boot-actuator-autoconfigure"))
|
||||
testImplementation(project(":spring-boot-project:spring-boot-cache"))
|
||||
testImplementation(project(":spring-boot-project:spring-boot-flyway"))
|
||||
testImplementation(project(":spring-boot-project:spring-boot-health"))
|
||||
testImplementation(project(":spring-boot-project:spring-boot-http-converter"))
|
||||
testImplementation(project(":spring-boot-project:spring-boot-integration"))
|
||||
testImplementation(project(":spring-boot-project:spring-boot-jackson"))
|
||||
|
|
|
@ -29,23 +29,24 @@ import org.junit.jupiter.api.Test;
|
|||
import org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;
|
||||
import org.springframework.boot.actuate.endpoint.SecurityContext;
|
||||
import org.springframework.boot.actuate.health.AdditionalHealthEndpointPath;
|
||||
import org.springframework.boot.actuate.health.CompositeHealthContributor;
|
||||
import org.springframework.boot.actuate.health.DefaultHealthContributorRegistry;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthContributor;
|
||||
import org.springframework.boot.actuate.health.HealthContributorRegistry;
|
||||
import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroup;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointGroups;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HttpCodeStatusMapper;
|
||||
import org.springframework.boot.actuate.health.SimpleHttpCodeStatusMapper;
|
||||
import org.springframework.boot.actuate.health.SimpleStatusAggregator;
|
||||
import org.springframework.boot.actuate.health.StatusAggregator;
|
||||
import org.springframework.boot.actuate.system.DiskSpaceHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.jdbc.actuate.health.DataSourceHealthIndicator;
|
||||
import org.springframework.boot.health.autoconfigure.registry.HealthContributorNameGenerator;
|
||||
import org.springframework.boot.health.contributor.CompositeHealthContributor;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthContributor;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.health.registry.DefaultHealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.HealthContributorRegistry;
|
||||
import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.jdbc.health.DataSourceHealthIndicator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
|
@ -105,11 +106,12 @@ class HealthEndpointDocumentationTests extends MockMvcEndpointDocumentationTests
|
|||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
HealthEndpoint healthEndpoint(Map<String, HealthContributor> healthContributors) {
|
||||
HealthContributorRegistry registry = new DefaultHealthContributorRegistry(healthContributors);
|
||||
HealthEndpoint healthEndpoint(Map<String, HealthContributor> contributors) {
|
||||
HealthContributorRegistry registry = new DefaultHealthContributorRegistry(null,
|
||||
HealthContributorNameGenerator.withoutStandardSuffixes().registrar(contributors));
|
||||
HealthEndpointGroup primary = new TestHealthEndpointGroup();
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(primary, Collections.emptyMap());
|
||||
return new HealthEndpoint(registry, groups, null);
|
||||
return new HealthEndpoint(registry, null, groups, null);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
|
@ -25,6 +25,7 @@ description = "Spring Boot Actuator Integration Tests"
|
|||
dependencies {
|
||||
testImplementation(project(":spring-boot-project:spring-boot-actuator"))
|
||||
testImplementation(project(":spring-boot-project:spring-boot-autoconfigure"))
|
||||
testImplementation(project(":spring-boot-project:spring-boot-health"))
|
||||
testImplementation(project(":spring-boot-project:spring-boot-http-converter"))
|
||||
testImplementation(project(":spring-boot-project:spring-boot-jackson"))
|
||||
testImplementation(project(":spring-boot-project:spring-boot-jersey"))
|
||||
|
|
|
@ -17,16 +17,28 @@
|
|||
package org.springframework.boot.actuate.health;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.endpoint.ApiVersion;
|
||||
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.boot.health.autoconfigure.registry.HealthContributorNameGenerator;
|
||||
import org.springframework.boot.health.contributor.CompositeHealthContributor;
|
||||
import org.springframework.boot.health.contributor.CompositeReactiveHealthContributor;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthContributor;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.health.contributor.ReactiveHealthContributor;
|
||||
import org.springframework.boot.health.contributor.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.health.registry.DefaultHealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.DefaultReactiveHealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.HealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -199,8 +211,7 @@ class HealthEndpointWebIntegrationTests {
|
|||
}
|
||||
}
|
||||
|
||||
private <R extends ContributorRegistry<?>> R getContributorRegistry(ApplicationContext context,
|
||||
Class<R> registryType) {
|
||||
private <R> R getContributorRegistry(ApplicationContext context, Class<R> registryType) {
|
||||
return context.getBeanProvider(registryType).getIfAvailable();
|
||||
}
|
||||
|
||||
|
@ -241,41 +252,44 @@ class HealthEndpointWebIntegrationTests {
|
|||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
HealthContributorRegistry healthContributorRegistry(Map<String, HealthContributor> healthContributorBeans) {
|
||||
return new DefaultHealthContributorRegistry(healthContributorBeans);
|
||||
HealthContributorRegistry healthContributorRegistry(Map<String, HealthContributor> contributorBeans) {
|
||||
return new DefaultHealthContributorRegistry(null,
|
||||
HealthContributorNameGenerator.withoutStandardSuffixes().registrar(contributorBeans));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnWebApplication(type = Type.REACTIVE)
|
||||
ReactiveHealthContributorRegistry reactiveHealthContributorRegistry(
|
||||
Map<String, HealthContributor> healthContributorBeans,
|
||||
Map<String, ReactiveHealthContributor> reactiveHealthContributorBeans) {
|
||||
Map<String, ReactiveHealthContributor> allIndicators = new LinkedHashMap<>(reactiveHealthContributorBeans);
|
||||
healthContributorBeans.forEach((name, contributor) -> allIndicators.computeIfAbsent(name,
|
||||
(key) -> ReactiveHealthContributor.adapt(contributor)));
|
||||
return new DefaultReactiveHealthContributorRegistry(allIndicators);
|
||||
Map<String, ReactiveHealthContributor> contributorBeans) {
|
||||
return new DefaultReactiveHealthContributorRegistry(null,
|
||||
HealthContributorNameGenerator.withoutStandardSuffixes().registrar(contributorBeans));
|
||||
}
|
||||
|
||||
@Bean
|
||||
HealthEndpoint healthEndpoint(HealthContributorRegistry healthContributorRegistry,
|
||||
ObjectProvider<ReactiveHealthContributorRegistry> reactiveHealthContributorRegistry,
|
||||
HealthEndpointGroups healthEndpointGroups) {
|
||||
return new HealthEndpoint(healthContributorRegistry, healthEndpointGroups, null);
|
||||
return new HealthEndpoint(healthContributorRegistry, reactiveHealthContributorRegistry.getIfAvailable(),
|
||||
healthEndpointGroups, null);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
HealthEndpointWebExtension healthWebEndpointExtension(HealthContributorRegistry healthContributorRegistry,
|
||||
ObjectProvider<ReactiveHealthContributorRegistry> reactiveHealthContributorRegistry,
|
||||
HealthEndpointGroups healthEndpointGroups) {
|
||||
return new HealthEndpointWebExtension(healthContributorRegistry, healthEndpointGroups, null);
|
||||
return new HealthEndpointWebExtension(healthContributorRegistry,
|
||||
reactiveHealthContributorRegistry.getIfAvailable(), healthEndpointGroups, null);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnWebApplication(type = Type.REACTIVE)
|
||||
ReactiveHealthEndpointWebExtension reactiveHealthWebEndpointExtension(
|
||||
ReactiveHealthContributorRegistry reactiveHealthContributorRegistry,
|
||||
ObjectProvider<HealthContributorRegistry> healthContributorRegistry,
|
||||
HealthEndpointGroups healthEndpointGroups) {
|
||||
return new ReactiveHealthEndpointWebExtension(reactiveHealthContributorRegistry, healthEndpointGroups,
|
||||
null);
|
||||
return new ReactiveHealthEndpointWebExtension(reactiveHealthContributorRegistry,
|
||||
healthContributorRegistry.getIfAvailable(), healthEndpointGroups, null);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
|
@ -27,6 +27,7 @@ description = "Spring Boot Actuator"
|
|||
dependencies {
|
||||
api(project(":spring-boot-project:spring-boot"))
|
||||
|
||||
optional(project(":spring-boot-project:spring-boot-health"))
|
||||
optional(project(":spring-boot-project:spring-boot-http-converter"))
|
||||
optional(project(":spring-boot-project:spring-boot-jsonb"))
|
||||
optional(project(":spring-boot-project:spring-boot-validation"))
|
||||
|
|
|
@ -21,12 +21,12 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health.Builder;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.availability.ApplicationAvailability;
|
||||
import org.springframework.boot.availability.AvailabilityState;
|
||||
import org.springframework.boot.health.contributor.AbstractHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
@ -76,7 +76,7 @@ public class AvailabilityStateHealthIndicator extends AbstractHealthIndicator {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Builder builder) throws Exception {
|
||||
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||
AvailabilityState state = getState(this.applicationAvailability);
|
||||
Status status = this.statusMappings.get(state);
|
||||
if (status == null) {
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
package org.springframework.boot.actuate.availability;
|
||||
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.availability.ApplicationAvailability;
|
||||
import org.springframework.boot.availability.AvailabilityState;
|
||||
import org.springframework.boot.availability.LivenessState;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
/**
|
||||
* A {@link HealthIndicator} that checks the {@link LivenessState} of the application.
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
package org.springframework.boot.actuate.availability;
|
||||
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.availability.ApplicationAvailability;
|
||||
import org.springframework.boot.availability.AvailabilityState;
|
||||
import org.springframework.boot.availability.ReadinessState;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
/**
|
||||
* A {@link HealthIndicator} that checks the {@link ReadinessState} of the application.
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.Iterator;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Adapts a {@link CompositeHealthContributor} to a
|
||||
* {@link CompositeReactiveHealthContributor} so that it can be safely invoked in a
|
||||
* reactive environment.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see ReactiveHealthContributor#adapt(HealthContributor)
|
||||
*/
|
||||
class CompositeHealthContributorReactiveAdapter implements CompositeReactiveHealthContributor {
|
||||
|
||||
private final CompositeHealthContributor delegate;
|
||||
|
||||
CompositeHealthContributorReactiveAdapter(CompositeHealthContributor delegate) {
|
||||
Assert.notNull(delegate, "'delegate' must not be null");
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<NamedContributor<ReactiveHealthContributor>> iterator() {
|
||||
Iterator<NamedContributor<HealthContributor>> iterator = this.delegate.iterator();
|
||||
return new Iterator<>() {
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedContributor<ReactiveHealthContributor> next() {
|
||||
NamedContributor<HealthContributor> namedContributor = iterator.next();
|
||||
return NamedContributor.of(namedContributor.getName(),
|
||||
ReactiveHealthContributor.adapt(namedContributor.getContributor()));
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReactiveHealthContributor getContributor(String name) {
|
||||
HealthContributor contributor = this.delegate.getContributor(name);
|
||||
return (contributor != null) ? ReactiveHealthContributor.adapt(contributor) : null;
|
||||
}
|
||||
|
||||
}
|
|
@ -21,37 +21,32 @@ import java.util.TreeMap;
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.ApiVersion;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link HealthComponent} that is composed of other {@link HealthComponent} instances.
|
||||
* Used to provide a unified view of related components. For example, a database health
|
||||
* indicator may be a composite containing the {@link Health} of each datasource
|
||||
* connection.
|
||||
* Description of health that is composed of other {@link HealthDescriptor health
|
||||
* descriptors}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.2.0
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public class CompositeHealth extends HealthComponent {
|
||||
public sealed class CompositeHealthDescriptor extends HealthDescriptor permits SystemHealthDescriptor {
|
||||
|
||||
private final ApiVersion apiVersion;
|
||||
|
||||
private final Status status;
|
||||
|
||||
private final Map<String, HealthComponent> components;
|
||||
private final Map<String, HealthDescriptor> components;
|
||||
|
||||
private final Map<String, HealthComponent> details;
|
||||
|
||||
CompositeHealth(ApiVersion apiVersion, Status status, Map<String, HealthComponent> components) {
|
||||
CompositeHealthDescriptor(ApiVersion apiVersion, Status status, Map<String, HealthDescriptor> components) {
|
||||
Assert.notNull(apiVersion, "'apiVersion' must not be null");
|
||||
Assert.notNull(status, "'status' must not be null");
|
||||
this.apiVersion = apiVersion;
|
||||
this.status = status;
|
||||
this.components = (apiVersion != ApiVersion.V3) ? null : sort(components);
|
||||
this.details = (apiVersion != ApiVersion.V2) ? null : sort(components);
|
||||
}
|
||||
|
||||
private Map<String, HealthComponent> sort(Map<String, HealthComponent> components) {
|
||||
return (components != null) ? new TreeMap<>(components) : components;
|
||||
this.components = (components != null) ? new TreeMap<>(components) : components;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -60,14 +55,13 @@ public class CompositeHealth extends HealthComponent {
|
|||
}
|
||||
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
public Map<String, HealthComponent> getComponents() {
|
||||
return this.components;
|
||||
public Map<String, HealthDescriptor> getComponents() {
|
||||
return (this.apiVersion == ApiVersion.V3) ? this.components : null;
|
||||
}
|
||||
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
@JsonProperty
|
||||
public Map<String, HealthComponent> getDetails() {
|
||||
return this.details;
|
||||
public Map<String, HealthDescriptor> getDetails() {
|
||||
return (this.apiVersion == ApiVersion.V2) ? this.components : null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.Iterator;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthContributor;
|
||||
import org.springframework.boot.health.contributor.HealthContributors;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.health.contributor.ReactiveHealthContributor;
|
||||
import org.springframework.boot.health.contributor.ReactiveHealthContributors;
|
||||
import org.springframework.boot.health.contributor.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.health.registry.HealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Allows {@link HealthEndpointSupport} to access blocking or reactive contributors and
|
||||
* registries in a uniform way.
|
||||
*
|
||||
* @param <H> the health type
|
||||
* @param <D> the descriptor type
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
sealed interface Contributor<H, D> extends Iterable<Contributor.Child<H, D>> {
|
||||
|
||||
/**
|
||||
* Return if this contributor is a composite and may have children.
|
||||
* @return if the contributor is a composite
|
||||
*/
|
||||
boolean isComposite();
|
||||
|
||||
/**
|
||||
* Get the child with the given name. Must only be called if {@link #isComposite()}
|
||||
* returns {@code true}.
|
||||
* @param name the child name
|
||||
* @return the child or {@code null}
|
||||
*/
|
||||
Contributor<H, D> getChild(String name);
|
||||
|
||||
/**
|
||||
* Get the health. Must only be called if {@link #isComposite()} returns
|
||||
* {@code false}.
|
||||
* @param includeDetails if details are to be included.
|
||||
* @return the health
|
||||
*/
|
||||
D getDescriptor(boolean includeDetails);
|
||||
|
||||
/**
|
||||
* Return an identifier for logging purposes.
|
||||
* @param name the name if known
|
||||
* @return an identifier
|
||||
*/
|
||||
default String getIdentifier(String name) {
|
||||
String className = getContributorClassName();
|
||||
return (!StringUtils.hasLength(name)) ? className : className + " (" + name + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class name of the underlying contributor.
|
||||
* @return the contributor class name
|
||||
*/
|
||||
String getContributorClassName();
|
||||
|
||||
/**
|
||||
* Factory method to create a blocking {@link Contributor} from the given registries.
|
||||
* @param registry the source registry
|
||||
* @param fallbackRegistry the fallback registry or {@code null}
|
||||
* @return a new {@link Contributor}
|
||||
*/
|
||||
static Blocking blocking(HealthContributorRegistry registry, ReactiveHealthContributorRegistry fallbackRegistry) {
|
||||
return new Blocking((fallbackRegistry != null)
|
||||
? HealthContributors.of(registry, fallbackRegistry.asHealthContributors()) : registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a reactive {@link Contributor} from the given registries.
|
||||
* @param registry the registry
|
||||
* @param fallbackRegistry the fallback registry or {@code null}
|
||||
* @return a new {@link Contributor}
|
||||
*/
|
||||
static Reactive reactive(ReactiveHealthContributorRegistry registry, HealthContributorRegistry fallbackRegistry) {
|
||||
return new Reactive((fallbackRegistry != null)
|
||||
? ReactiveHealthContributors.of(registry, ReactiveHealthContributors.adapt(fallbackRegistry))
|
||||
: registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* A child consisting of a name and a contributor.
|
||||
*
|
||||
* @param <H> the health type
|
||||
* @param <D> the descriptor type
|
||||
* @param name the child name
|
||||
* @param contributor the contributor
|
||||
*/
|
||||
record Child<H, D>(String name, Contributor<H, D> contributor) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Contributor} to adapt the blocking {@link HealthContributor} and
|
||||
* {@link HealthContributors} types.
|
||||
*
|
||||
* @param contributor the underlying contributor
|
||||
*/
|
||||
record Blocking(Object contributor) implements Contributor<Health, HealthDescriptor> {
|
||||
|
||||
@Override
|
||||
public boolean isComposite() {
|
||||
return contributor() instanceof HealthContributors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Blocking getChild(String name) {
|
||||
HealthContributor child = ((HealthContributors) contributor()).getContributor(name);
|
||||
return (child != null) ? new Blocking(child) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Child<Health, HealthDescriptor>> iterator() {
|
||||
return ((HealthContributors) contributor()).stream()
|
||||
.map((entry) -> new Child<>(entry.name(), new Blocking(entry.contributor())))
|
||||
.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HealthDescriptor getDescriptor(boolean includeDetails) {
|
||||
Health health = ((HealthIndicator) contributor()).health(includeDetails);
|
||||
return (health != null) ? new IndicatedHealthDescriptor(health) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContributorClassName() {
|
||||
return contributor().getClass().getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Contributor} to adapt the reactive {@link ReactiveHealthContributor} and
|
||||
* {@link ReactiveHealthContributors} types.
|
||||
*
|
||||
* @param contributor the underlying contributor
|
||||
*/
|
||||
record Reactive(
|
||||
Object contributor) implements Contributor<Mono<? extends Health>, Mono<? extends HealthDescriptor>> {
|
||||
|
||||
@Override
|
||||
public boolean isComposite() {
|
||||
return contributor() instanceof ReactiveHealthContributors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reactive getChild(String name) {
|
||||
ReactiveHealthContributor child = ((ReactiveHealthContributors) contributor()).getContributor(name);
|
||||
return (child != null) ? new Reactive(child) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Child<Mono<? extends Health>, Mono<? extends HealthDescriptor>>> iterator() {
|
||||
return ((ReactiveHealthContributors) contributor()).stream()
|
||||
.map((entry) -> new Child<>(entry.name(), new Reactive(entry.contributor())))
|
||||
.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<? extends HealthDescriptor> getDescriptor(boolean includeDetails) {
|
||||
Mono<Health> health = ((ReactiveHealthIndicator) this.contributor).health(includeDetails);
|
||||
return health.map(IndicatedHealthDescriptor::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContributorClassName() {
|
||||
return contributor().getClass().getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default {@link ContributorRegistry} implementation.
|
||||
*
|
||||
* @param <C> the health contributor type
|
||||
* @author Phillip Webb
|
||||
* @see DefaultHealthContributorRegistry
|
||||
* @see DefaultReactiveHealthContributorRegistry
|
||||
*/
|
||||
class DefaultContributorRegistry<C> implements ContributorRegistry<C> {
|
||||
|
||||
private final Function<String, String> nameFactory;
|
||||
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private volatile Map<String, C> contributors;
|
||||
|
||||
DefaultContributorRegistry() {
|
||||
this(Collections.emptyMap());
|
||||
}
|
||||
|
||||
DefaultContributorRegistry(Map<String, C> contributors) {
|
||||
this(contributors, HealthContributorNameFactory.INSTANCE);
|
||||
}
|
||||
|
||||
DefaultContributorRegistry(Map<String, C> contributors, Function<String, String> nameFactory) {
|
||||
Assert.notNull(contributors, "'contributors' must not be null");
|
||||
Assert.notNull(nameFactory, "'nameFactory' must not be null");
|
||||
this.nameFactory = nameFactory;
|
||||
Map<String, C> namedContributors = new LinkedHashMap<>();
|
||||
contributors.forEach((name, contributor) -> namedContributors.put(nameFactory.apply(name), contributor));
|
||||
this.contributors = Collections.unmodifiableMap(namedContributors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerContributor(String name, C contributor) {
|
||||
Assert.notNull(name, "'name' must not be null");
|
||||
Assert.notNull(contributor, "'contributor' must not be null");
|
||||
String adaptedName = this.nameFactory.apply(name);
|
||||
synchronized (this.monitor) {
|
||||
Assert.state(!this.contributors.containsKey(adaptedName),
|
||||
() -> "A contributor named \"" + adaptedName + "\" has already been registered");
|
||||
Map<String, C> contributors = new LinkedHashMap<>(this.contributors);
|
||||
contributors.put(adaptedName, contributor);
|
||||
this.contributors = Collections.unmodifiableMap(contributors);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public C unregisterContributor(String name) {
|
||||
Assert.notNull(name, "'name' must not be null");
|
||||
String adaptedName = this.nameFactory.apply(name);
|
||||
synchronized (this.monitor) {
|
||||
C unregistered = this.contributors.get(adaptedName);
|
||||
if (unregistered != null) {
|
||||
Map<String, C> contributors = new LinkedHashMap<>(this.contributors);
|
||||
contributors.remove(adaptedName);
|
||||
this.contributors = Collections.unmodifiableMap(contributors);
|
||||
}
|
||||
return unregistered;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public C getContributor(String name) {
|
||||
return this.contributors.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<NamedContributor<C>> iterator() {
|
||||
Iterator<Map.Entry<String, C>> iterator = this.contributors.entrySet().iterator();
|
||||
return new Iterator<>() {
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedContributor<C> next() {
|
||||
Entry<String, C> entry = iterator.next();
|
||||
return NamedContributor.of(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Default {@link HealthContributorRegistry} implementation.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public class DefaultHealthContributorRegistry extends DefaultContributorRegistry<HealthContributor>
|
||||
implements HealthContributorRegistry {
|
||||
|
||||
public DefaultHealthContributorRegistry() {
|
||||
}
|
||||
|
||||
public DefaultHealthContributorRegistry(Map<String, HealthContributor> contributors) {
|
||||
super(contributors);
|
||||
}
|
||||
|
||||
public DefaultHealthContributorRegistry(Map<String, HealthContributor> contributors,
|
||||
Function<String, String> nameFactory) {
|
||||
super(contributors, nameFactory);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Default {@link ReactiveHealthContributorRegistry} implementation.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class DefaultReactiveHealthContributorRegistry extends DefaultContributorRegistry<ReactiveHealthContributor>
|
||||
implements ReactiveHealthContributorRegistry {
|
||||
|
||||
public DefaultReactiveHealthContributorRegistry() {
|
||||
}
|
||||
|
||||
public DefaultReactiveHealthContributorRegistry(Map<String, ReactiveHealthContributor> contributors) {
|
||||
super(contributors);
|
||||
}
|
||||
|
||||
public DefaultReactiveHealthContributorRegistry(Map<String, ReactiveHealthContributor> contributors,
|
||||
Function<String, String> nameFactory) {
|
||||
super(contributors, nameFactory);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.Locale;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Generate a sensible health indicator name based on its bean name.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class HealthContributorNameFactory implements Function<String, String> {
|
||||
|
||||
private static final String[] SUFFIXES = { "healthindicator", "healthcontributor" };
|
||||
|
||||
/**
|
||||
* A shared singleton {@link HealthContributorNameFactory} instance.
|
||||
*/
|
||||
public static final HealthContributorNameFactory INSTANCE = new HealthContributorNameFactory();
|
||||
|
||||
@Override
|
||||
public String apply(String name) {
|
||||
for (String suffix : SUFFIXES) {
|
||||
if (name != null && name.toLowerCase(Locale.ENGLISH).endsWith(suffix)) {
|
||||
return name.substring(0, name.length() - suffix.length());
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
|
@ -19,19 +19,16 @@ package org.springframework.boot.actuate.health;
|
|||
import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
/**
|
||||
* A component that contributes data to results returned from the {@link HealthEndpoint}.
|
||||
* Description of health including a status.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.2.0
|
||||
* @see Health
|
||||
* @see CompositeHealth
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public abstract class HealthComponent implements OperationResponseBody {
|
||||
|
||||
HealthComponent() {
|
||||
}
|
||||
public abstract sealed class HealthDescriptor implements OperationResponseBody
|
||||
permits IndicatedHealthDescriptor, CompositeHealthDescriptor {
|
||||
|
||||
/**
|
||||
* Return the status of the component.
|
|
@ -27,6 +27,9 @@ import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
|||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Selector;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Selector.Match;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.registry.HealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;
|
||||
|
||||
/**
|
||||
* {@link Endpoint @Endpoint} to expose application health information.
|
||||
|
@ -39,53 +42,47 @@ import org.springframework.boot.actuate.endpoint.annotation.Selector.Match;
|
|||
* @since 2.0.0
|
||||
*/
|
||||
@Endpoint(id = "health")
|
||||
public class HealthEndpoint extends HealthEndpointSupport<HealthContributor, HealthComponent> {
|
||||
public class HealthEndpoint extends HealthEndpointSupport<Health, HealthDescriptor> {
|
||||
|
||||
/**
|
||||
* Health endpoint id.
|
||||
*/
|
||||
public static final EndpointId ID = EndpointId.of("health");
|
||||
|
||||
private static final String[] EMPTY_PATH = {};
|
||||
|
||||
/**
|
||||
* Create a new {@link HealthEndpoint} instance.
|
||||
* @param registry the health contributor registry
|
||||
* @param fallbackRegistry the fallback registry or {@code null}
|
||||
* @param groups the health endpoint groups
|
||||
* @param slowIndicatorLoggingThreshold duration after which slow health indicator
|
||||
* @param slowContributorLoggingThreshold duration after which slow health indicator
|
||||
* logging should occur
|
||||
* @since 2.6.9
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public HealthEndpoint(HealthContributorRegistry registry, HealthEndpointGroups groups,
|
||||
Duration slowIndicatorLoggingThreshold) {
|
||||
super(registry, groups, slowIndicatorLoggingThreshold);
|
||||
public HealthEndpoint(HealthContributorRegistry registry, ReactiveHealthContributorRegistry fallbackRegistry,
|
||||
HealthEndpointGroups groups, Duration slowContributorLoggingThreshold) {
|
||||
super(Contributor.blocking(registry, fallbackRegistry), groups, slowContributorLoggingThreshold);
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public HealthComponent health() {
|
||||
HealthComponent health = health(ApiVersion.V3, EMPTY_PATH);
|
||||
return (health != null) ? health : DEFAULT_HEALTH;
|
||||
public HealthDescriptor health() {
|
||||
HealthDescriptor health = health(ApiVersion.V3, EMPTY_PATH);
|
||||
return (health != null) ? health : IndicatedHealthDescriptor.UP;
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public HealthComponent healthForPath(@Selector(match = Match.ALL_REMAINING) String... path) {
|
||||
public HealthDescriptor healthForPath(@Selector(match = Match.ALL_REMAINING) String... path) {
|
||||
return health(ApiVersion.V3, path);
|
||||
}
|
||||
|
||||
private HealthComponent health(ApiVersion apiVersion, String... path) {
|
||||
HealthResult<HealthComponent> result = getHealth(apiVersion, null, SecurityContext.NONE, true, path);
|
||||
return (result != null) ? result.getHealth() : null;
|
||||
private HealthDescriptor health(ApiVersion apiVersion, String... path) {
|
||||
Result<HealthDescriptor> result = getResult(apiVersion, null, SecurityContext.NONE, true, path);
|
||||
return (result != null) ? result.descriptor() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HealthComponent getHealth(HealthContributor contributor, boolean includeDetails) {
|
||||
return ((HealthIndicator) contributor).getHealth(includeDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HealthComponent aggregateContributions(ApiVersion apiVersion, Map<String, HealthComponent> contributions,
|
||||
protected HealthDescriptor aggregateDescriptors(ApiVersion apiVersion, Map<String, HealthDescriptor> contributions,
|
||||
StatusAggregator statusAggregator, boolean showComponents, Set<String> groupNames) {
|
||||
return getCompositeHealth(apiVersion, contributions, statusAggregator, showComponents, groupNames);
|
||||
return getCompositeDescriptor(apiVersion, contributions, statusAggregator, showComponents, groupNames);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
package org.springframework.boot.actuate.health;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.SecurityContext;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthContributor;
|
||||
|
||||
/**
|
||||
* A logical grouping of {@link HealthContributor health contributors} that can be exposed
|
||||
|
@ -36,8 +38,8 @@ public interface HealthEndpointGroup {
|
|||
boolean isMember(String name);
|
||||
|
||||
/**
|
||||
* Returns if {@link CompositeHealth#getComponents() health components} should be
|
||||
* shown in the response.
|
||||
* Returns if {@link CompositeHealthDescriptor#getComponents() health components}
|
||||
* should be shown in the response.
|
||||
* @param securityContext the endpoint security context
|
||||
* @return {@code true} to shown details or {@code false} to hide them
|
||||
*/
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.time.Instant;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
@ -30,6 +31,7 @@ import org.springframework.boot.actuate.endpoint.ApiVersion;
|
|||
import org.springframework.boot.actuate.endpoint.SecurityContext;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.convert.DurationStyle;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
@ -37,62 +39,59 @@ import org.springframework.util.StringUtils;
|
|||
/**
|
||||
* Base class for health endpoints and health endpoint extensions.
|
||||
*
|
||||
* @param <C> the contributor type
|
||||
* @param <T> the contributed health component type
|
||||
* @param <H> the health type
|
||||
* @param <D> the descriptor type
|
||||
* @author Phillip Webb
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
abstract class HealthEndpointSupport<C, T> {
|
||||
abstract class HealthEndpointSupport<H, D> {
|
||||
|
||||
static final String[] EMPTY_PATH = {};
|
||||
|
||||
private static final Log logger = LogFactory.getLog(HealthEndpointSupport.class);
|
||||
|
||||
static final Health DEFAULT_HEALTH = Health.up().build();
|
||||
|
||||
private final ContributorRegistry<C> registry;
|
||||
private final Contributor<H, D> rootContributor;
|
||||
|
||||
private final HealthEndpointGroups groups;
|
||||
|
||||
private final Duration slowIndicatorLoggingThreshold;
|
||||
private final Duration slowContributorLoggingThreshold;
|
||||
|
||||
/**
|
||||
* Create a new {@link HealthEndpointSupport} instance.
|
||||
* @param registry the health contributor registry
|
||||
* @param rootContributor the health contributor registry
|
||||
* @param groups the health endpoint groups
|
||||
* @param slowIndicatorLoggingThreshold duration after which slow health indicator
|
||||
* @param slowContributorLoggingThreshold duration after which slow health contributor
|
||||
* logging should occur
|
||||
*/
|
||||
HealthEndpointSupport(ContributorRegistry<C> registry, HealthEndpointGroups groups,
|
||||
Duration slowIndicatorLoggingThreshold) {
|
||||
Assert.notNull(registry, "'registry' must not be null");
|
||||
HealthEndpointSupport(Contributor<H, D> rootContributor, HealthEndpointGroups groups,
|
||||
Duration slowContributorLoggingThreshold) {
|
||||
Assert.notNull(rootContributor, "'rootContributor' must not be null");
|
||||
Assert.notNull(groups, "'groups' must not be null");
|
||||
this.registry = registry;
|
||||
this.rootContributor = rootContributor;
|
||||
this.groups = groups;
|
||||
this.slowIndicatorLoggingThreshold = slowIndicatorLoggingThreshold;
|
||||
this.slowContributorLoggingThreshold = slowContributorLoggingThreshold;
|
||||
}
|
||||
|
||||
HealthResult<T> getHealth(ApiVersion apiVersion, WebServerNamespace serverNamespace,
|
||||
SecurityContext securityContext, boolean showAll, String... path) {
|
||||
if (path.length > 0) {
|
||||
HealthEndpointGroup group = getHealthGroup(serverNamespace, path);
|
||||
if (group != null) {
|
||||
return getHealth(apiVersion, group, securityContext, showAll, path, 1);
|
||||
}
|
||||
Result<D> getResult(ApiVersion apiVersion, WebServerNamespace serverNamespace, SecurityContext securityContext,
|
||||
boolean showAll, String... path) {
|
||||
HealthEndpointGroup group = (path.length > 0) ? getGroup(serverNamespace, path) : null;
|
||||
if (group != null) {
|
||||
return getResult(apiVersion, group, securityContext, showAll, path, 1);
|
||||
}
|
||||
return getHealth(apiVersion, this.groups.getPrimary(), securityContext, showAll, path, 0);
|
||||
return getResult(apiVersion, this.groups.getPrimary(), securityContext, showAll, path, 0);
|
||||
}
|
||||
|
||||
private HealthEndpointGroup getHealthGroup(WebServerNamespace serverNamespace, String... path) {
|
||||
private HealthEndpointGroup getGroup(WebServerNamespace serverNamespace, String... path) {
|
||||
if (this.groups.get(path[0]) != null) {
|
||||
return this.groups.get(path[0]);
|
||||
}
|
||||
if (serverNamespace != null) {
|
||||
AdditionalHealthEndpointPath additionalPath = AdditionalHealthEndpointPath.of(serverNamespace, path[0]);
|
||||
return this.groups.get(additionalPath);
|
||||
return this.groups.get(AdditionalHealthEndpointPath.of(serverNamespace, path[0]));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private HealthResult<T> getHealth(ApiVersion apiVersion, HealthEndpointGroup group, SecurityContext securityContext,
|
||||
private Result<D> getResult(ApiVersion apiVersion, HealthEndpointGroup group, SecurityContext securityContext,
|
||||
boolean showAll, String[] path, int pathOffset) {
|
||||
boolean showComponents = showAll || group.showComponents(securityContext);
|
||||
boolean showDetails = showAll || group.showDetails(securityContext);
|
||||
|
@ -101,24 +100,23 @@ abstract class HealthEndpointSupport<C, T> {
|
|||
if (!showComponents && !isRoot) {
|
||||
return null;
|
||||
}
|
||||
Object contributor = getContributor(path, pathOffset);
|
||||
Contributor<H, D> contributor = getContributor(path, pathOffset);
|
||||
if (contributor == null) {
|
||||
return null;
|
||||
}
|
||||
String name = getName(path, pathOffset);
|
||||
Set<String> groupNames = isSystemHealth ? this.groups.getNames() : null;
|
||||
T health = getContribution(apiVersion, group, name, contributor, showComponents, showDetails, groupNames);
|
||||
return (health != null) ? new HealthResult<>(health, group) : null;
|
||||
Set<String> groupNames = (!isSystemHealth) ? null : new TreeSet<>(this.groups.getNames());
|
||||
D descriptor = getDescriptor(apiVersion, group, name, contributor, showComponents, showDetails, groupNames);
|
||||
return (descriptor != null) ? new Result<>(descriptor, group) : null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object getContributor(String[] path, int pathOffset) {
|
||||
Object contributor = this.registry;
|
||||
private Contributor<H, D> getContributor(String[] path, int pathOffset) {
|
||||
Contributor<H, D> contributor = this.rootContributor;
|
||||
while (pathOffset < path.length) {
|
||||
if (!(contributor instanceof NamedContributors)) {
|
||||
if (!contributor.isComposite()) {
|
||||
return null;
|
||||
}
|
||||
contributor = ((NamedContributors<C>) contributor).getContributor(path[pathOffset]);
|
||||
contributor = contributor.getChild(path[pathOffset]);
|
||||
pathOffset++;
|
||||
}
|
||||
return contributor;
|
||||
|
@ -134,100 +132,77 @@ abstract class HealthEndpointSupport<C, T> {
|
|||
return name.toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private T getContribution(ApiVersion apiVersion, HealthEndpointGroup group, String name, Object contributor,
|
||||
boolean showComponents, boolean showDetails, Set<String> groupNames) {
|
||||
if (contributor instanceof NamedContributors) {
|
||||
return getAggregateContribution(apiVersion, group, name, (NamedContributors<C>) contributor, showComponents,
|
||||
showDetails, groupNames);
|
||||
private D getDescriptor(ApiVersion apiVersion, HealthEndpointGroup group, String name,
|
||||
Contributor<H, D> contributor, boolean showComponents, boolean showDetails, Set<String> groupNames) {
|
||||
if (contributor.isComposite()) {
|
||||
return getAggregateDescriptor(apiVersion, group, name, contributor, showComponents, showDetails,
|
||||
groupNames);
|
||||
}
|
||||
if (contributor != null && (name.isEmpty() || group.isMember(name))) {
|
||||
return getLoggedHealth((C) contributor, name, showDetails);
|
||||
if (name.isEmpty() || group.isMember(name)) {
|
||||
return getDescriptorAndLogIfSlow(contributor, name, showDetails);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private T getAggregateContribution(ApiVersion apiVersion, HealthEndpointGroup group, String name,
|
||||
NamedContributors<C> namedContributors, boolean showComponents, boolean showDetails,
|
||||
Set<String> groupNames) {
|
||||
private D getAggregateDescriptor(ApiVersion apiVersion, HealthEndpointGroup group, String name,
|
||||
Contributor<H, D> contributor, boolean showComponents, boolean showDetails, Set<String> groupNames) {
|
||||
String prefix = (StringUtils.hasText(name)) ? name + "/" : "";
|
||||
Map<String, T> contributions = new LinkedHashMap<>();
|
||||
for (NamedContributor<C> child : namedContributors) {
|
||||
T contribution = getContribution(apiVersion, group, prefix + child.getName(), child.getContributor(),
|
||||
showComponents, showDetails, null);
|
||||
if (contribution != null) {
|
||||
contributions.put(child.getName(), contribution);
|
||||
Map<String, D> descriptors = new LinkedHashMap<>();
|
||||
for (Contributor.Child<H, D> child : contributor) {
|
||||
String childName = child.name();
|
||||
D descriptor = getDescriptor(apiVersion, group, prefix + childName, child.contributor(), showComponents,
|
||||
showDetails, null);
|
||||
if (descriptor != null) {
|
||||
descriptors.put(childName, descriptor);
|
||||
}
|
||||
}
|
||||
if (contributions.isEmpty()) {
|
||||
if (descriptors.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return aggregateContributions(apiVersion, contributions, group.getStatusAggregator(), showComponents,
|
||||
groupNames);
|
||||
return aggregateDescriptors(apiVersion, descriptors, group.getStatusAggregator(), showComponents, groupNames);
|
||||
}
|
||||
|
||||
private T getLoggedHealth(C contributor, String name, boolean showDetails) {
|
||||
private D getDescriptorAndLogIfSlow(Contributor<H, D> contributor, String name, boolean showDetails) {
|
||||
Instant start = Instant.now();
|
||||
try {
|
||||
return getHealth(contributor, showDetails);
|
||||
return contributor.getDescriptor(showDetails);
|
||||
}
|
||||
finally {
|
||||
if (logger.isWarnEnabled() && this.slowIndicatorLoggingThreshold != null) {
|
||||
if (logger.isWarnEnabled() && this.slowContributorLoggingThreshold != null) {
|
||||
Duration duration = Duration.between(start, Instant.now());
|
||||
if (duration.compareTo(this.slowIndicatorLoggingThreshold) > 0) {
|
||||
String contributorClassName = contributor.getClass().getName();
|
||||
Object contributorIdentifier = (!StringUtils.hasLength(name)) ? contributorClassName
|
||||
: contributorClassName + " (" + name + ")";
|
||||
logger.warn(LogMessage.format("Health contributor %s took %s to respond", contributorIdentifier,
|
||||
DurationStyle.SIMPLE.print(duration)));
|
||||
if (duration.compareTo(this.slowContributorLoggingThreshold) > 0) {
|
||||
logger.warn(LogMessage.format("Health contributor %s took %s to respond",
|
||||
contributor.getIdentifier(name), DurationStyle.SIMPLE.print(duration)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract T getHealth(C contributor, boolean includeDetails);
|
||||
|
||||
protected abstract T aggregateContributions(ApiVersion apiVersion, Map<String, T> contributions,
|
||||
abstract D aggregateDescriptors(ApiVersion apiVersion, Map<String, D> descriptors,
|
||||
StatusAggregator statusAggregator, boolean showComponents, Set<String> groupNames);
|
||||
|
||||
protected final CompositeHealth getCompositeHealth(ApiVersion apiVersion, Map<String, HealthComponent> components,
|
||||
StatusAggregator statusAggregator, boolean showComponents, Set<String> groupNames) {
|
||||
final CompositeHealthDescriptor getCompositeDescriptor(ApiVersion apiVersion,
|
||||
Map<String, HealthDescriptor> descriptors, StatusAggregator statusAggregator, boolean showComponents,
|
||||
Set<String> groupNames) {
|
||||
Status status = statusAggregator
|
||||
.getAggregateStatus(components.values().stream().map(this::getStatus).collect(Collectors.toSet()));
|
||||
Map<String, HealthComponent> instances = showComponents ? components : null;
|
||||
if (groupNames != null) {
|
||||
return new SystemHealth(apiVersion, status, instances, groupNames);
|
||||
}
|
||||
return new CompositeHealth(apiVersion, status, instances);
|
||||
.getAggregateStatus(descriptors.values().stream().map(this::getStatus).collect(Collectors.toSet()));
|
||||
descriptors = (!showComponents) ? null : descriptors;
|
||||
return (groupNames != null) ? new SystemHealthDescriptor(apiVersion, status, descriptors, groupNames)
|
||||
: new CompositeHealthDescriptor(apiVersion, status, descriptors);
|
||||
}
|
||||
|
||||
private Status getStatus(HealthComponent component) {
|
||||
private Status getStatus(HealthDescriptor component) {
|
||||
return (component != null) ? component.getStatus() : Status.UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* A health result containing health and the group that created it.
|
||||
* A health result containing descriptor and the group that created it.
|
||||
*
|
||||
* @param <T> the contributed health component
|
||||
* @param descriptor the health descriptor
|
||||
* @param group the group used to create the health
|
||||
* @param <D> the details type
|
||||
*/
|
||||
static class HealthResult<T> {
|
||||
|
||||
private final T health;
|
||||
|
||||
private final HealthEndpointGroup group;
|
||||
|
||||
HealthResult(T health, HealthEndpointGroup group) {
|
||||
this.health = health;
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
T getHealth() {
|
||||
return this.health;
|
||||
}
|
||||
|
||||
HealthEndpointGroup getGroup() {
|
||||
return this.group;
|
||||
}
|
||||
record Result<D>(D descriptor, HealthEndpointGroup group) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,9 @@ import org.springframework.boot.actuate.endpoint.annotation.Selector.Match;
|
|||
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.registry.HealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;
|
||||
import org.springframework.context.annotation.ImportRuntimeHints;
|
||||
|
||||
/**
|
||||
|
@ -46,58 +49,53 @@ import org.springframework.context.annotation.ImportRuntimeHints;
|
|||
*/
|
||||
@EndpointWebExtension(endpoint = HealthEndpoint.class)
|
||||
@ImportRuntimeHints(HealthEndpointWebExtensionRuntimeHints.class)
|
||||
public class HealthEndpointWebExtension extends HealthEndpointSupport<HealthContributor, HealthComponent> {
|
||||
|
||||
private static final String[] NO_PATH = {};
|
||||
public class HealthEndpointWebExtension extends HealthEndpointSupport<Health, HealthDescriptor> {
|
||||
|
||||
/**
|
||||
* Create a new {@link HealthEndpointWebExtension} instance.
|
||||
* @param registry the health contributor registry
|
||||
* @param fallbackRegistry the fallback registry or {@code null}
|
||||
* @param groups the health endpoint groups
|
||||
* @param slowIndicatorLoggingThreshold duration after which slow health indicator
|
||||
* @param slowContributorLoggingThreshold duration after which slow health indicator
|
||||
* logging should occur
|
||||
* @since 2.6.9
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public HealthEndpointWebExtension(HealthContributorRegistry registry, HealthEndpointGroups groups,
|
||||
Duration slowIndicatorLoggingThreshold) {
|
||||
super(registry, groups, slowIndicatorLoggingThreshold);
|
||||
public HealthEndpointWebExtension(HealthContributorRegistry registry,
|
||||
ReactiveHealthContributorRegistry fallbackRegistry, HealthEndpointGroups groups,
|
||||
Duration slowContributorLoggingThreshold) {
|
||||
super(Contributor.blocking(registry, fallbackRegistry), groups, slowContributorLoggingThreshold);
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public WebEndpointResponse<HealthComponent> health(ApiVersion apiVersion, WebServerNamespace serverNamespace,
|
||||
public WebEndpointResponse<HealthDescriptor> health(ApiVersion apiVersion, WebServerNamespace serverNamespace,
|
||||
SecurityContext securityContext) {
|
||||
return health(apiVersion, serverNamespace, securityContext, false, NO_PATH);
|
||||
return health(apiVersion, serverNamespace, securityContext, false, EMPTY_PATH);
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public WebEndpointResponse<HealthComponent> health(ApiVersion apiVersion, WebServerNamespace serverNamespace,
|
||||
public WebEndpointResponse<HealthDescriptor> health(ApiVersion apiVersion, WebServerNamespace serverNamespace,
|
||||
SecurityContext securityContext, @Selector(match = Match.ALL_REMAINING) String... path) {
|
||||
return health(apiVersion, serverNamespace, securityContext, false, path);
|
||||
}
|
||||
|
||||
public WebEndpointResponse<HealthComponent> health(ApiVersion apiVersion, WebServerNamespace serverNamespace,
|
||||
public WebEndpointResponse<HealthDescriptor> health(ApiVersion apiVersion, WebServerNamespace serverNamespace,
|
||||
SecurityContext securityContext, boolean showAll, String... path) {
|
||||
HealthResult<HealthComponent> result = getHealth(apiVersion, serverNamespace, securityContext, showAll, path);
|
||||
Result<HealthDescriptor> result = getResult(apiVersion, serverNamespace, securityContext, showAll, path);
|
||||
if (result == null) {
|
||||
return (Arrays.equals(path, NO_PATH))
|
||||
? new WebEndpointResponse<>(DEFAULT_HEALTH, WebEndpointResponse.STATUS_OK)
|
||||
return (Arrays.equals(path, EMPTY_PATH))
|
||||
? new WebEndpointResponse<>(IndicatedHealthDescriptor.UP, WebEndpointResponse.STATUS_OK)
|
||||
: new WebEndpointResponse<>(WebEndpointResponse.STATUS_NOT_FOUND);
|
||||
}
|
||||
HealthComponent health = result.getHealth();
|
||||
HealthEndpointGroup group = result.getGroup();
|
||||
int statusCode = group.getHttpCodeStatusMapper().getStatusCode(health.getStatus());
|
||||
return new WebEndpointResponse<>(health, statusCode);
|
||||
HealthDescriptor descriptor = result.descriptor();
|
||||
HealthEndpointGroup group = result.group();
|
||||
int statusCode = group.getHttpCodeStatusMapper().getStatusCode(descriptor.getStatus());
|
||||
return new WebEndpointResponse<>(descriptor, statusCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HealthComponent getHealth(HealthContributor contributor, boolean includeDetails) {
|
||||
return ((HealthIndicator) contributor).getHealth(includeDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HealthComponent aggregateContributions(ApiVersion apiVersion, Map<String, HealthComponent> contributions,
|
||||
protected HealthDescriptor aggregateDescriptors(ApiVersion apiVersion, Map<String, HealthDescriptor> contributions,
|
||||
StatusAggregator statusAggregator, boolean showComponents, Set<String> groupNames) {
|
||||
return getCompositeHealth(apiVersion, contributions, statusAggregator, showComponents, groupNames);
|
||||
return getCompositeDescriptor(apiVersion, contributions, statusAggregator, showComponents, groupNames);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,8 +32,8 @@ class HealthEndpointWebExtensionRuntimeHints implements RuntimeHintsRegistrar {
|
|||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Health.class, SystemHealth.class,
|
||||
CompositeHealth.class);
|
||||
this.bindingRegistrar.registerReflectionHints(hints.reflection(), IndicatedHealthDescriptor.class,
|
||||
CompositeHealthDescriptor.class, SystemHealthDescriptor.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.boot.actuate.health;
|
||||
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
/**
|
||||
* Strategy used to map a {@link Status health status} to an HTTP status code.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2012-present 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;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.health.contributor.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
/**
|
||||
* Description of health obtained from a {@link HealthIndicator} or
|
||||
* {@link ReactiveHealthIndicator}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public final class IndicatedHealthDescriptor extends HealthDescriptor {
|
||||
|
||||
static final IndicatedHealthDescriptor UP = new IndicatedHealthDescriptor(Health.up().build());
|
||||
|
||||
private final Health health;
|
||||
|
||||
IndicatedHealthDescriptor(Health health) {
|
||||
this.health = health;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status getStatus() {
|
||||
return this.health.getStatus();
|
||||
}
|
||||
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
public Map<String, Object> getDetails() {
|
||||
return this.health.getDetails();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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 org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A single named health endpoint contributors (either {@link HealthContributor} or
|
||||
* {@link ReactiveHealthContributor}).
|
||||
*
|
||||
* @param <C> the contributor type
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
* @see NamedContributors
|
||||
*/
|
||||
public interface NamedContributor<C> {
|
||||
|
||||
/**
|
||||
* Returns the name of the contributor.
|
||||
* @return the contributor name
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Returns the contributor instance.
|
||||
* @return the contributor instance
|
||||
*/
|
||||
C getContributor();
|
||||
|
||||
static <C> NamedContributor<C> of(String name, C contributor) {
|
||||
Assert.notNull(name, "'name' must not be null");
|
||||
Assert.notNull(contributor, "'contributor' must not be null");
|
||||
return new NamedContributor<>() {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public C getContributor() {
|
||||
return contributor;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
/**
|
||||
* A collection of named health endpoint contributors (either {@link HealthContributor} or
|
||||
* {@link ReactiveHealthContributor}).
|
||||
*
|
||||
* @param <C> the contributor type
|
||||
* @author Phillip Webb
|
||||
* @since 2.0.0
|
||||
* @see NamedContributor
|
||||
*/
|
||||
public interface NamedContributors<C> extends Iterable<NamedContributor<C>> {
|
||||
|
||||
/**
|
||||
* Return the contributor with the given name.
|
||||
* @param name the name of the contributor
|
||||
* @return a contributor instance or {@code null}
|
||||
*/
|
||||
C getContributor(String name);
|
||||
|
||||
/**
|
||||
* Return a stream of the {@link NamedContributor named contributors}.
|
||||
* @return the stream of named contributors
|
||||
*/
|
||||
default Stream<NamedContributor<C>> stream() {
|
||||
return StreamSupport.stream(spliterator(), false);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link NamedContributors} backed by a map with values adapted as necessary.
|
||||
*
|
||||
* @param <V> the value type
|
||||
* @param <C> the contributor type
|
||||
* @author Phillip Webb
|
||||
* @author Guirong Hu
|
||||
* @see CompositeHealthContributorMapAdapter
|
||||
* @see CompositeReactiveHealthContributorMapAdapter
|
||||
*/
|
||||
abstract class NamedContributorsMapAdapter<V, C> implements NamedContributors<C> {
|
||||
|
||||
private final Map<String, C> map;
|
||||
|
||||
NamedContributorsMapAdapter(Map<String, V> map, Function<V, ? extends C> valueAdapter) {
|
||||
Assert.notNull(map, "'map' must not be null");
|
||||
Assert.notNull(valueAdapter, "'valueAdapter' must not be null");
|
||||
map.keySet().forEach(this::validateMapKey);
|
||||
this.map = Collections.unmodifiableMap(map.entrySet().stream().collect(LinkedHashMap::new, (result, entry) -> {
|
||||
String key = entry.getKey();
|
||||
C value = adaptMapValue(entry.getValue(), valueAdapter);
|
||||
result.put(key, value);
|
||||
}, Map::putAll));
|
||||
|
||||
}
|
||||
|
||||
private void validateMapKey(String value) {
|
||||
Assert.notNull(value, "'map' must not contain null keys");
|
||||
Assert.isTrue(!value.contains("/"), "'map' keys must not contain a '/'");
|
||||
}
|
||||
|
||||
private C adaptMapValue(V value, Function<V, ? extends C> valueAdapter) {
|
||||
C contributor = (value != null) ? valueAdapter.apply(value) : null;
|
||||
Assert.notNull(contributor, "'map' must not contain null values");
|
||||
return contributor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<NamedContributor<C>> iterator() {
|
||||
Iterator<Entry<String, C>> iterator = this.map.entrySet().iterator();
|
||||
return new Iterator<>() {
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedContributor<C> next() {
|
||||
Entry<String, C> entry = iterator.next();
|
||||
return NamedContributor.of(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public C getContributor(String name) {
|
||||
return this.map.get(name);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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 org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Tagging interface for classes that contribute to {@link HealthComponent health
|
||||
* components} to the results returned from the {@link HealthEndpoint}. A contributor must
|
||||
* be either a {@link ReactiveHealthIndicator} or a
|
||||
* {@link CompositeReactiveHealthContributor}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.2.0
|
||||
* @see ReactiveHealthIndicator
|
||||
* @see CompositeReactiveHealthContributor
|
||||
*/
|
||||
public interface ReactiveHealthContributor {
|
||||
|
||||
static ReactiveHealthContributor adapt(HealthContributor healthContributor) {
|
||||
Assert.notNull(healthContributor, "'healthContributor' must not be null");
|
||||
if (healthContributor instanceof HealthIndicator healthIndicator) {
|
||||
return new HealthIndicatorReactiveAdapter(healthIndicator);
|
||||
}
|
||||
if (healthContributor instanceof CompositeHealthContributor compositeHealthContributor) {
|
||||
return new CompositeHealthContributorReactiveAdapter(compositeHealthContributor);
|
||||
}
|
||||
throw new IllegalStateException("Unknown HealthContributor type");
|
||||
}
|
||||
|
||||
}
|
|
@ -32,6 +32,9 @@ import org.springframework.boot.actuate.endpoint.annotation.Selector.Match;
|
|||
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.registry.HealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;
|
||||
import org.springframework.context.annotation.ImportRuntimeHints;
|
||||
|
||||
/**
|
||||
|
@ -46,94 +49,76 @@ import org.springframework.context.annotation.ImportRuntimeHints;
|
|||
@EndpointWebExtension(endpoint = HealthEndpoint.class)
|
||||
@ImportRuntimeHints(HealthEndpointWebExtensionRuntimeHints.class)
|
||||
public class ReactiveHealthEndpointWebExtension
|
||||
extends HealthEndpointSupport<ReactiveHealthContributor, Mono<? extends HealthComponent>> {
|
||||
|
||||
private static final String[] NO_PATH = {};
|
||||
extends HealthEndpointSupport<Mono<? extends Health>, Mono<? extends HealthDescriptor>> {
|
||||
|
||||
/**
|
||||
* Create a new {@link ReactiveHealthEndpointWebExtension} instance.
|
||||
* @param registry the health contributor registry
|
||||
* @param fallbackRegistry the fallback registry or {@code null}
|
||||
* @param groups the health endpoint groups
|
||||
* @param slowIndicatorLoggingThreshold duration after which slow health indicator
|
||||
* @param slowContributorLoggingThreshold duration after which slow health indicator
|
||||
* logging should occur
|
||||
* @since 2.6.9
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public ReactiveHealthEndpointWebExtension(ReactiveHealthContributorRegistry registry, HealthEndpointGroups groups,
|
||||
Duration slowIndicatorLoggingThreshold) {
|
||||
super(registry, groups, slowIndicatorLoggingThreshold);
|
||||
public ReactiveHealthEndpointWebExtension(ReactiveHealthContributorRegistry registry,
|
||||
HealthContributorRegistry fallbackRegistry, HealthEndpointGroups groups,
|
||||
Duration slowContributorLoggingThreshold) {
|
||||
super(Contributor.reactive(registry, fallbackRegistry), groups, slowContributorLoggingThreshold);
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public Mono<WebEndpointResponse<? extends HealthComponent>> health(ApiVersion apiVersion,
|
||||
public Mono<WebEndpointResponse<? extends HealthDescriptor>> health(ApiVersion apiVersion,
|
||||
WebServerNamespace serverNamespace, SecurityContext securityContext) {
|
||||
return health(apiVersion, serverNamespace, securityContext, false, NO_PATH);
|
||||
return health(apiVersion, serverNamespace, securityContext, false, EMPTY_PATH);
|
||||
}
|
||||
|
||||
@ReadOperation
|
||||
public Mono<WebEndpointResponse<? extends HealthComponent>> health(ApiVersion apiVersion,
|
||||
public Mono<WebEndpointResponse<? extends HealthDescriptor>> health(ApiVersion apiVersion,
|
||||
WebServerNamespace serverNamespace, SecurityContext securityContext,
|
||||
@Selector(match = Match.ALL_REMAINING) String... path) {
|
||||
return health(apiVersion, serverNamespace, securityContext, false, path);
|
||||
}
|
||||
|
||||
public Mono<WebEndpointResponse<? extends HealthComponent>> health(ApiVersion apiVersion,
|
||||
public Mono<WebEndpointResponse<? extends HealthDescriptor>> health(ApiVersion apiVersion,
|
||||
WebServerNamespace serverNamespace, SecurityContext securityContext, boolean showAll, String... path) {
|
||||
HealthResult<Mono<? extends HealthComponent>> result = getHealth(apiVersion, serverNamespace, securityContext,
|
||||
Result<Mono<? extends HealthDescriptor>> result = getResult(apiVersion, serverNamespace, securityContext,
|
||||
showAll, path);
|
||||
if (result == null) {
|
||||
return (Arrays.equals(path, NO_PATH))
|
||||
? Mono.just(new WebEndpointResponse<>(DEFAULT_HEALTH, WebEndpointResponse.STATUS_OK))
|
||||
return (Arrays.equals(path, EMPTY_PATH))
|
||||
? Mono.just(new WebEndpointResponse<>(IndicatedHealthDescriptor.UP, WebEndpointResponse.STATUS_OK))
|
||||
: Mono.just(new WebEndpointResponse<>(WebEndpointResponse.STATUS_NOT_FOUND));
|
||||
}
|
||||
HealthEndpointGroup group = result.getGroup();
|
||||
return result.getHealth().map((health) -> {
|
||||
HealthEndpointGroup group = result.group();
|
||||
return result.descriptor().map((health) -> {
|
||||
int statusCode = group.getHttpCodeStatusMapper().getStatusCode(health.getStatus());
|
||||
return new WebEndpointResponse<>(health, statusCode);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Mono<? extends HealthComponent> getHealth(ReactiveHealthContributor contributor, boolean includeDetails) {
|
||||
return ((ReactiveHealthIndicator) contributor).getHealth(includeDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Mono<? extends HealthComponent> aggregateContributions(ApiVersion apiVersion,
|
||||
Map<String, Mono<? extends HealthComponent>> contributions, StatusAggregator statusAggregator,
|
||||
protected Mono<? extends HealthDescriptor> aggregateDescriptors(ApiVersion apiVersion,
|
||||
Map<String, Mono<? extends HealthDescriptor>> contributions, StatusAggregator statusAggregator,
|
||||
boolean showComponents, Set<String> groupNames) {
|
||||
return Flux.fromIterable(contributions.entrySet())
|
||||
.flatMap(NamedHealthComponent::create)
|
||||
.collectMap(NamedHealthComponent::getName, NamedHealthComponent::getHealth)
|
||||
.map((components) -> this.getCompositeHealth(apiVersion, components, statusAggregator, showComponents,
|
||||
.flatMap(NamedHealthDescriptor::create)
|
||||
.collectMap(NamedHealthDescriptor::name, NamedHealthDescriptor::descriptor)
|
||||
.map((components) -> this.getCompositeDescriptor(apiVersion, components, statusAggregator, showComponents,
|
||||
groupNames));
|
||||
}
|
||||
|
||||
/**
|
||||
* A named {@link HealthComponent}.
|
||||
* A named {@link HealthDescriptor}.
|
||||
*/
|
||||
private static final class NamedHealthComponent {
|
||||
private record NamedHealthDescriptor(String name, HealthDescriptor descriptor) {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final HealthComponent health;
|
||||
|
||||
private NamedHealthComponent(Object... pair) {
|
||||
this.name = (String) pair[0];
|
||||
this.health = (HealthComponent) pair[1];
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
HealthComponent getHealth() {
|
||||
return this.health;
|
||||
}
|
||||
|
||||
static Mono<NamedHealthComponent> create(Map.Entry<String, Mono<? extends HealthComponent>> entry) {
|
||||
static Mono<NamedHealthDescriptor> create(Map.Entry<String, Mono<? extends HealthDescriptor>> entry) {
|
||||
Mono<String> name = Mono.just(entry.getKey());
|
||||
Mono<? extends HealthComponent> health = entry.getValue();
|
||||
return Mono.zip(NamedHealthComponent::new, name, health);
|
||||
Mono<? extends HealthDescriptor> health = entry.getValue();
|
||||
return Mono.zip(NamedHealthDescriptor::ofPair, name, health);
|
||||
}
|
||||
|
||||
private static NamedHealthDescriptor ofPair(Object... pair) {
|
||||
return new NamedHealthDescriptor((String) pair[0], (HealthDescriptor) pair[1]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.LinkedHashMap;
|
|||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@ import java.util.Arrays;
|
|||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
/**
|
||||
* Strategy used to aggregate {@link Status} instances.
|
||||
* <p>
|
||||
|
|
|
@ -18,27 +18,27 @@ package org.springframework.boot.actuate.health;
|
|||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.ApiVersion;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
/**
|
||||
* A {@link HealthComponent} that represents the overall system health and the available
|
||||
* groups.
|
||||
* Description of overall system health.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.2.0
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public final class SystemHealth extends CompositeHealth {
|
||||
public final class SystemHealthDescriptor extends CompositeHealthDescriptor {
|
||||
|
||||
private final Set<String> groups;
|
||||
|
||||
SystemHealth(ApiVersion apiVersion, Status status, Map<String, HealthComponent> instances, Set<String> groups) {
|
||||
super(apiVersion, status, instances);
|
||||
this.groups = (groups != null) ? new TreeSet<>(groups) : null;
|
||||
SystemHealthDescriptor(ApiVersion apiVersion, Status status, Map<String, HealthDescriptor> components,
|
||||
Set<String> groups) {
|
||||
super(apiVersion, status, components);
|
||||
this.groups = groups;
|
||||
}
|
||||
|
||||
@JsonInclude(Include.NON_EMPTY)
|
|
@ -22,10 +22,10 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health.Builder;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.health.contributor.AbstractHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.boot.info.SslInfo;
|
||||
import org.springframework.boot.info.SslInfo.BundleInfo;
|
||||
import org.springframework.boot.info.SslInfo.CertificateChainInfo;
|
||||
|
@ -54,7 +54,7 @@ public class SslHealthIndicator extends AbstractHealthIndicator {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Builder builder) throws Exception {
|
||||
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||
List<CertificateChainInfo> validCertificateChains = new ArrayList<>();
|
||||
List<CertificateChainInfo> invalidCertificateChains = new ArrayList<>();
|
||||
List<CertificateChainInfo> expiringCerificateChains = new ArrayList<>();
|
||||
|
|
|
@ -21,10 +21,10 @@ import java.io.File;
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.health.contributor.AbstractHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.util.unit.DataSize;
|
||||
|
||||
|
|
|
@ -21,10 +21,10 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.availability.ApplicationAvailability;
|
||||
import org.springframework.boot.availability.AvailabilityState;
|
||||
import org.springframework.boot.availability.LivenessState;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
@ -82,7 +82,7 @@ class AvailabilityStateHealthIndicatorTests {
|
|||
statusMappings.add(LivenessState.BROKEN, Status.DOWN);
|
||||
});
|
||||
given(this.applicationAvailability.getState(LivenessState.class)).willReturn(LivenessState.BROKEN);
|
||||
assertThat(indicator.getHealth(false).getStatus()).isEqualTo(Status.DOWN);
|
||||
assertThat(indicator.health(false).getStatus()).isEqualTo(Status.DOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -93,7 +93,7 @@ class AvailabilityStateHealthIndicatorTests {
|
|||
statusMappings.addDefaultStatus(Status.UNKNOWN);
|
||||
});
|
||||
given(this.applicationAvailability.getState(LivenessState.class)).willReturn(LivenessState.BROKEN);
|
||||
assertThat(indicator.getHealth(false).getStatus()).isEqualTo(Status.UNKNOWN);
|
||||
assertThat(indicator.health(false).getStatus()).isEqualTo(Status.UNKNOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -104,7 +104,7 @@ class AvailabilityStateHealthIndicatorTests {
|
|||
statusMappings.addDefaultStatus(Status.DOWN);
|
||||
});
|
||||
given(this.applicationAvailability.getState(TestAvailabilityState.class)).willReturn(TestAvailabilityState.TWO);
|
||||
assertThat(indicator.getHealth(false).getStatus()).isEqualTo(Status.DOWN);
|
||||
assertThat(indicator.health(false).getStatus()).isEqualTo(Status.DOWN);
|
||||
}
|
||||
|
||||
static class TestAvailabilityState implements AvailabilityState {
|
||||
|
|
|
@ -19,9 +19,9 @@ package org.springframework.boot.actuate.availability;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.availability.ApplicationAvailability;
|
||||
import org.springframework.boot.availability.LivenessState;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
|
|
@ -19,9 +19,9 @@ package org.springframework.boot.actuate.availability;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.availability.ApplicationAvailability;
|
||||
import org.springframework.boot.availability.ReadinessState;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.ApiVersion;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests for {@link CompositeHealthDescriptor}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class CompositeHealthDescriptorTests {
|
||||
|
||||
@Test
|
||||
void createWhenApiVersionIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new CompositeHealthDescriptor(null, Status.UP, Collections.emptyMap()))
|
||||
.withMessage("'apiVersion' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWhenStatusIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new CompositeHealthDescriptor(ApiVersion.V3, null, Collections.emptyMap()))
|
||||
.withMessage("'status' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getStatusReturnsStatus() {
|
||||
CompositeHealthDescriptor descriptor = new CompositeHealthDescriptor(ApiVersion.V3, Status.UP,
|
||||
Collections.emptyMap());
|
||||
assertThat(descriptor.getStatus()).isEqualTo(Status.UP);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getComponentReturnsComponents() {
|
||||
Map<String, HealthDescriptor> components = new LinkedHashMap<>();
|
||||
components.put("a", new IndicatedHealthDescriptor(Health.up().build()));
|
||||
CompositeHealthDescriptor descriptor = new CompositeHealthDescriptor(ApiVersion.V3, Status.UP, components);
|
||||
assertThat(descriptor.getComponents()).isEqualTo(components);
|
||||
}
|
||||
|
||||
@Test
|
||||
void serializeV3WithJacksonReturnsValidJson() throws Exception {
|
||||
Map<String, HealthDescriptor> components = new LinkedHashMap<>();
|
||||
components.put("db1", new IndicatedHealthDescriptor(Health.up().build()));
|
||||
components.put("db2", new IndicatedHealthDescriptor(Health.down().withDetail("a", "b").build()));
|
||||
CompositeHealthDescriptor descriptor = new CompositeHealthDescriptor(ApiVersion.V3, Status.UP, components);
|
||||
ObjectMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();
|
||||
String json = mapper.writeValueAsString(descriptor);
|
||||
assertThat(json).isEqualTo("""
|
||||
{"components":{"db1":{"status":"UP"},"db2":{"details":{"a":"b"},"status":"DOWN"}},"status":"UP"}""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void serializeV2WithJacksonReturnsValidJson() throws Exception {
|
||||
Map<String, HealthDescriptor> components = new LinkedHashMap<>();
|
||||
components.put("db1", new IndicatedHealthDescriptor(Health.up().build()));
|
||||
components.put("db2", new IndicatedHealthDescriptor(Health.down().withDetail("a", "b").build()));
|
||||
CompositeHealthDescriptor descriptor = new CompositeHealthDescriptor(ApiVersion.V2, Status.UP, components);
|
||||
ObjectMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();
|
||||
String json = mapper.writeValueAsString(descriptor);
|
||||
assertThat(json).isEqualTo("""
|
||||
{"details":{"db1":{"status":"UP"},"db2":{"details":{"a":"b"},"status":"DOWN"}},"status":"UP"}""");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.ApiVersion;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Test for {@link CompositeHealth}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class CompositeHealthTests {
|
||||
|
||||
@Test
|
||||
void createWhenStatusIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new CompositeHealth(ApiVersion.V3, null, Collections.emptyMap()))
|
||||
.withMessage("'status' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getStatusReturnsStatus() {
|
||||
CompositeHealth health = new CompositeHealth(ApiVersion.V3, Status.UP, Collections.emptyMap());
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getComponentReturnsComponents() {
|
||||
Map<String, HealthComponent> components = new LinkedHashMap<>();
|
||||
components.put("a", Health.up().build());
|
||||
CompositeHealth health = new CompositeHealth(ApiVersion.V3, Status.UP, components);
|
||||
assertThat(health.getComponents()).isEqualTo(components);
|
||||
}
|
||||
|
||||
@Test
|
||||
void serializeV3WithJacksonReturnsValidJson() throws Exception {
|
||||
Map<String, HealthComponent> components = new LinkedHashMap<>();
|
||||
components.put("db1", Health.up().build());
|
||||
components.put("db2", Health.down().withDetail("a", "b").build());
|
||||
CompositeHealth health = new CompositeHealth(ApiVersion.V3, Status.UP, components);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String json = mapper.writeValueAsString(health);
|
||||
assertThat(json).isEqualTo("{\"status\":\"UP\",\"components\":{\"db1\":{\"status\":\"UP\"},"
|
||||
+ "\"db2\":{\"status\":\"DOWN\",\"details\":{\"a\":\"b\"}}}}");
|
||||
}
|
||||
|
||||
@Test
|
||||
void serializeV2WithJacksonReturnsValidJson() throws Exception {
|
||||
Map<String, HealthComponent> components = new LinkedHashMap<>();
|
||||
components.put("db1", Health.up().build());
|
||||
components.put("db2", Health.down().withDetail("a", "b").build());
|
||||
CompositeHealth health = new CompositeHealth(ApiVersion.V2, Status.UP, components);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String json = mapper.writeValueAsString(health);
|
||||
assertThat(json).isEqualTo("{\"status\":\"UP\",\"details\":{\"db1\":{\"status\":\"UP\"},"
|
||||
+ "\"db2\":{\"status\":\"DOWN\",\"details\":{\"a\":\"b\"}}}}");
|
||||
}
|
||||
|
||||
@Test // gh-26797
|
||||
void serializeV2WithJacksonAndDisabledCanOverrideAccessModifiersReturnsValidJson() throws Exception {
|
||||
Map<String, HealthComponent> components = new LinkedHashMap<>();
|
||||
components.put("db1", Health.up().build());
|
||||
components.put("db2", Health.down().withDetail("a", "b").build());
|
||||
CompositeHealth health = new CompositeHealth(ApiVersion.V2, Status.UP, components);
|
||||
JsonMapper mapper = JsonMapper.builder().disable(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS).build();
|
||||
String json = mapper.writeValueAsString(health);
|
||||
assertThat(json).isEqualTo("{\"status\":\"UP\",\"details\":{\"db1\":{\"status\":\"UP\"},"
|
||||
+ "\"db2\":{\"status\":\"DOWN\",\"details\":{\"a\":\"b\"}}}}");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.Collections;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link DefaultContributorRegistry}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Vedran Pavic
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
abstract class DefaultContributorRegistryTests {
|
||||
|
||||
private final HealthIndicator one = mock(HealthIndicator.class);
|
||||
|
||||
private final HealthIndicator two = mock(HealthIndicator.class);
|
||||
|
||||
private ContributorRegistry<HealthIndicator> registry;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
given(this.one.health()).willReturn(new Health.Builder().unknown().withDetail("1", "1").build());
|
||||
given(this.two.health()).willReturn(new Health.Builder().unknown().withDetail("2", "2").build());
|
||||
this.registry = new DefaultContributorRegistry<>();
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWhenContributorsIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new DefaultContributorRegistry<>(null))
|
||||
.withMessage("Contributors must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWhenNameFactoryIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new DefaultContributorRegistry<>(Collections.emptyMap(), null))
|
||||
.withMessage("NameFactory must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createUsesHealthIndicatorNameFactoryByDefault() {
|
||||
this.registry = new DefaultContributorRegistry<>(Collections.singletonMap("oneHealthIndicator", this.one));
|
||||
assertThat(this.registry.getContributor("oneHealthIndicator")).isNull();
|
||||
assertThat(this.registry.getContributor("one")).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWithCustomNameFactoryAppliesFunctionToName() {
|
||||
this.registry = new DefaultContributorRegistry<>(Collections.singletonMap("one", this.one), this::reverse);
|
||||
assertThat(this.registry.getContributor("one")).isNull();
|
||||
assertThat(this.registry.getContributor("eno")).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerContributorWhenNameIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.registry.registerContributor(null, this.one))
|
||||
.withMessage("Name must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerContributorWhenContributorIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.registry.registerContributor("one", null))
|
||||
.withMessage("Contributor must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerContributorRegistersContributors() {
|
||||
this.registry.registerContributor("one", this.one);
|
||||
this.registry.registerContributor("two", this.two);
|
||||
assertThat(this.registry).hasSize(2);
|
||||
assertThat(this.registry.getContributor("one")).isSameAs(this.one);
|
||||
assertThat(this.registry.getContributor("two")).isSameAs(this.two);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerContributorWhenNameAlreadyUsedThrowsException() {
|
||||
this.registry.registerContributor("one", this.one);
|
||||
assertThatIllegalStateException().isThrownBy(() -> this.registry.registerContributor("one", this.two))
|
||||
.withMessageContaining("A contributor named \"one\" has already been registered");
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerContributorUsesNameFactory() {
|
||||
this.registry.registerContributor("oneHealthIndicator", this.one);
|
||||
assertThat(this.registry.getContributor("oneHealthIndicator")).isNull();
|
||||
assertThat(this.registry.getContributor("one")).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void unregisterContributorUnregistersContributor() {
|
||||
this.registry.registerContributor("one", this.one);
|
||||
this.registry.registerContributor("two", this.two);
|
||||
assertThat(this.registry).hasSize(2);
|
||||
HealthIndicator two = this.registry.unregisterContributor("two");
|
||||
assertThat(two).isSameAs(this.two);
|
||||
assertThat(this.registry).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void unregisterContributorWhenUnknownReturnsNull() {
|
||||
this.registry.registerContributor("one", this.one);
|
||||
assertThat(this.registry).hasSize(1);
|
||||
HealthIndicator two = this.registry.unregisterContributor("two");
|
||||
assertThat(two).isNull();
|
||||
assertThat(this.registry).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void unregisterContributorUsesNameFactory() {
|
||||
this.registry.registerContributor("oneHealthIndicator", this.one);
|
||||
assertThat(this.registry.getContributor("oneHealthIndicator")).isNull();
|
||||
assertThat(this.registry.getContributor("one")).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getContributorReturnsContributor() {
|
||||
this.registry.registerContributor("one", this.one);
|
||||
assertThat(this.registry.getContributor("one")).isEqualTo(this.one);
|
||||
}
|
||||
|
||||
@Test
|
||||
void iteratorIteratesContributors() {
|
||||
this.registry.registerContributor("one", this.one);
|
||||
this.registry.registerContributor("two", this.two);
|
||||
Iterator<NamedContributor<HealthIndicator>> iterator = this.registry.iterator();
|
||||
NamedContributor<HealthIndicator> first = iterator.next();
|
||||
NamedContributor<HealthIndicator> second = iterator.next();
|
||||
assertThat(iterator.hasNext()).isFalse();
|
||||
assertThat(first.getName()).isEqualTo("one");
|
||||
assertThat(first.getContributor()).isEqualTo(this.one);
|
||||
assertThat(second.getName()).isEqualTo("two");
|
||||
assertThat(second.getContributor()).isEqualTo(this.two);
|
||||
}
|
||||
|
||||
private String reverse(String name) {
|
||||
return new StringBuilder(name).reverse().toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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 org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link HealthContributorNameFactory}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class HealthContributorNameFactoryTests {
|
||||
|
||||
@Test
|
||||
void applyWhenNameDoesNotEndWithSuffixReturnsName() {
|
||||
assertThat(HealthContributorNameFactory.INSTANCE.apply("test")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyWhenNameEndsWithSuffixReturnsNewName() {
|
||||
assertThat(HealthContributorNameFactory.INSTANCE.apply("testHealthIndicator")).isEqualTo("test");
|
||||
assertThat(HealthContributorNameFactory.INSTANCE.apply("testHealthContributor")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyWhenNameEndsWithSuffixInDifferentReturnsNewName() {
|
||||
assertThat(HealthContributorNameFactory.INSTANCE.apply("testHEALTHindicator")).isEqualTo("test");
|
||||
assertThat(HealthContributorNameFactory.INSTANCE.apply("testHEALTHcontributor")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyWhenNameContainsSuffixReturnsName() {
|
||||
assertThat(HealthContributorNameFactory.INSTANCE.apply("testHealthIndicatorTest"))
|
||||
.isEqualTo("testHealthIndicatorTest");
|
||||
assertThat(HealthContributorNameFactory.INSTANCE.apply("testHealthContributorTest"))
|
||||
.isEqualTo("testHealthContributorTest");
|
||||
}
|
||||
|
||||
}
|
|
@ -20,6 +20,8 @@ import java.time.Duration;
|
|||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -27,24 +29,24 @@ import org.junit.jupiter.api.Test;
|
|||
import org.springframework.boot.actuate.endpoint.ApiVersion;
|
||||
import org.springframework.boot.actuate.endpoint.SecurityContext;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointSupport.HealthResult;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointSupport.Result;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Base class for {@link HealthEndpointSupport} tests.
|
||||
*
|
||||
* @param <S> the support type
|
||||
* @param <E> the endpoint type;
|
||||
* @param <H> the health type
|
||||
* @param <D> the descriptor type
|
||||
* @param <R> the registry type
|
||||
* @param <C> the contributor type
|
||||
* @param <T> the contributed health component type
|
||||
* @author Phillip Webb
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
abstract class HealthEndpointSupportTests<S extends HealthEndpointSupport<C, T>, R extends ContributorRegistry<C>, C, T> {
|
||||
|
||||
final R registry;
|
||||
abstract class HealthEndpointSupportTests<E extends HealthEndpointSupport<H, D>, H, D, R, C> {
|
||||
|
||||
final Health up = Health.up().withDetail("spring", "boot").build();
|
||||
|
||||
|
@ -54,217 +56,227 @@ abstract class HealthEndpointSupportTests<S extends HealthEndpointSupport<C, T>,
|
|||
|
||||
final TestHealthEndpointGroup allTheAs = new TestHealthEndpointGroup((name) -> name.startsWith("a"));
|
||||
|
||||
final HealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup,
|
||||
Collections.singletonMap("alltheas", this.allTheAs));
|
||||
final HealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup, Map.of("alltheas", this.allTheAs));
|
||||
|
||||
HealthEndpointSupportTests() {
|
||||
this.registry = createRegistry();
|
||||
@Test
|
||||
void getResultWhenPathIsEmptyUsesPrimaryGroup() {
|
||||
R registry = createRegistry("test", createContributor(this.up));
|
||||
E support = create(registry, this.groups);
|
||||
Result<D> result = support.getResult(ApiVersion.V3, null, SecurityContext.NONE, false);
|
||||
assertThat(result.group()).isEqualTo(this.primaryGroup);
|
||||
SystemHealthDescriptor descriptor = (SystemHealthDescriptor) getDescriptor(result);
|
||||
assertThat(descriptor.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(descriptor.getComponents()).containsKey("test");
|
||||
assertThat(descriptor.getDetails()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWhenRegistryIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> create(null, this.groups))
|
||||
.withMessage("'registry' must not be null");
|
||||
void getResultWhenPathIsNotGroupReturnsResultFromPrimaryGroup() {
|
||||
R registry = createRegistry("test", createContributor(this.up));
|
||||
E endpoint = create(registry, this.groups);
|
||||
Result<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, "test");
|
||||
assertThat(result.group()).isEqualTo(this.primaryGroup);
|
||||
IndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) getDescriptor(result);
|
||||
assertThat(descriptor.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(descriptor.getDetails()).containsEntry("spring", "boot");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWhenGroupsIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> create(this.registry, null))
|
||||
.withMessage("'groups' must not be null");
|
||||
void getResultWhenPathIsGroupReturnsResultFromGroup() {
|
||||
R registry = createRegistry("atest", createContributor(this.up));
|
||||
E endpoint = create(registry, this.groups);
|
||||
Result<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, "alltheas", "atest");
|
||||
assertThat(result.group()).isEqualTo(this.allTheAs);
|
||||
IndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) getDescriptor(result);
|
||||
assertThat(descriptor.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(descriptor.getDetails()).containsEntry("spring", "boot");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenPathIsEmptyUsesPrimaryGroup() {
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
HealthResult<T> result = create(this.registry, this.groups).getHealth(ApiVersion.V3, null, SecurityContext.NONE,
|
||||
false);
|
||||
assertThat(result.getGroup()).isEqualTo(this.primaryGroup);
|
||||
assertThat(getHealth(result)).isNotSameAs(this.up);
|
||||
assertThat(getHealth(result).getStatus()).isEqualTo(Status.UP);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenPathIsNotGroupReturnsResultFromPrimaryGroup() {
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
HealthResult<T> result = create(this.registry, this.groups).getHealth(ApiVersion.V3, null, SecurityContext.NONE,
|
||||
false, "test");
|
||||
assertThat(result.getGroup()).isEqualTo(this.primaryGroup);
|
||||
assertThat(getHealth(result)).isEqualTo(this.up);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenPathIsGroupReturnsResultFromGroup() {
|
||||
this.registry.registerContributor("atest", createContributor(this.up));
|
||||
HealthResult<T> result = create(this.registry, this.groups).getHealth(ApiVersion.V3, null, SecurityContext.NONE,
|
||||
false, "alltheas", "atest");
|
||||
assertThat(result.getGroup()).isEqualTo(this.allTheAs);
|
||||
assertThat(getHealth(result)).isEqualTo(this.up);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenAlwaysShowIsFalseAndGroupIsTrueShowsComponents() {
|
||||
void getResultWhenAlwaysShowIsFalseAndGroupIsTrueShowsComponents() {
|
||||
C contributor = createContributor(this.up);
|
||||
C compositeContributor = createCompositeContributor(Collections.singletonMap("spring", contributor));
|
||||
this.registry.registerContributor("test", compositeContributor);
|
||||
HealthResult<T> result = create(this.registry, this.groups).getHealth(ApiVersion.V3, null, SecurityContext.NONE,
|
||||
false, "test");
|
||||
CompositeHealth health = (CompositeHealth) getHealth(result);
|
||||
assertThat(health.getComponents()).containsKey("spring");
|
||||
C compositeContributor = createCompositeContributor(Map.of("spring", contributor));
|
||||
R registry = createRegistry("test", compositeContributor);
|
||||
E endpoint = create(registry, this.groups);
|
||||
Result<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, "test");
|
||||
CompositeHealthDescriptor descriptor = (CompositeHealthDescriptor) getDescriptor(result);
|
||||
assertThat(descriptor.getComponents()).containsKey("spring");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenAlwaysShowIsFalseAndGroupIsFalseCannotAccessComponent() {
|
||||
void getResultWhenAlwaysShowIsFalseAndGroupIsFalseCannotAccessComponent() {
|
||||
this.primaryGroup.setShowComponents(false);
|
||||
C contributor = createContributor(this.up);
|
||||
C compositeContributor = createCompositeContributor(Collections.singletonMap("spring", contributor));
|
||||
this.registry.registerContributor("test", compositeContributor);
|
||||
HealthEndpointSupport<C, T> endpoint = create(this.registry, this.groups);
|
||||
HealthResult<T> rootResult = endpoint.getHealth(ApiVersion.V3, null, SecurityContext.NONE, false);
|
||||
assertThat(((CompositeHealth) getHealth(rootResult)).getComponents()).isNullOrEmpty();
|
||||
HealthResult<T> componentResult = endpoint.getHealth(ApiVersion.V3, null, SecurityContext.NONE, false, "test");
|
||||
C compositeContributor = createCompositeContributor(Map.of("spring", contributor));
|
||||
R registry = createRegistry("test", compositeContributor);
|
||||
E endpoint = create(registry, this.groups);
|
||||
Result<D> rootResult = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false);
|
||||
CompositeHealthDescriptor rootDescriptor = (CompositeHealthDescriptor) getDescriptor(rootResult);
|
||||
assertThat(rootDescriptor.getComponents()).isNullOrEmpty();
|
||||
Result<D> componentResult = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, "test");
|
||||
assertThat(componentResult).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenAlwaysShowIsTrueShowsComponents() {
|
||||
void getResultWhenAlwaysShowIsTrueShowsComponents() {
|
||||
this.primaryGroup.setShowComponents(true);
|
||||
C contributor = createContributor(this.up);
|
||||
C compositeContributor = createCompositeContributor(Collections.singletonMap("spring", contributor));
|
||||
this.registry.registerContributor("test", compositeContributor);
|
||||
HealthEndpointSupport<C, T> endpoint = create(this.registry, this.groups);
|
||||
HealthResult<T> rootResult = endpoint.getHealth(ApiVersion.V3, null, SecurityContext.NONE, false);
|
||||
assertThat(((CompositeHealth) getHealth(rootResult)).getComponents()).containsKey("test");
|
||||
HealthResult<T> componentResult = endpoint.getHealth(ApiVersion.V3, null, SecurityContext.NONE, false, "test");
|
||||
assertThat(((CompositeHealth) getHealth(componentResult)).getComponents()).containsKey("spring");
|
||||
C compositeContributor = createCompositeContributor(Map.of("spring", contributor));
|
||||
R registry = createRegistry("test", compositeContributor);
|
||||
E endpoint = create(registry, this.groups);
|
||||
Result<D> rootResult = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false);
|
||||
CompositeHealthDescriptor rootDescriptor = (CompositeHealthDescriptor) getDescriptor(rootResult);
|
||||
assertThat(rootDescriptor.getComponents()).containsKey("test");
|
||||
Result<D> componentResult = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, "test");
|
||||
CompositeHealthDescriptor componentDescriptor = (CompositeHealthDescriptor) getDescriptor(componentResult);
|
||||
assertThat(componentDescriptor.getComponents()).containsKey("spring");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenAlwaysShowIsFalseAndGroupIsTrueShowsDetails() {
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
HealthResult<T> result = create(this.registry, this.groups).getHealth(ApiVersion.V3, null, SecurityContext.NONE,
|
||||
false, "test");
|
||||
assertThat(((Health) getHealth(result)).getDetails()).containsEntry("spring", "boot");
|
||||
void getResultWhenAlwaysShowIsFalseAndGroupIsTrueShowsDetails() {
|
||||
R registry = createRegistry("test", createContributor(this.up));
|
||||
E endpoint = create(registry, this.groups);
|
||||
Result<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, "test");
|
||||
IndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) getDescriptor(result);
|
||||
assertThat(descriptor.getDetails()).containsEntry("spring", "boot");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenAlwaysShowIsFalseAndGroupIsFalseShowsNoDetails() {
|
||||
void getResultWhenAlwaysShowIsFalseAndGroupIsFalseShowsNoDetails() {
|
||||
this.primaryGroup.setShowDetails(false);
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
HealthEndpointSupport<C, T> endpoint = create(this.registry, this.groups);
|
||||
HealthResult<T> rootResult = endpoint.getHealth(ApiVersion.V3, null, SecurityContext.NONE, false);
|
||||
HealthResult<T> componentResult = endpoint.getHealth(ApiVersion.V3, null, SecurityContext.NONE, false, "test");
|
||||
assertThat(((CompositeHealth) getHealth(rootResult)).getStatus()).isEqualTo(Status.UP);
|
||||
R registry = createRegistry("test", createContributor(this.up));
|
||||
E endpoint = create(registry, this.groups);
|
||||
Result<D> rootResult = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false);
|
||||
Result<D> componentResult = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, "test");
|
||||
assertThat(getDescriptor(rootResult).getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(componentResult).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenAlwaysShowIsTrueShowsDetails() {
|
||||
void getResultWhenAlwaysShowIsTrueShowsDetails() {
|
||||
this.primaryGroup.setShowDetails(false);
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
HealthResult<T> result = create(this.registry, this.groups).getHealth(ApiVersion.V3, null, SecurityContext.NONE,
|
||||
true, "test");
|
||||
assertThat(((Health) getHealth(result)).getDetails()).containsEntry("spring", "boot");
|
||||
R registry = createRegistry("test", createContributor(this.up));
|
||||
E endpoint = create(registry, this.groups);
|
||||
Result<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, true, "test");
|
||||
IndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) getDescriptor(result);
|
||||
assertThat(descriptor.getDetails()).containsEntry("spring", "boot");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenCompositeReturnsAggregateResult() {
|
||||
void getResultWhenCompositeReturnsAggregateResult() {
|
||||
Map<String, C> contributors = new LinkedHashMap<>();
|
||||
contributors.put("a", createContributor(this.up));
|
||||
contributors.put("b", createContributor(this.down));
|
||||
this.registry.registerContributor("test", createCompositeContributor(contributors));
|
||||
HealthResult<T> result = create(this.registry, this.groups).getHealth(ApiVersion.V3, null, SecurityContext.NONE,
|
||||
false);
|
||||
CompositeHealth root = (CompositeHealth) getHealth(result);
|
||||
CompositeHealth component = (CompositeHealth) root.getComponents().get("test");
|
||||
R registry = createRegistry("test", createCompositeContributor(contributors));
|
||||
E endpoint = create(registry, this.groups);
|
||||
Result<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false);
|
||||
CompositeHealthDescriptor root = (CompositeHealthDescriptor) getDescriptor(result);
|
||||
CompositeHealthDescriptor component = (CompositeHealthDescriptor) root.getComponents().get("test");
|
||||
assertThat(root.getStatus()).isEqualTo(Status.DOWN);
|
||||
assertThat(component.getStatus()).isEqualTo(Status.DOWN);
|
||||
assertThat(component.getComponents()).containsOnlyKeys("a", "b");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenPathDoesNotExistReturnsNull() {
|
||||
HealthResult<T> result = create(this.registry, this.groups).getHealth(ApiVersion.V3, null, SecurityContext.NONE,
|
||||
false, "missing");
|
||||
void getResultWhenPathDoesNotExistReturnsNull() {
|
||||
R registry = createRegistry("test", createCompositeContributor(Collections.emptyMap()));
|
||||
Result<D> result = create(registry, this.groups).getResult(ApiVersion.V3, null, SecurityContext.NONE, false,
|
||||
"missing");
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenPathIsEmptyIncludesGroups() {
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
HealthResult<T> result = create(this.registry, this.groups).getHealth(ApiVersion.V3, null, SecurityContext.NONE,
|
||||
false);
|
||||
assertThat(((SystemHealth) getHealth(result)).getGroups()).containsOnly("alltheas");
|
||||
void getResultWhenPathIsEmptyIncludesGroups() {
|
||||
R registry = createRegistry("test", createContributor(this.up));
|
||||
E endpoint = create(registry, this.groups);
|
||||
Result<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false);
|
||||
SystemHealthDescriptor descriptor = (SystemHealthDescriptor) getDescriptor(result);
|
||||
assertThat(descriptor.getGroups()).containsOnly("alltheas");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenPathIsGroupDoesNotIncludesGroups() {
|
||||
this.registry.registerContributor("atest", createContributor(this.up));
|
||||
HealthResult<T> result = create(this.registry, this.groups).getHealth(ApiVersion.V3, null, SecurityContext.NONE,
|
||||
false, "alltheas");
|
||||
assertThat(getHealth(result)).isNotInstanceOf(SystemHealth.class);
|
||||
void getResultWhenPathIsGroupDoesNotIncludesGroups() {
|
||||
R registry = createRegistry("atest", createContributor(this.up));
|
||||
E endpoint = create(registry, this.groups);
|
||||
Result<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, "alltheas");
|
||||
HealthDescriptor descriptor = getDescriptor(result);
|
||||
assertThat(descriptor).isInstanceOf(CompositeHealthDescriptor.class);
|
||||
assertThat(descriptor).isNotInstanceOf(SystemHealthDescriptor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWithEmptyCompositeReturnsNullResult() { // gh-18687
|
||||
this.registry.registerContributor("test", createCompositeContributor(Collections.emptyMap()));
|
||||
HealthResult<T> result = create(this.registry, this.groups).getHealth(ApiVersion.V3, null, SecurityContext.NONE,
|
||||
false);
|
||||
void getResultWithEmptyCompositeReturnsNullResult() { // gh-18687
|
||||
R registry = createRegistry("test", createCompositeContributor(Collections.emptyMap()));
|
||||
E endpoint = create(registry, this.groups);
|
||||
Result<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false);
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenGroupContainsCompositeContributorReturnsHealth() {
|
||||
void getResultWhenGroupContainsCompositeContributorReturnsHealth() {
|
||||
C contributor = createContributor(this.up);
|
||||
C compositeContributor = createCompositeContributor(Collections.singletonMap("spring", contributor));
|
||||
this.registry.registerContributor("test", compositeContributor);
|
||||
C compositeContributor = createCompositeContributor(Map.of("spring", contributor));
|
||||
R registry = createRegistry("test", compositeContributor);
|
||||
TestHealthEndpointGroup testGroup = new TestHealthEndpointGroup((name) -> name.startsWith("test"));
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup,
|
||||
Collections.singletonMap("testGroup", testGroup));
|
||||
HealthResult<T> result = create(this.registry, groups).getHealth(ApiVersion.V3, null, SecurityContext.NONE,
|
||||
false, "testGroup");
|
||||
CompositeHealth health = (CompositeHealth) getHealth(result);
|
||||
assertThat(health.getComponents()).containsKey("test");
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup, Map.of("testGroup", testGroup));
|
||||
E endpoint = create(registry, groups);
|
||||
Result<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, "testGroup");
|
||||
CompositeHealthDescriptor descriptor = (CompositeHealthDescriptor) getDescriptor(result);
|
||||
assertThat(descriptor.getComponents()).containsKey("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenGroupContainsComponentOfCompositeContributorReturnsHealth() {
|
||||
CompositeHealth health = getCompositeHealth((name) -> name.equals("test/spring-1"));
|
||||
assertThat(health.getComponents()).containsKey("test");
|
||||
CompositeHealth test = (CompositeHealth) health.getComponents().get("test");
|
||||
void getResultWhenGroupContainsComponentOfCompositeContributorReturnsHealth() {
|
||||
CompositeHealthDescriptor descriptor = getCompositeHealthDescriptor((name) -> name.equals("test/spring-1"));
|
||||
assertThat(descriptor.getComponents()).containsKey("test");
|
||||
CompositeHealthDescriptor test = (CompositeHealthDescriptor) descriptor.getComponents().get("test");
|
||||
assertThat(test.getComponents()).containsKey("spring-1");
|
||||
assertThat(test.getComponents()).doesNotContainKey("spring-2");
|
||||
assertThat(test.getComponents()).doesNotContainKey("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenGroupExcludesComponentOfCompositeContributorReturnsHealth() {
|
||||
CompositeHealth health = getCompositeHealth(
|
||||
void getResultWhenGroupExcludesComponentOfCompositeContributorReturnsHealth() {
|
||||
CompositeHealthDescriptor descriptor = getCompositeHealthDescriptor(
|
||||
(name) -> name.startsWith("test/") && !name.equals("test/spring-2"));
|
||||
assertThat(health.getComponents()).containsKey("test");
|
||||
CompositeHealth test = (CompositeHealth) health.getComponents().get("test");
|
||||
assertThat(descriptor.getComponents()).containsKey("test");
|
||||
CompositeHealthDescriptor test = (CompositeHealthDescriptor) descriptor.getComponents().get("test");
|
||||
assertThat(test.getComponents()).containsKey("spring-1");
|
||||
assertThat(test.getComponents()).doesNotContainKey("spring-2");
|
||||
}
|
||||
|
||||
private CompositeHealthDescriptor getCompositeHealthDescriptor(Predicate<String> memberPredicate) {
|
||||
C contributor1 = createContributor(this.up);
|
||||
C contributor2 = createContributor(this.down);
|
||||
Map<String, C> contributors = new LinkedHashMap<>();
|
||||
contributors.put("spring-1", contributor1);
|
||||
contributors.put("spring-2", contributor2);
|
||||
C compositeContributor = createCompositeContributor(contributors);
|
||||
R registry = createRegistry("test", compositeContributor);
|
||||
TestHealthEndpointGroup testGroup = new TestHealthEndpointGroup(memberPredicate);
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup, Map.of("testGroup", testGroup));
|
||||
E endpoint = create(registry, groups);
|
||||
Result<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, "testGroup");
|
||||
return (CompositeHealthDescriptor) getDescriptor(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthForPathWhenGroupContainsComponentOfCompositeContributorReturnsHealth() {
|
||||
void getResultForPathWhenGroupContainsComponentOfCompositeContributorReturnsHealth() {
|
||||
Map<String, C> contributors = new LinkedHashMap<>();
|
||||
contributors.put("spring-1", createNestedHealthContributor("spring-1"));
|
||||
contributors.put("spring-2", createNestedHealthContributor("spring-2"));
|
||||
C compositeContributor = createCompositeContributor(contributors);
|
||||
this.registry.registerContributor("test", compositeContributor);
|
||||
R registry = createRegistry("test", compositeContributor);
|
||||
TestHealthEndpointGroup testGroup = new TestHealthEndpointGroup(
|
||||
(name) -> name.startsWith("test") && !name.equals("test/spring-1/b"));
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup,
|
||||
Collections.singletonMap("testGroup", testGroup));
|
||||
HealthResult<T> result = create(this.registry, groups).getHealth(ApiVersion.V3, null, SecurityContext.NONE,
|
||||
false, "testGroup", "test");
|
||||
CompositeHealth health = (CompositeHealth) getHealth(result);
|
||||
assertThat(health.getComponents()).containsKey("spring-1");
|
||||
assertThat(health.getComponents()).containsKey("spring-2");
|
||||
CompositeHealth spring1 = (CompositeHealth) health.getComponents().get("spring-1");
|
||||
CompositeHealth spring2 = (CompositeHealth) health.getComponents().get("spring-2");
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup, Map.of("testGroup", testGroup));
|
||||
E endpoint = create(registry, groups);
|
||||
Result<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, "testGroup", "test");
|
||||
CompositeHealthDescriptor descriptor = (CompositeHealthDescriptor) getDescriptor(result);
|
||||
assertThat(descriptor.getComponents()).containsKey("spring-1");
|
||||
assertThat(descriptor.getComponents()).containsKey("spring-2");
|
||||
CompositeHealthDescriptor spring1 = (CompositeHealthDescriptor) descriptor.getComponents().get("spring-1");
|
||||
CompositeHealthDescriptor spring2 = (CompositeHealthDescriptor) descriptor.getComponents().get("spring-2");
|
||||
assertThat(spring1.getComponents()).containsKey("a");
|
||||
assertThat(spring1.getComponents()).containsKey("c");
|
||||
assertThat(spring1.getComponents()).doesNotContainKey("b");
|
||||
|
@ -274,37 +286,21 @@ abstract class HealthEndpointSupportTests<S extends HealthEndpointSupport<C, T>,
|
|||
}
|
||||
|
||||
@Test
|
||||
void getHealthForComponentPathWhenNotPartOfGroup() {
|
||||
void getResultForComponentPathWhenNotPartOfGroup() {
|
||||
Map<String, C> contributors = new LinkedHashMap<>();
|
||||
contributors.put("spring-1", createNestedHealthContributor("spring-1"));
|
||||
contributors.put("spring-2", createNestedHealthContributor("spring-2"));
|
||||
C compositeContributor = createCompositeContributor(contributors);
|
||||
this.registry.registerContributor("test", compositeContributor);
|
||||
R registry = createRegistry("test", compositeContributor);
|
||||
TestHealthEndpointGroup testGroup = new TestHealthEndpointGroup(
|
||||
(name) -> name.startsWith("test") && !name.equals("test/spring-1/b"));
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup,
|
||||
Collections.singletonMap("testGroup", testGroup));
|
||||
HealthResult<T> result = create(this.registry, groups).getHealth(ApiVersion.V3, null, SecurityContext.NONE,
|
||||
false, "testGroup", "test", "spring-1", "b");
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup, Map.of("testGroup", testGroup));
|
||||
E endpoint = create(registry, groups);
|
||||
Result<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, "testGroup", "test",
|
||||
"spring-1", "b");
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
private CompositeHealth getCompositeHealth(Predicate<String> memberPredicate) {
|
||||
C contributor1 = createContributor(this.up);
|
||||
C contributor2 = createContributor(this.down);
|
||||
Map<String, C> contributors = new LinkedHashMap<>();
|
||||
contributors.put("spring-1", contributor1);
|
||||
contributors.put("spring-2", contributor2);
|
||||
C compositeContributor = createCompositeContributor(contributors);
|
||||
this.registry.registerContributor("test", compositeContributor);
|
||||
TestHealthEndpointGroup testGroup = new TestHealthEndpointGroup(memberPredicate);
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup,
|
||||
Collections.singletonMap("testGroup", testGroup));
|
||||
HealthResult<T> result = create(this.registry, groups).getHealth(ApiVersion.V3, null, SecurityContext.NONE,
|
||||
false, "testGroup");
|
||||
return (CompositeHealth) getHealth(result);
|
||||
}
|
||||
|
||||
private C createNestedHealthContributor(String name) {
|
||||
Map<String, C> map = new LinkedHashMap<>();
|
||||
map.put("a", createContributor(Health.up().withDetail("hello", name + "-a").build()));
|
||||
|
@ -314,58 +310,62 @@ abstract class HealthEndpointSupportTests<S extends HealthEndpointSupport<C, T>,
|
|||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenGroupHasAdditionalPath() {
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
void getResultWhenGroupHasAdditionalPath() {
|
||||
R registry = createRegistry("test", createContributor(this.up));
|
||||
TestHealthEndpointGroup testGroup = new TestHealthEndpointGroup((name) -> name.startsWith("test"));
|
||||
testGroup.setAdditionalPath(AdditionalHealthEndpointPath.from("server:/healthz"));
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup,
|
||||
Collections.singletonMap("testGroup", testGroup));
|
||||
HealthResult<T> result = create(this.registry, groups).getHealth(ApiVersion.V3, WebServerNamespace.SERVER,
|
||||
SecurityContext.NONE, false, "healthz");
|
||||
CompositeHealth health = (CompositeHealth) getHealth(result);
|
||||
assertThat(health.getComponents()).containsKey("test");
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup, Map.of("testGroup", testGroup));
|
||||
E endpoint = create(registry, groups);
|
||||
Result<D> result = endpoint.getResult(ApiVersion.V3, WebServerNamespace.SERVER, SecurityContext.NONE, false,
|
||||
"healthz");
|
||||
CompositeHealthDescriptor descriptor = (CompositeHealthDescriptor) getDescriptor(result);
|
||||
assertThat(descriptor.getComponents()).containsKey("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getHealthWhenGroupHasAdditionalPathAndShowComponentsFalse() {
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
void getResultWhenGroupHasAdditionalPathAndShowComponentsFalse() {
|
||||
R registry = createRegistry("test", createContributor(this.up));
|
||||
TestHealthEndpointGroup testGroup = new TestHealthEndpointGroup((name) -> name.startsWith("test"));
|
||||
testGroup.setAdditionalPath(AdditionalHealthEndpointPath.from("server:/healthz"));
|
||||
testGroup.setShowComponents(false);
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup,
|
||||
Collections.singletonMap("testGroup", testGroup));
|
||||
HealthResult<T> result = create(this.registry, groups).getHealth(ApiVersion.V3, WebServerNamespace.SERVER,
|
||||
SecurityContext.NONE, false, "healthz");
|
||||
CompositeHealth health = (CompositeHealth) getHealth(result);
|
||||
assertThat(health.getStatus().getCode()).isEqualTo("UP");
|
||||
assertThat(health.getComponents()).isNull();
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup, Map.of("testGroup", testGroup));
|
||||
E endpoint = create(registry, groups);
|
||||
Result<D> result = endpoint.getResult(ApiVersion.V3, WebServerNamespace.SERVER, SecurityContext.NONE, false,
|
||||
"healthz");
|
||||
CompositeHealthDescriptor descriptor = (CompositeHealthDescriptor) getDescriptor(result);
|
||||
assertThat(descriptor.getStatus().getCode()).isEqualTo("UP");
|
||||
assertThat(descriptor.getComponents()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getComponentHealthWhenGroupHasAdditionalPathAndShowComponentsFalse() {
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
void getResultWithPathWhenGroupHasAdditionalPathAndShowComponentsFalse() {
|
||||
R registry = createRegistry("test", createContributor(this.up));
|
||||
TestHealthEndpointGroup testGroup = new TestHealthEndpointGroup((name) -> name.startsWith("test"));
|
||||
testGroup.setAdditionalPath(AdditionalHealthEndpointPath.from("server:/healthz"));
|
||||
testGroup.setShowComponents(false);
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup,
|
||||
Collections.singletonMap("testGroup", testGroup));
|
||||
HealthResult<T> result = create(this.registry, groups).getHealth(ApiVersion.V3, WebServerNamespace.SERVER,
|
||||
SecurityContext.NONE, false, "healthz", "test");
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup, Map.of("testGroup", testGroup));
|
||||
E endpoint = create(registry, groups);
|
||||
Result<D> result = endpoint.getResult(ApiVersion.V3, WebServerNamespace.SERVER, SecurityContext.NONE, false,
|
||||
"healthz", "test");
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
protected final S create(R registry, HealthEndpointGroups groups) {
|
||||
protected final E create(R registry, HealthEndpointGroups groups) {
|
||||
return create(registry, groups, null);
|
||||
}
|
||||
|
||||
protected abstract S create(R registry, HealthEndpointGroups groups, Duration slowIndicatorLoggingThreshold);
|
||||
protected abstract E create(R registry, HealthEndpointGroups groups, Duration slowContributorLoggingThreshold);
|
||||
|
||||
protected abstract R createRegistry();
|
||||
protected final R createRegistry(String name, C contributor) {
|
||||
return createRegistry((registrations) -> registrations.accept(name, contributor));
|
||||
}
|
||||
|
||||
protected abstract R createRegistry(Consumer<BiConsumer<String, C>> intialRegistrations);
|
||||
|
||||
protected abstract C createContributor(Health health);
|
||||
|
||||
protected abstract C createCompositeContributor(Map<String, C> contributors);
|
||||
|
||||
protected abstract HealthComponent getHealth(HealthResult<T> result);
|
||||
protected abstract HealthDescriptor getDescriptor(Result<D> result);
|
||||
|
||||
}
|
||||
|
|
|
@ -19,11 +19,20 @@ package org.springframework.boot.actuate.health;
|
|||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.boot.actuate.health.HealthEndpointSupport.HealthResult;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointSupport.Result;
|
||||
import org.springframework.boot.health.contributor.CompositeHealthContributor;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthContributor;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.boot.health.registry.DefaultHealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.HealthContributorRegistry;
|
||||
import org.springframework.boot.test.system.CapturedOutput;
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
|
||||
|
@ -38,38 +47,42 @@ import static org.mockito.Mockito.mock;
|
|||
*/
|
||||
@ExtendWith(OutputCaptureExtension.class)
|
||||
class HealthEndpointTests extends
|
||||
HealthEndpointSupportTests<HealthEndpoint, HealthContributorRegistry, HealthContributor, HealthComponent> {
|
||||
HealthEndpointSupportTests<HealthEndpoint, Health, HealthDescriptor, HealthContributorRegistry, HealthContributor> {
|
||||
|
||||
@Test
|
||||
void healthReturnsSystemHealth() {
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
HealthComponent health = create(this.registry, this.groups).health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(health).isInstanceOf(SystemHealth.class);
|
||||
HealthContributorRegistry registry = createRegistry("test", createContributor(this.up));
|
||||
HealthEndpoint endpoint = create(registry, this.groups);
|
||||
HealthDescriptor descriptor = endpoint.health();
|
||||
assertThat(descriptor.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(descriptor).isInstanceOf(SystemHealthDescriptor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthWithNoContributorReturnsUp() {
|
||||
assertThat(this.registry).isEmpty();
|
||||
HealthComponent health = create(this.registry,
|
||||
HealthEndpointGroups.of(mock(HealthEndpointGroup.class), Collections.emptyMap()))
|
||||
.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(health).isInstanceOf(Health.class);
|
||||
HealthContributorRegistry registry = createRegistry(null);
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(mock(HealthEndpointGroup.class), Collections.emptyMap());
|
||||
HealthEndpoint endpoint = create(registry, groups);
|
||||
HealthDescriptor descriptor = endpoint.health();
|
||||
assertThat(descriptor.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(descriptor).isInstanceOf(IndicatedHealthDescriptor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthWhenPathDoesNotExistReturnsNull() {
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
HealthComponent health = create(this.registry, this.groups).healthForPath("missing");
|
||||
assertThat(health).isNull();
|
||||
HealthContributorRegistry registry = createRegistry("test", createContributor(this.up));
|
||||
HealthEndpoint endpoint = create(registry, this.groups);
|
||||
HealthDescriptor descriptor = endpoint.healthForPath("missing");
|
||||
assertThat(descriptor).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthWhenPathExistsReturnsHealth() {
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
HealthComponent health = create(this.registry, this.groups).healthForPath("test");
|
||||
assertThat(health).isEqualTo(this.up);
|
||||
HealthContributorRegistry registry = createRegistry("test", createContributor(this.up));
|
||||
HealthEndpoint endpoint = create(registry, this.groups);
|
||||
IndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) endpoint.healthForPath("test");
|
||||
assertThat(descriptor.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(descriptor.getDetails()).containsEntry("spring", "boot");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -83,22 +96,23 @@ class HealthEndpointTests extends
|
|||
}
|
||||
return this.up;
|
||||
};
|
||||
this.registry.registerContributor("test", indicator);
|
||||
create(this.registry, this.groups, Duration.ofMillis(10)).health();
|
||||
HealthContributorRegistry registry = createRegistry("test", indicator);
|
||||
HealthEndpoint endpoint = create(registry, this.groups, Duration.ofMillis(10));
|
||||
endpoint.health();
|
||||
assertThat(output).contains("Health contributor");
|
||||
assertThat(output).contains("to respond");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HealthEndpoint create(HealthContributorRegistry registry, HealthEndpointGroups groups,
|
||||
Duration slowIndicatorLoggingThreshold) {
|
||||
return new HealthEndpoint(registry, groups, slowIndicatorLoggingThreshold);
|
||||
Duration slowContributorLoggingThreshold) {
|
||||
return new HealthEndpoint(registry, null, groups, slowContributorLoggingThreshold);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HealthContributorRegistry createRegistry() {
|
||||
return new DefaultHealthContributorRegistry();
|
||||
protected HealthContributorRegistry createRegistry(
|
||||
Consumer<BiConsumer<String, HealthContributor>> intialRegistrations) {
|
||||
return new DefaultHealthContributorRegistry(Collections.emptyList(), intialRegistrations);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -112,8 +126,8 @@ class HealthEndpointTests extends
|
|||
}
|
||||
|
||||
@Override
|
||||
protected HealthComponent getHealth(HealthResult<HealthComponent> result) {
|
||||
return result.getHealth();
|
||||
protected HealthDescriptor getDescriptor(Result<HealthDescriptor> result) {
|
||||
return result.descriptor();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,7 +37,8 @@ class HealthEndpointWebExtensionRuntimeHintsTests {
|
|||
void shouldRegisterHints() {
|
||||
RuntimeHints runtimeHints = new RuntimeHints();
|
||||
new HealthEndpointWebExtensionRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
|
||||
Set<Class<?>> bindingTypes = Set.of(Health.class, SystemHealth.class, CompositeHealth.class);
|
||||
Set<Class<?>> bindingTypes = Set.of(IndicatedHealthDescriptor.class, SystemHealthDescriptor.class,
|
||||
CompositeHealthDescriptor.class);
|
||||
for (Class<?> bindingType : bindingTypes) {
|
||||
assertThat(RuntimeHintsPredicates.reflection()
|
||||
.onType(bindingType)
|
||||
|
|
|
@ -19,6 +19,8 @@ package org.springframework.boot.actuate.health;
|
|||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -26,7 +28,14 @@ import org.springframework.boot.actuate.endpoint.ApiVersion;
|
|||
import org.springframework.boot.actuate.endpoint.SecurityContext;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointSupport.HealthResult;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointSupport.Result;
|
||||
import org.springframework.boot.health.contributor.CompositeHealthContributor;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthContributor;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.boot.health.registry.DefaultHealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.HealthContributorRegistry;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
@ -38,58 +47,65 @@ import static org.mockito.Mockito.mock;
|
|||
* @author Scott Frederick
|
||||
*/
|
||||
class HealthEndpointWebExtensionTests extends
|
||||
HealthEndpointSupportTests<HealthEndpointWebExtension, HealthContributorRegistry, HealthContributor, HealthComponent> {
|
||||
HealthEndpointSupportTests<HealthEndpointWebExtension, Health, HealthDescriptor, HealthContributorRegistry, HealthContributor> {
|
||||
|
||||
@Test
|
||||
void healthReturnsSystemHealth() {
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
WebEndpointResponse<HealthComponent> response = create(this.registry, this.groups).health(ApiVersion.LATEST,
|
||||
WebServerNamespace.SERVER, SecurityContext.NONE);
|
||||
HealthComponent health = response.getBody();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(health).isInstanceOf(SystemHealth.class);
|
||||
HealthContributorRegistry registry = createRegistry("test", createContributor(this.up));
|
||||
HealthEndpointWebExtension endpoint = create(registry, this.groups);
|
||||
WebEndpointResponse<HealthDescriptor> response = endpoint.health(ApiVersion.LATEST, WebServerNamespace.SERVER,
|
||||
SecurityContext.NONE);
|
||||
HealthDescriptor descriptor = response.getBody();
|
||||
assertThat(descriptor.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(descriptor).isInstanceOf(SystemHealthDescriptor.class);
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthWithNoContributorReturnsUp() {
|
||||
assertThat(this.registry).isEmpty();
|
||||
WebEndpointResponse<HealthComponent> response = create(this.registry,
|
||||
HealthEndpointGroups.of(mock(HealthEndpointGroup.class), Collections.emptyMap()))
|
||||
.health(ApiVersion.LATEST, WebServerNamespace.SERVER, SecurityContext.NONE);
|
||||
HealthContributorRegistry registry = createRegistry(null);
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(mock(HealthEndpointGroup.class), Collections.emptyMap());
|
||||
HealthEndpointWebExtension endpoint = create(registry, groups);
|
||||
WebEndpointResponse<HealthDescriptor> response = endpoint.health(ApiVersion.LATEST, WebServerNamespace.SERVER,
|
||||
SecurityContext.NONE);
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
HealthComponent health = response.getBody();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(health).isInstanceOf(Health.class);
|
||||
HealthDescriptor descriptor = response.getBody();
|
||||
assertThat(descriptor.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(descriptor).isInstanceOf(IndicatedHealthDescriptor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthWhenPathDoesNotExistReturnsHttp404() {
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
WebEndpointResponse<HealthComponent> response = create(this.registry, this.groups).health(ApiVersion.LATEST,
|
||||
WebServerNamespace.SERVER, SecurityContext.NONE, "missing");
|
||||
HealthContributorRegistry registry = createRegistry("test", createContributor(this.up));
|
||||
HealthEndpointWebExtension endpoint = create(registry, this.groups);
|
||||
WebEndpointResponse<HealthDescriptor> response = endpoint.health(ApiVersion.LATEST, WebServerNamespace.SERVER,
|
||||
SecurityContext.NONE, "missing");
|
||||
assertThat(response.getBody()).isNull();
|
||||
assertThat(response.getStatus()).isEqualTo(404);
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthWhenPathExistsReturnsHealth() {
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
WebEndpointResponse<HealthComponent> response = create(this.registry, this.groups).health(ApiVersion.LATEST,
|
||||
WebServerNamespace.SERVER, SecurityContext.NONE, "test");
|
||||
assertThat(response.getBody()).isEqualTo(this.up);
|
||||
HealthContributorRegistry registry = createRegistry("test", createContributor(this.up));
|
||||
HealthEndpointWebExtension endpoint = create(registry, this.groups);
|
||||
WebEndpointResponse<HealthDescriptor> response = endpoint.health(ApiVersion.LATEST, WebServerNamespace.SERVER,
|
||||
SecurityContext.NONE, "test");
|
||||
IndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) response.getBody();
|
||||
assertThat(descriptor.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(descriptor.getDetails()).containsEntry("spring", "boot");
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HealthEndpointWebExtension create(HealthContributorRegistry registry, HealthEndpointGroups groups,
|
||||
Duration slowIndicatorLoggingThreshold) {
|
||||
return new HealthEndpointWebExtension(registry, groups, slowIndicatorLoggingThreshold);
|
||||
return new HealthEndpointWebExtension(registry, null, groups, slowIndicatorLoggingThreshold);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HealthContributorRegistry createRegistry() {
|
||||
return new DefaultHealthContributorRegistry();
|
||||
protected HealthContributorRegistry createRegistry(
|
||||
Consumer<BiConsumer<String, HealthContributor>> intialRegistrations) {
|
||||
return new DefaultHealthContributorRegistry(Collections.emptyList(), intialRegistrations);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -103,8 +119,8 @@ class HealthEndpointWebExtensionTests extends
|
|||
}
|
||||
|
||||
@Override
|
||||
protected HealthComponent getHealth(HealthResult<HealthComponent> result) {
|
||||
return result.getHealth();
|
||||
protected HealthDescriptor getDescriptor(Result<HealthDescriptor> result) {
|
||||
return result.descriptor();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright 2012-present 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 com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link IndicatedHealthDescriptor}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class IndicatedHealthDescriptorTests {
|
||||
|
||||
@Test
|
||||
void serializeWithJacksonReturnsValidJson() throws Exception {
|
||||
IndicatedHealthDescriptor descriptor = new IndicatedHealthDescriptor(
|
||||
Health.outOfService().withDetail("spring", "boot").build());
|
||||
ObjectMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();
|
||||
String json = mapper.writeValueAsString(descriptor);
|
||||
assertThat(json).isEqualTo("""
|
||||
{"details":{"spring":"boot"},"status":"OUT_OF_SERVICE"}""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void serializeWithJacksonWhenEmptyDetailsReturnsValidJson() throws Exception {
|
||||
IndicatedHealthDescriptor descriptor = new IndicatedHealthDescriptor(Health.outOfService().build());
|
||||
ObjectMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();
|
||||
String json = mapper.writeValueAsString(descriptor);
|
||||
assertThat(json).isEqualTo("""
|
||||
{"status":"OUT_OF_SERVICE"}""");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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 org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests for {@link NamedContributor}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class NamedContributorTests {
|
||||
|
||||
@Test
|
||||
void ofNameAndContributorCreatesContributor() {
|
||||
NamedContributor<String> contributor = NamedContributor.of("one", "two");
|
||||
assertThat(contributor.getName()).isEqualTo("one");
|
||||
assertThat(contributor.getContributor()).isEqualTo("two");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofWhenNameIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> NamedContributor.of(null, "two"))
|
||||
.withMessage("'name' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofWhenContributorIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> NamedContributor.of("one", null))
|
||||
.withMessage("'contributor' must not be null");
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -19,6 +19,8 @@ package org.springframework.boot.actuate.health;
|
|||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
@ -26,7 +28,14 @@ import reactor.core.publisher.Mono;
|
|||
import org.springframework.boot.actuate.endpoint.ApiVersion;
|
||||
import org.springframework.boot.actuate.endpoint.SecurityContext;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointSupport.HealthResult;
|
||||
import org.springframework.boot.actuate.health.HealthEndpointSupport.Result;
|
||||
import org.springframework.boot.health.contributor.CompositeReactiveHealthContributor;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.ReactiveHealthContributor;
|
||||
import org.springframework.boot.health.contributor.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.boot.health.registry.DefaultReactiveHealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
@ -38,37 +47,40 @@ import static org.mockito.Mockito.mock;
|
|||
* @author Scott Frederick
|
||||
*/
|
||||
class ReactiveHealthEndpointWebExtensionTests extends
|
||||
HealthEndpointSupportTests<ReactiveHealthEndpointWebExtension, ReactiveHealthContributorRegistry, ReactiveHealthContributor, Mono<? extends HealthComponent>> {
|
||||
HealthEndpointSupportTests<ReactiveHealthEndpointWebExtension, Mono<? extends Health>, Mono<? extends HealthDescriptor>, ReactiveHealthContributorRegistry, ReactiveHealthContributor> {
|
||||
|
||||
@Test
|
||||
void healthReturnsSystemHealth() {
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
WebEndpointResponse<? extends HealthComponent> response = create(this.registry, this.groups)
|
||||
ReactiveHealthContributorRegistry registry = createRegistry("test", createContributor(this.up));
|
||||
ReactiveHealthEndpointWebExtension endpoint = create(registry, this.groups);
|
||||
WebEndpointResponse<? extends HealthDescriptor> response = endpoint
|
||||
.health(ApiVersion.LATEST, null, SecurityContext.NONE)
|
||||
.block();
|
||||
HealthComponent health = response.getBody();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(health).isInstanceOf(SystemHealth.class);
|
||||
HealthDescriptor descriptor = response.getBody();
|
||||
assertThat(descriptor.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(descriptor).isInstanceOf(SystemHealthDescriptor.class);
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthWithNoContributorReturnsUp() {
|
||||
assertThat(this.registry).isEmpty();
|
||||
WebEndpointResponse<? extends HealthComponent> response = create(this.registry,
|
||||
HealthEndpointGroups.of(mock(HealthEndpointGroup.class), Collections.emptyMap()))
|
||||
ReactiveHealthContributorRegistry registry = createRegistry(null);
|
||||
HealthEndpointGroups groups = HealthEndpointGroups.of(mock(HealthEndpointGroup.class), Collections.emptyMap());
|
||||
ReactiveHealthEndpointWebExtension endpoint = create(registry, groups);
|
||||
WebEndpointResponse<? extends HealthDescriptor> response = endpoint
|
||||
.health(ApiVersion.LATEST, null, SecurityContext.NONE)
|
||||
.block();
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
HealthComponent health = response.getBody();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(health).isInstanceOf(Health.class);
|
||||
HealthDescriptor descriptor = response.getBody();
|
||||
assertThat(descriptor.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(descriptor).isInstanceOf(IndicatedHealthDescriptor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthWhenPathDoesNotExistReturnsHttp404() {
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
WebEndpointResponse<? extends HealthComponent> response = create(this.registry, this.groups)
|
||||
ReactiveHealthContributorRegistry registry = createRegistry("test", createContributor(this.up));
|
||||
ReactiveHealthEndpointWebExtension endpoint = create(registry, this.groups);
|
||||
WebEndpointResponse<? extends HealthDescriptor> response = endpoint
|
||||
.health(ApiVersion.LATEST, null, SecurityContext.NONE, "missing")
|
||||
.block();
|
||||
assertThat(response.getBody()).isNull();
|
||||
|
@ -77,23 +89,27 @@ class ReactiveHealthEndpointWebExtensionTests extends
|
|||
|
||||
@Test
|
||||
void healthWhenPathExistsReturnsHealth() {
|
||||
this.registry.registerContributor("test", createContributor(this.up));
|
||||
WebEndpointResponse<? extends HealthComponent> response = create(this.registry, this.groups)
|
||||
ReactiveHealthContributorRegistry registry = createRegistry("test", createContributor(this.up));
|
||||
ReactiveHealthEndpointWebExtension endpoint = create(registry, this.groups);
|
||||
WebEndpointResponse<? extends HealthDescriptor> response = endpoint
|
||||
.health(ApiVersion.LATEST, null, SecurityContext.NONE, "test")
|
||||
.block();
|
||||
assertThat(response.getBody()).isEqualTo(this.up);
|
||||
IndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) response.getBody();
|
||||
assertThat(descriptor.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(descriptor.getDetails()).containsEntry("spring", "boot");
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReactiveHealthEndpointWebExtension create(ReactiveHealthContributorRegistry registry,
|
||||
HealthEndpointGroups groups, Duration slowIndicatorLoggingThreshold) {
|
||||
return new ReactiveHealthEndpointWebExtension(registry, groups, slowIndicatorLoggingThreshold);
|
||||
HealthEndpointGroups groups, Duration slowContributorLoggingThreshold) {
|
||||
return new ReactiveHealthEndpointWebExtension(registry, null, groups, slowContributorLoggingThreshold);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReactiveHealthContributorRegistry createRegistry() {
|
||||
return new DefaultReactiveHealthContributorRegistry();
|
||||
protected ReactiveHealthContributorRegistry createRegistry(
|
||||
Consumer<BiConsumer<String, ReactiveHealthContributor>> intialRegistrations) {
|
||||
return new DefaultReactiveHealthContributorRegistry(Collections.emptyList(), intialRegistrations);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -108,8 +124,8 @@ class ReactiveHealthEndpointWebExtensionTests extends
|
|||
}
|
||||
|
||||
@Override
|
||||
protected HealthComponent getHealth(HealthResult<Mono<? extends HealthComponent>> result) {
|
||||
return result.getHealth().block();
|
||||
protected HealthDescriptor getDescriptor(Result<Mono<? extends HealthDescriptor>> result) {
|
||||
return result.descriptor().block();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,7 +23,8 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health.Builder;
|
||||
import org.springframework.boot.health.contributor.AbstractReactiveHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.test.system.CapturedOutput;
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension;
|
||||
|
||||
|
@ -73,7 +74,7 @@ class ReactiveHealthIndicatorImplementationTests {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Mono<Health> doHealthCheck(Builder builder) {
|
||||
protected Mono<Health> doHealthCheck(Health.Builder builder) {
|
||||
return Mono.just(builder.up().build());
|
||||
}
|
||||
|
||||
|
@ -86,7 +87,7 @@ class ReactiveHealthIndicatorImplementationTests {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Mono<Health> doHealthCheck(Builder builder) {
|
||||
protected Mono<Health> doHealthCheck(Health.Builder builder) {
|
||||
return Mono.error(new UnsupportedOperationException());
|
||||
}
|
||||
|
||||
|
@ -100,7 +101,7 @@ class ReactiveHealthIndicatorImplementationTests {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Mono<Health> doHealthCheck(Builder builder) {
|
||||
protected Mono<Health> doHealthCheck(Health.Builder builder) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.Map;
|
|||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ package org.springframework.boot.actuate.health;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.ApiVersion;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link SystemHealthDescriptor}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class SystemHealthDescriptorTests {
|
||||
|
||||
@Test
|
||||
void serializeWithJacksonReturnsValidJson() throws Exception {
|
||||
Map<String, HealthDescriptor> components = new LinkedHashMap<>();
|
||||
components.put("db1", new IndicatedHealthDescriptor(Health.up().build()));
|
||||
components.put("db2", new IndicatedHealthDescriptor(Health.down().withDetail("a", "b").build()));
|
||||
Set<String> groups = new LinkedHashSet<>(Arrays.asList("liveness", "readiness"));
|
||||
SystemHealthDescriptor descriptor = new SystemHealthDescriptor(ApiVersion.V3, Status.UP, components, groups);
|
||||
ObjectMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();
|
||||
String json = mapper.writeValueAsString(descriptor);
|
||||
assertThat(json).isEqualTo(
|
||||
"""
|
||||
{"components":{"db1":{"status":"UP"},"db2":{"details":{"a":"b"},"status":"DOWN"}},"groups":["liveness","readiness"],"status":"UP"}""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void serializeWhenNoGroupsWithJacksonReturnsValidJson() throws Exception {
|
||||
Map<String, HealthDescriptor> components = new LinkedHashMap<>();
|
||||
components.put("db1", new IndicatedHealthDescriptor(Health.up().build()));
|
||||
components.put("db2", new IndicatedHealthDescriptor(Health.down().withDetail("a", "b").build()));
|
||||
SystemHealthDescriptor descriptor = new SystemHealthDescriptor(ApiVersion.V3, Status.UP, components, null);
|
||||
ObjectMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();
|
||||
String json = mapper.writeValueAsString(descriptor);
|
||||
assertThat(json).isEqualTo("""
|
||||
{"components":{"db1":{"status":"UP"},"db2":{"details":{"a":"b"},"status":"DOWN"}},"status":"UP"}""");
|
||||
}
|
||||
|
||||
@Test // gh-26797
|
||||
void serializeV2WithJacksonAndDisabledCanOverrideAccessModifiersReturnsValidJson() throws Exception {
|
||||
Map<String, HealthDescriptor> components = new LinkedHashMap<>();
|
||||
components.put("db1", new IndicatedHealthDescriptor(Health.up().build()));
|
||||
components.put("db2", new IndicatedHealthDescriptor(Health.down().withDetail("a", "b").build()));
|
||||
SystemHealthDescriptor descriptor = new SystemHealthDescriptor(ApiVersion.V2, Status.UP, components, null);
|
||||
ObjectMapper mapper = JsonMapper.builder()
|
||||
.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)
|
||||
.disable(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS)
|
||||
.build();
|
||||
String json = mapper.writeValueAsString(descriptor);
|
||||
assertThat(json).isEqualTo("""
|
||||
{"details":{"db1":{"status":"UP"},"db2":{"details":{"a":"b"},"status":"DOWN"}},"status":"UP"}""");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present 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.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.ApiVersion;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link SystemHealth}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class SystemHealthTests {
|
||||
|
||||
@Test
|
||||
void serializeWithJacksonReturnsValidJson() throws Exception {
|
||||
Map<String, HealthComponent> components = new LinkedHashMap<>();
|
||||
components.put("db1", Health.up().build());
|
||||
components.put("db2", Health.down().withDetail("a", "b").build());
|
||||
Set<String> groups = new LinkedHashSet<>(Arrays.asList("liveness", "readiness"));
|
||||
CompositeHealth health = new SystemHealth(ApiVersion.V3, Status.UP, components, groups);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String json = mapper.writeValueAsString(health);
|
||||
assertThat(json).isEqualTo("{\"status\":\"UP\",\"components\":{\"db1\":{\"status\":\"UP\"},"
|
||||
+ "\"db2\":{\"status\":\"DOWN\",\"details\":{\"a\":\"b\"}}},"
|
||||
+ "\"groups\":[\"liveness\",\"readiness\"]}");
|
||||
}
|
||||
|
||||
}
|
|
@ -23,8 +23,8 @@ import java.util.List;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.boot.info.SslInfo;
|
||||
import org.springframework.boot.info.SslInfo.BundleInfo;
|
||||
import org.springframework.boot.info.SslInfo.CertificateChainInfo;
|
||||
|
|
|
@ -24,9 +24,9 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.util.unit.DataSize;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
|
|
@ -35,9 +35,9 @@ dependencies {
|
|||
|
||||
implementation(project(":spring-boot-project:spring-boot-tx"))
|
||||
|
||||
optional(project(":spring-boot-project:spring-boot-actuator-autoconfigure"))
|
||||
optional(project(":spring-boot-project:spring-boot-autoconfigure"))
|
||||
optional(project(":spring-boot-project:spring-boot-docker-compose"))
|
||||
optional(project(":spring-boot-project:spring-boot-health"))
|
||||
optional(project(":spring-boot-project:spring-boot-metrics"))
|
||||
optional(project(":spring-boot-project:spring-boot-testcontainers"))
|
||||
optional("io.micrometer:micrometer-core")
|
||||
|
|
|
@ -18,16 +18,16 @@ package org.springframework.boot.amqp.autoconfigure.health;
|
|||
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthContributor;
|
||||
import org.springframework.boot.amqp.actuate.health.RabbitHealthIndicator;
|
||||
import org.springframework.boot.amqp.autoconfigure.RabbitAutoConfiguration;
|
||||
import org.springframework.boot.amqp.health.RabbitHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
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.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.health.autoconfigure.contributor.CompositeHealthContributorConfiguration;
|
||||
import org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.HealthContributor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.amqp.actuate.health;
|
||||
package org.springframework.boot.amqp.health;
|
||||
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.health.contributor.AbstractHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
|
@ -17,4 +17,4 @@
|
|||
/**
|
||||
* Health integration for AMQP and RabbitMQ.
|
||||
*/
|
||||
package org.springframework.boot.amqp.actuate.health;
|
||||
package org.springframework.boot.amqp.health;
|
|
@ -18,10 +18,10 @@ package org.springframework.boot.amqp.autoconfigure.health;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.amqp.actuate.health.RabbitHealthIndicator;
|
||||
import org.springframework.boot.amqp.autoconfigure.RabbitAutoConfiguration;
|
||||
import org.springframework.boot.amqp.health.RabbitHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.amqp.actuate.health;
|
||||
package org.springframework.boot.amqp.health;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
|
@ -27,8 +27,8 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
|||
|
||||
import org.springframework.amqp.rabbit.core.ChannelCallback;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
|
@ -30,9 +30,9 @@ dependencies {
|
|||
api(project(":spring-boot-project:spring-boot"))
|
||||
api("org.apache.cassandra:java-driver-core")
|
||||
|
||||
optional(project(":spring-boot-project:spring-boot-actuator-autoconfigure"))
|
||||
optional(project(":spring-boot-project:spring-boot-autoconfigure"))
|
||||
optional(project(":spring-boot-project:spring-boot-docker-compose"))
|
||||
optional(project(":spring-boot-project:spring-boot-health"))
|
||||
optional(project(":spring-boot-project:spring-boot-testcontainers"))
|
||||
optional("io.projectreactor:reactor-core")
|
||||
optional("org.testcontainers:cassandra")
|
||||
|
|
|
@ -18,13 +18,13 @@ package org.springframework.boot.cassandra.autoconfigure.health;
|
|||
|
||||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.cassandra.actuate.health.CassandraDriverHealthIndicator;
|
||||
import org.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration;
|
||||
import org.springframework.boot.cassandra.autoconfigure.health.CassandraHealthContributorConfigurations.CassandraDriverConfiguration;
|
||||
import org.springframework.boot.cassandra.health.CassandraDriverHealthIndicator;
|
||||
import org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,14 +21,14 @@ import java.util.Map;
|
|||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthContributorConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfiguration;
|
||||
import org.springframework.boot.actuate.health.HealthContributor;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthContributor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.cassandra.actuate.health.CassandraDriverHealthIndicator;
|
||||
import org.springframework.boot.cassandra.actuate.health.CassandraDriverReactiveHealthIndicator;
|
||||
import org.springframework.boot.cassandra.health.CassandraDriverHealthIndicator;
|
||||
import org.springframework.boot.cassandra.health.CassandraDriverReactiveHealthIndicator;
|
||||
import org.springframework.boot.health.autoconfigure.contributor.CompositeHealthContributorConfiguration;
|
||||
import org.springframework.boot.health.autoconfigure.contributor.CompositeReactiveHealthContributorConfiguration;
|
||||
import org.springframework.boot.health.contributor.HealthContributor;
|
||||
import org.springframework.boot.health.contributor.ReactiveHealthContributor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
|
|
@ -19,13 +19,13 @@ package org.springframework.boot.cassandra.autoconfigure.health;
|
|||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.cassandra.actuate.health.CassandraDriverReactiveHealthIndicator;
|
||||
import org.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration;
|
||||
import org.springframework.boot.cassandra.autoconfigure.health.CassandraHealthContributorConfigurations.CassandraReactiveDriverConfiguration;
|
||||
import org.springframework.boot.cassandra.health.CassandraDriverReactiveHealthIndicator;
|
||||
import org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cassandra.actuate.health;
|
||||
package org.springframework.boot.cassandra.health;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
@ -23,10 +23,10 @@ import com.datastax.oss.driver.api.core.CqlSession;
|
|||
import com.datastax.oss.driver.api.core.metadata.Node;
|
||||
import com.datastax.oss.driver.api.core.metadata.NodeState;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.health.contributor.AbstractHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cassandra.actuate.health;
|
||||
package org.springframework.boot.cassandra.health;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
@ -24,10 +24,10 @@ import com.datastax.oss.driver.api.core.metadata.Node;
|
|||
import com.datastax.oss.driver.api.core.metadata.NodeState;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.health.contributor.AbstractReactiveHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
|
@ -17,4 +17,4 @@
|
|||
/**
|
||||
* Health integration for Cassandra.
|
||||
*/
|
||||
package org.springframework.boot.cassandra.actuate.health;
|
||||
package org.springframework.boot.cassandra.health;
|
|
@ -19,9 +19,9 @@ package org.springframework.boot.cassandra.autoconfigure.health;
|
|||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.cassandra.actuate.health.CassandraDriverHealthIndicator;
|
||||
import org.springframework.boot.cassandra.health.CassandraDriverHealthIndicator;
|
||||
import org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
|
|
@ -19,9 +19,9 @@ package org.springframework.boot.cassandra.autoconfigure.health;
|
|||
import com.datastax.oss.driver.api.core.CqlSession;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.cassandra.actuate.health.CassandraDriverReactiveHealthIndicator;
|
||||
import org.springframework.boot.cassandra.health.CassandraDriverReactiveHealthIndicator;
|
||||
import org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cassandra.actuate.health;
|
||||
package org.springframework.boot.cassandra.health;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -31,8 +31,8 @@ import com.datastax.oss.driver.api.core.metadata.Node;
|
|||
import com.datastax.oss.driver.api.core.metadata.NodeState;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cassandra.actuate.health;
|
||||
package org.springframework.boot.cassandra.health;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
|
@ -34,8 +34,8 @@ import org.junit.jupiter.api.Test;
|
|||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.Status;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue