Merge branch 'rework-health-support'
This commit is contained in:
@@ -37,6 +37,8 @@ import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.TraceEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.VanillaPublicMetrics;
|
||||
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
|
||||
import org.springframework.boot.actuate.health.HealthAggregator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.metrics.reader.MetricReader;
|
||||
import org.springframework.boot.actuate.metrics.repository.InMemoryMetricRepository;
|
||||
@@ -74,7 +76,10 @@ public class EndpointAutoConfiguration {
|
||||
private InfoPropertiesConfiguration properties;
|
||||
|
||||
@Autowired(required = false)
|
||||
Map<String, HealthIndicator<? extends Object>> healthIndicators = new HashMap<String, HealthIndicator<? extends Object>>();
|
||||
private HealthAggregator healthAggregator = new OrderedHealthAggregator();
|
||||
|
||||
@Autowired(required = false)
|
||||
Map<String, HealthIndicator> healthIndicators = new HashMap<String, HealthIndicator>();
|
||||
|
||||
@Autowired(required = false)
|
||||
private MetricReader metricRepository = new InMemoryMetricRepository();
|
||||
@@ -97,7 +102,7 @@ public class EndpointAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public HealthEndpoint healthEndpoint() {
|
||||
return new HealthEndpoint(this.healthIndicators);
|
||||
return new HealthEndpoint(this.healthAggregator, this.healthIndicators);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -33,10 +33,12 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EnvironmentMvcEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.MetricsMvcEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.ShutdownMvcEndpoint;
|
||||
@@ -54,6 +56,7 @@ import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
|
||||
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
|
||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerException;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
@@ -72,16 +75,18 @@ import org.springframework.web.servlet.DispatcherServlet;
|
||||
* different port to {@link ServerProperties} a new child context is created, otherwise it
|
||||
* is assumed that endpoint requests will be mapped and handled via an already registered
|
||||
* {@link DispatcherServlet}.
|
||||
*
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
|
||||
@ConditionalOnWebApplication
|
||||
@AutoConfigureAfter({ PropertyPlaceholderAutoConfiguration.class,
|
||||
EmbeddedServletContainerAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
ManagementServerPropertiesAutoConfiguration.class })
|
||||
EmbeddedServletContainerAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
ManagementServerPropertiesAutoConfiguration.class })
|
||||
@EnableConfigurationProperties(HealthMvcEndpointProperties.class)
|
||||
public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
|
||||
ApplicationListener<ContextRefreshedEvent> {
|
||||
|
||||
@@ -89,6 +94,9 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
private HealthMvcEndpointProperties healthMvcEndpointProperties;
|
||||
|
||||
@Autowired
|
||||
private ManagementServerProperties managementServerProperties;
|
||||
|
||||
@@ -101,8 +109,8 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public EndpointHandlerMapping endpointHandlerMapping() {
|
||||
EndpointHandlerMapping mapping = new EndpointHandlerMapping(mvcEndpoints()
|
||||
.getEndpoints());
|
||||
EndpointHandlerMapping mapping = new EndpointHandlerMapping(
|
||||
mvcEndpoints().getEndpoints());
|
||||
boolean disabled = ManagementServerPort.get(this.applicationContext) != ManagementServerPort.SAME;
|
||||
mapping.setDisabled(disabled);
|
||||
if (!disabled) {
|
||||
@@ -125,10 +133,12 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
|
||||
// instantiation of ManagementServerProperties.
|
||||
@Configuration
|
||||
protected static class ApplicationContextFilterConfiguration {
|
||||
|
||||
@Bean
|
||||
public Filter applicationContextIdFilter(ApplicationContext context) {
|
||||
final String id = context.getId();
|
||||
return new OncePerRequestFilter() {
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request,
|
||||
HttpServletResponse response, FilterChain filterChain)
|
||||
@@ -153,6 +163,17 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
|
||||
return new EnvironmentMvcEndpoint(delegate);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(HealthEndpoint.class)
|
||||
@ConditionalOnExpression("${endpoints.health.enabled:true}")
|
||||
public HealthMvcEndpoint healthMvcEndpoint(HealthEndpoint delegate) {
|
||||
HealthMvcEndpoint healthMvcEndpoint = new HealthMvcEndpoint(delegate);
|
||||
if (this.healthMvcEndpointProperties.getMapping() != null) {
|
||||
healthMvcEndpoint.setStatusMapping(this.healthMvcEndpointProperties.getMapping());
|
||||
}
|
||||
return healthMvcEndpoint;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(MetricsEndpoint.class)
|
||||
@ConditionalOnExpression("${endpoints.metrics.enabled:true}")
|
||||
@@ -184,27 +205,25 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
|
||||
|
||||
// Ensure close on the parent also closes the child
|
||||
if (this.applicationContext instanceof ConfigurableApplicationContext) {
|
||||
((ConfigurableApplicationContext) this.applicationContext)
|
||||
.addApplicationListener(new ApplicationListener<ContextClosedEvent>() {
|
||||
@Override
|
||||
public void onApplicationEvent(ContextClosedEvent event) {
|
||||
if (event.getApplicationContext() == EndpointWebMvcAutoConfiguration.this.applicationContext) {
|
||||
childContext.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
((ConfigurableApplicationContext) this.applicationContext).addApplicationListener(new ApplicationListener<ContextClosedEvent>() {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextClosedEvent event) {
|
||||
if (event.getApplicationContext() == EndpointWebMvcAutoConfiguration.this.applicationContext) {
|
||||
childContext.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
try {
|
||||
childContext.refresh();
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
} catch (RuntimeException ex) {
|
||||
// No support currently for deploying a war with management.port=<different>,
|
||||
// and this is the signature of that happening
|
||||
if (ex instanceof EmbeddedServletContainerException
|
||||
|| ex.getCause() instanceof EmbeddedServletContainerException) {
|
||||
logger.warn("Could not start embedded container (management endpoints are still available through JMX)");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
@@ -219,17 +238,14 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
|
||||
ServerProperties serverProperties;
|
||||
try {
|
||||
serverProperties = beanFactory.getBean(ServerProperties.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
} catch (NoSuchBeanDefinitionException ex) {
|
||||
serverProperties = new ServerProperties();
|
||||
}
|
||||
|
||||
ManagementServerProperties managementServerProperties;
|
||||
try {
|
||||
managementServerProperties = beanFactory
|
||||
.getBean(ManagementServerProperties.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
managementServerProperties = beanFactory.getBean(ManagementServerProperties.class);
|
||||
} catch (NoSuchBeanDefinitionException ex) {
|
||||
managementServerProperties = new ManagementServerProperties();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,15 +16,19 @@
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.actuate.health.CompositeHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthAggregator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.MongoHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
|
||||
import org.springframework.boot.actuate.health.RabbitHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.RedisHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.SimpleDataSourceHealthIndicator;
|
||||
@@ -58,9 +62,22 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
RabbitAutoConfiguration.class })
|
||||
public class HealthIndicatorAutoConfiguration {
|
||||
|
||||
@Value("${health.status.order:}")
|
||||
private List<String> statusOrder = null;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public HealthAggregator healthAggregator() {
|
||||
OrderedHealthAggregator healthAggregator = new OrderedHealthAggregator();
|
||||
if (this.statusOrder != null) {
|
||||
healthAggregator.setStatusOrder(this.statusOrder);
|
||||
}
|
||||
return healthAggregator;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(HealthIndicator.class)
|
||||
public HealthIndicator<?> statusHealthIndicator() {
|
||||
public HealthIndicator statusHealthIndicator() {
|
||||
return new VanillaHealthIndicator();
|
||||
}
|
||||
|
||||
@@ -69,18 +86,22 @@ public class HealthIndicatorAutoConfiguration {
|
||||
@ConditionalOnExpression("${health.db.enabled:true}")
|
||||
public static class DataSourcesHealthIndicatorConfiguration {
|
||||
|
||||
@Autowired
|
||||
private HealthAggregator healthAggregator;
|
||||
|
||||
@Autowired(required = false)
|
||||
private Map<String, DataSource> dataSources;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "dbHealthIndicator")
|
||||
public HealthIndicator<? extends Object> dbHealthIndicator() {
|
||||
public HealthIndicator dbHealthIndicator() {
|
||||
if (this.dataSources.size() == 1) {
|
||||
return new SimpleDataSourceHealthIndicator(this.dataSources.values()
|
||||
.iterator().next());
|
||||
}
|
||||
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator();
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator(
|
||||
this.healthAggregator);
|
||||
for (Map.Entry<String, DataSource> entry : this.dataSources.entrySet()) {
|
||||
composite.addHealthIndicator(entry.getKey(),
|
||||
new SimpleDataSourceHealthIndicator(entry.getValue()));
|
||||
@@ -94,18 +115,22 @@ public class HealthIndicatorAutoConfiguration {
|
||||
@ConditionalOnExpression("${health.mongo.enabled:true}")
|
||||
public static class MongoHealthIndicatorConfiguration {
|
||||
|
||||
@Autowired
|
||||
private HealthAggregator healthAggregator;
|
||||
|
||||
@Autowired
|
||||
private Map<String, MongoTemplate> mongoTemplates;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "mongoHealthIndicator")
|
||||
public HealthIndicator<?> mongoHealthIndicator() {
|
||||
public HealthIndicator mongoHealthIndicator() {
|
||||
if (this.mongoTemplates.size() == 1) {
|
||||
return new MongoHealthIndicator(this.mongoTemplates.values().iterator()
|
||||
.next());
|
||||
}
|
||||
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator();
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator(
|
||||
this.healthAggregator);
|
||||
for (Map.Entry<String, MongoTemplate> entry : this.mongoTemplates.entrySet()) {
|
||||
composite.addHealthIndicator(entry.getKey(), new MongoHealthIndicator(
|
||||
entry.getValue()));
|
||||
@@ -119,18 +144,22 @@ public class HealthIndicatorAutoConfiguration {
|
||||
@ConditionalOnExpression("${health.redis.enabled:true}")
|
||||
public static class RedisHealthIndicatorConfiguration {
|
||||
|
||||
@Autowired
|
||||
private HealthAggregator healthAggregator;
|
||||
|
||||
@Autowired
|
||||
private Map<String, RedisConnectionFactory> redisConnectionFactories;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "redisHealthIndicator")
|
||||
public HealthIndicator<?> redisHealthIndicator() {
|
||||
public HealthIndicator redisHealthIndicator() {
|
||||
if (this.redisConnectionFactories.size() == 1) {
|
||||
return new RedisHealthIndicator(this.redisConnectionFactories.values()
|
||||
.iterator().next());
|
||||
}
|
||||
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator();
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator(
|
||||
this.healthAggregator);
|
||||
for (Map.Entry<String, RedisConnectionFactory> entry : this.redisConnectionFactories
|
||||
.entrySet()) {
|
||||
composite.addHealthIndicator(entry.getKey(), new RedisHealthIndicator(
|
||||
@@ -145,18 +174,22 @@ public class HealthIndicatorAutoConfiguration {
|
||||
@ConditionalOnExpression("${health.rabbit.enabled:true}")
|
||||
public static class RabbitHealthIndicatorConfiguration {
|
||||
|
||||
@Autowired
|
||||
private HealthAggregator healthAggregator;
|
||||
|
||||
@Autowired
|
||||
private Map<String, RabbitTemplate> rabbitTemplates;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "rabbitHealthIndicator")
|
||||
public HealthIndicator<?> rabbitHealthIndicator() {
|
||||
public HealthIndicator rabbitHealthIndicator() {
|
||||
if (this.rabbitTemplates.size() == 1) {
|
||||
return new RabbitHealthIndicator(this.rabbitTemplates.values().iterator()
|
||||
.next());
|
||||
}
|
||||
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator();
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator(
|
||||
this.healthAggregator);
|
||||
for (Map.Entry<String, RabbitTemplate> entry : this.rabbitTemplates
|
||||
.entrySet()) {
|
||||
composite.addHealthIndicator(entry.getKey(), new RabbitHealthIndicator(
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* Configuration properties for the {@link HealthMvcEndpoint}.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "endpoints.health")
|
||||
public class HealthMvcEndpointProperties {
|
||||
|
||||
private Map<String, HttpStatus> mapping = new HashMap<String, HttpStatus>();
|
||||
|
||||
public Map<String, HttpStatus> getMapping() {
|
||||
return this.mapping;
|
||||
}
|
||||
|
||||
public void setMapping(Map<String, HttpStatus> mapping) {
|
||||
this.mapping = mapping;
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,11 @@
|
||||
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.springframework.boot.actuate.health.CompositeHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthAggregator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -30,30 +31,39 @@ import org.springframework.util.Assert;
|
||||
* @author Dave Syer
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "endpoints.health", ignoreUnknownFields = false)
|
||||
public class HealthEndpoint extends AbstractEndpoint<Map<String, Object>> {
|
||||
@ConfigurationProperties(prefix = "endpoints.health", ignoreUnknownFields = true)
|
||||
public class HealthEndpoint extends AbstractEndpoint<Health> {
|
||||
|
||||
private final Map<String, HealthIndicator<? extends Object>> healthIndicators;
|
||||
private final HealthIndicator healthIndicator;
|
||||
|
||||
/**
|
||||
* Create a new {@link HealthIndicator} instance.
|
||||
*/
|
||||
public HealthEndpoint(Map<String, HealthIndicator<? extends Object>> healthIndicators) {
|
||||
public HealthEndpoint(HealthAggregator healthAggregator,
|
||||
Map<String, HealthIndicator> healthIndicators) {
|
||||
super("health", false, true);
|
||||
Assert.notNull(healthIndicators, "HealthIndicator must not be null");
|
||||
this.healthIndicators = healthIndicators;
|
||||
|
||||
Assert.notNull(healthAggregator, "HealthAggregator must not be null");
|
||||
Assert.notNull(healthIndicators, "HealthIndicators must not be null");
|
||||
|
||||
if (healthIndicators.size() == 1) {
|
||||
this.healthIndicator = healthIndicators.values().iterator().next();
|
||||
} else {
|
||||
CompositeHealthIndicator healthIndicator = new CompositeHealthIndicator(
|
||||
healthAggregator);
|
||||
for (Map.Entry<String, HealthIndicator> h : healthIndicators.entrySet()) {
|
||||
healthIndicator.addHealthIndicator(getKey(h.getKey()), h.getValue());
|
||||
}
|
||||
this.healthIndicator = healthIndicator;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke all {@link HealthIndicator} delegates and collect their health information.
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> invoke() {
|
||||
Map<String, Object> health = new LinkedHashMap<String, Object>();
|
||||
for (Entry<String, HealthIndicator<?>> entry : this.healthIndicators.entrySet()) {
|
||||
health.put(getKey(entry.getKey()), entry.getValue().health());
|
||||
}
|
||||
return health;
|
||||
public Health invoke() {
|
||||
return this.healthIndicator.health();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.endpoint.mvc;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
/**
|
||||
* Adapter to expose {@link HealthEndpoint} as an {@link MvcEndpoint}.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class HealthMvcEndpoint extends EndpointMvcAdapter {
|
||||
|
||||
private Map<String, HttpStatus> statusMapping;
|
||||
|
||||
public HealthMvcEndpoint(HealthEndpoint delegate) {
|
||||
super(delegate);
|
||||
setupDefaultStatusMapping();
|
||||
}
|
||||
|
||||
public void setStatusMapping(Map<String, HttpStatus> statusMapping) {
|
||||
Assert.notNull(statusMapping, "StatusMapping must not be null");
|
||||
this.statusMapping = statusMapping;
|
||||
}
|
||||
|
||||
@RequestMapping
|
||||
@ResponseBody
|
||||
@Override
|
||||
public Object invoke() {
|
||||
if (!this.getDelegate().isEnabled()) {
|
||||
// Shouldn't happen
|
||||
return new ResponseEntity<Map<String, String>>(Collections.singletonMap(
|
||||
"message", "This endpoint is disabled"), HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
Health health = (Health) getDelegate().invoke();
|
||||
Status status = health.getStatus();
|
||||
if (this.statusMapping.containsKey(status.getCode())) {
|
||||
return new ResponseEntity<Health>(health,
|
||||
this.statusMapping.get(status.getCode()));
|
||||
}
|
||||
return health;
|
||||
}
|
||||
|
||||
private void setupDefaultStatusMapping() {
|
||||
this.statusMapping = new HashMap<String, HttpStatus>();
|
||||
this.statusMapping.put(Status.DOWN.getCode(), HttpStatus.SERVICE_UNAVAILABLE);
|
||||
this.statusMapping.put(Status.OUT_OF_SERVICE.getCode(),
|
||||
HttpStatus.SERVICE_UNAVAILABLE);
|
||||
}
|
||||
}
|
||||
@@ -19,22 +19,27 @@ package org.springframework.boot.actuate.health;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link HealthIndicator} that returns health indications from all registered delegates.
|
||||
*
|
||||
*
|
||||
* @author Tyler J. Frederick
|
||||
* @author Phillip Webb
|
||||
* @author Christian Dupuis
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class CompositeHealthIndicator implements HealthIndicator<Map<String, Object>> {
|
||||
public class CompositeHealthIndicator implements HealthIndicator {
|
||||
|
||||
private final Map<String, HealthIndicator<?>> indicators;
|
||||
private final Map<String, HealthIndicator> indicators;
|
||||
|
||||
private final HealthAggregator healthAggregator;
|
||||
|
||||
/**
|
||||
* Create a new {@link CompositeHealthIndicator}.
|
||||
*/
|
||||
public CompositeHealthIndicator() {
|
||||
this.indicators = new LinkedHashMap<String, HealthIndicator<?>>();
|
||||
public CompositeHealthIndicator(HealthAggregator healthAggregator) {
|
||||
this(healthAggregator, new LinkedHashMap<String, HealthIndicator>());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,21 +47,25 @@ public class CompositeHealthIndicator implements HealthIndicator<Map<String, Obj
|
||||
* @param indicators a map of {@link HealthIndicator}s with the key being used as an
|
||||
* indicator name.
|
||||
*/
|
||||
public CompositeHealthIndicator(Map<String, HealthIndicator<?>> indicators) {
|
||||
this.indicators = new LinkedHashMap<String, HealthIndicator<?>>(indicators);
|
||||
public CompositeHealthIndicator(HealthAggregator healthAggregator,
|
||||
Map<String, HealthIndicator> indicators) {
|
||||
Assert.notNull(healthAggregator, "HealthAggregator must not be null");
|
||||
Assert.notNull(healthAggregator, "Indicators must not be null");
|
||||
this.indicators = new LinkedHashMap<String, HealthIndicator>(indicators);
|
||||
this.healthAggregator = healthAggregator;
|
||||
}
|
||||
|
||||
public void addHealthIndicator(String name, HealthIndicator<?> indicator) {
|
||||
public void addHealthIndicator(String name, HealthIndicator indicator) {
|
||||
this.indicators.put(name, indicator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> health() {
|
||||
Map<String, Object> health = new LinkedHashMap<String, Object>();
|
||||
for (Map.Entry<String, HealthIndicator<?>> entry : this.indicators.entrySet()) {
|
||||
health.put(entry.getKey(), entry.getValue().health());
|
||||
public Health health() {
|
||||
Map<String, Health> healths = new LinkedHashMap<String, Health>();
|
||||
for (Map.Entry<String, HealthIndicator> entry : this.indicators.entrySet()) {
|
||||
healths.put(entry.getKey(), entry.getValue().health());
|
||||
}
|
||||
return health;
|
||||
return this.healthAggregator.aggregate(healths);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.health;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnyGetter;
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
||||
|
||||
/**
|
||||
* Value object used to carry information about the health information of a component or
|
||||
* subsystem.
|
||||
*
|
||||
* <p>
|
||||
* {@link Health} contains a {@link Status} to express the state of a component or
|
||||
* subsystem and some additional details to carry some contextual information.
|
||||
*
|
||||
* <p>
|
||||
* {@link Health} has a fluent API to make it easy to construct instances. Typical usage
|
||||
* in a {@link HealthIndicator} would be:
|
||||
*
|
||||
* <code>
|
||||
* Health health = new Health();
|
||||
* try {
|
||||
* // do some test to determine state of component
|
||||
*
|
||||
* health.up().withDetail("version", "1.1.2");
|
||||
* }
|
||||
* catch (Exception ex) {
|
||||
* health.down().withException(ex);
|
||||
* }
|
||||
* return health;
|
||||
* </code>
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
public class Health {
|
||||
|
||||
private Status status;
|
||||
|
||||
private Map<String, Object> details;
|
||||
|
||||
public Health() {
|
||||
this(Status.UNKOWN);
|
||||
}
|
||||
|
||||
public Health(Status status) {
|
||||
this.status = status;
|
||||
this.details = new LinkedHashMap<String, Object>();
|
||||
}
|
||||
|
||||
public Health status(Status status) {
|
||||
Assert.notNull(status, "Status must not be null");
|
||||
this.status = status;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Health up() {
|
||||
return status(Status.UP);
|
||||
}
|
||||
|
||||
public Health down() {
|
||||
return status(Status.DOWN);
|
||||
}
|
||||
|
||||
public Health withException(Exception ex) {
|
||||
Assert.notNull(ex, "Exception must not be null");
|
||||
return withDetail("error", ex.getClass().getName() + ": " + ex.getMessage());
|
||||
}
|
||||
|
||||
@JsonAnySetter
|
||||
public Health withDetail(String key, Object data) {
|
||||
Assert.notNull(key, "Key must not be null");
|
||||
Assert.notNull(data, "Data must not be null");
|
||||
this.details.put(key, data);
|
||||
return this;
|
||||
}
|
||||
|
||||
@JsonUnwrapped
|
||||
public Status getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
@JsonAnyGetter
|
||||
public Map<String, Object> getDetails() {
|
||||
return this.details;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj != null && obj instanceof Health) {
|
||||
return ObjectUtils.nullSafeEquals(this.status, ((Health) obj).status)
|
||||
&& ObjectUtils.nullSafeEquals(this.details, ((Health) obj).details);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = 0;
|
||||
if (this.status != null) {
|
||||
hashCode = this.status.hashCode();
|
||||
}
|
||||
return 13 * hashCode + this.details.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.health;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Strategy interface used by {@link CompositeHealthIndicator} to aggregate {@link Health}
|
||||
* instances into a final one.
|
||||
*
|
||||
* <p>
|
||||
* This is especially useful to combine subsystem states expressed through
|
||||
* {@link Health#getStatus()} into one state for the entire system. The default
|
||||
* implementation {@link OrderedHealthAggregator} sorts {@link Status} instances based on
|
||||
* a priority list.
|
||||
*
|
||||
* <p>
|
||||
* It is possible to add more complex {@link Status} types to the system. In that case
|
||||
* either the {@link OrderedHealthAggregator} needs to be properly configured or users
|
||||
* need to register a custom {@link HealthAggregator} as bean.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public interface HealthAggregator {
|
||||
|
||||
/**
|
||||
* Aggregate several given {@link Health} instances into one.
|
||||
*/
|
||||
Health aggregate(Map<String, Health> healths);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
* Copyright 2012-2014 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.
|
||||
@@ -18,15 +18,15 @@ package org.springframework.boot.actuate.health;
|
||||
|
||||
/**
|
||||
* Strategy interface used to provide an indication of application health.
|
||||
*
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @see VanillaHealthIndicator
|
||||
*/
|
||||
public interface HealthIndicator<T> {
|
||||
public interface HealthIndicator {
|
||||
|
||||
/**
|
||||
* @return an indication of health
|
||||
*/
|
||||
T health();
|
||||
Health health();
|
||||
|
||||
}
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package org.springframework.boot.actuate.health;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -27,11 +24,11 @@ import com.mongodb.CommandResult;
|
||||
/**
|
||||
* Simple implementation of a {@link HealthIndicator} returning status information for
|
||||
* Mongo data stores.
|
||||
*
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class MongoHealthIndicator implements HealthIndicator<Map<String, Object>> {
|
||||
public class MongoHealthIndicator implements HealthIndicator {
|
||||
|
||||
private final MongoTemplate mongoTemplate;
|
||||
|
||||
@@ -41,17 +38,15 @@ public class MongoHealthIndicator implements HealthIndicator<Map<String, Object>
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> health() {
|
||||
Map<String, Object> health = new HashMap<String, Object>();
|
||||
public Health health() {
|
||||
Health health = new Health();
|
||||
try {
|
||||
CommandResult result = this.mongoTemplate
|
||||
.executeCommand("{ serverStatus: 1 }");
|
||||
health.put("status", "ok");
|
||||
health.put("version", result.getString("version"));
|
||||
health.up().withDetail("version", result.getString("version"));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
health.put("status", "error");
|
||||
health.put("error", ex.getClass().getName() + ": " + ex.getMessage());
|
||||
health.down().withException(ex);
|
||||
}
|
||||
return health;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.health;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Default {@link HealthAggregator} implementation that aggregates {@link Health}
|
||||
* instances and determines the final system state based on a simple ordered list.
|
||||
*
|
||||
* <p>
|
||||
* If a different order is required or a new {@link Status} type will be used, the order
|
||||
* can be set by calling {@link #setStatusOrder(List)}.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class OrderedHealthAggregator implements HealthAggregator {
|
||||
|
||||
private List<String> statusOrder = Arrays.asList("DOWN", "OUT_OF_SERVICE", "UP",
|
||||
"UNKOWN");
|
||||
|
||||
@Override
|
||||
public Health aggregate(Map<String, Health> healths) {
|
||||
Health health = new Health();
|
||||
|
||||
List<Status> status = new ArrayList<Status>();
|
||||
for (Map.Entry<String, Health> h : healths.entrySet()) {
|
||||
health.withDetail(h.getKey(), h.getValue());
|
||||
status.add(h.getValue().getStatus());
|
||||
}
|
||||
health.status(aggregateStatus(status));
|
||||
return health;
|
||||
}
|
||||
|
||||
public void setStatusOrder(List<String> statusOrder) {
|
||||
this.statusOrder = statusOrder;
|
||||
}
|
||||
|
||||
protected Status aggregateStatus(List<Status> status) {
|
||||
|
||||
if (status.size() == 0) {
|
||||
return Status.UNKOWN;
|
||||
}
|
||||
|
||||
status.sort(new Comparator<Status>() {
|
||||
|
||||
@Override
|
||||
public int compare(Status s1, Status s2) {
|
||||
return Integer.valueOf(
|
||||
OrderedHealthAggregator.this.statusOrder.indexOf(s1.getCode())).compareTo(
|
||||
Integer.valueOf(OrderedHealthAggregator.this.statusOrder.indexOf(s2.getCode())));
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
return status.get(0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.boot.actuate.health;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.amqp.rabbit.core.ChannelCallback;
|
||||
@@ -28,11 +27,11 @@ import com.rabbitmq.client.Channel;
|
||||
/**
|
||||
* Simple implementation of a {@link HealthIndicator} returning status information for the
|
||||
* RabbitMQ messaging system.
|
||||
*
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class RabbitHealthIndicator implements HealthIndicator<Map<String, Object>> {
|
||||
public class RabbitHealthIndicator implements HealthIndicator {
|
||||
|
||||
private final RabbitTemplate rabbitTemplate;
|
||||
|
||||
@@ -42,10 +41,10 @@ public class RabbitHealthIndicator implements HealthIndicator<Map<String, Object
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> health() {
|
||||
Map<String, Object> health = new HashMap<String, Object>();
|
||||
public Health health() {
|
||||
Health health = new Health();
|
||||
try {
|
||||
health.put("version",
|
||||
health.up().withDetail("version",
|
||||
this.rabbitTemplate.execute(new ChannelCallback<String>() {
|
||||
|
||||
@Override
|
||||
@@ -55,12 +54,9 @@ public class RabbitHealthIndicator implements HealthIndicator<Map<String, Object
|
||||
return serverProperties.get("version").toString();
|
||||
}
|
||||
}));
|
||||
|
||||
health.put("status", "ok");
|
||||
}
|
||||
catch (Exception ex) {
|
||||
health.put("status", "error");
|
||||
health.put("error", ex.getClass().getName() + ": " + ex.getMessage());
|
||||
health.down().withException(ex);
|
||||
}
|
||||
return health;
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.boot.actuate.health;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
@@ -28,11 +26,11 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* Simple implementation of a {@link HealthIndicator} returning status information for
|
||||
* Redis data stores.
|
||||
*
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class RedisHealthIndicator implements HealthIndicator<Map<String, Object>> {
|
||||
public class RedisHealthIndicator implements HealthIndicator {
|
||||
|
||||
private final RedisConnectionFactory redisConnectionFactory;
|
||||
|
||||
@@ -42,19 +40,17 @@ public class RedisHealthIndicator implements HealthIndicator<Map<String, Object>
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> health() {
|
||||
Map<String, Object> health = new HashMap<String, Object>();
|
||||
public Health health() {
|
||||
Health health = new Health();
|
||||
|
||||
RedisConnection connection = null;
|
||||
try {
|
||||
connection = RedisConnectionUtils.getConnection(this.redisConnectionFactory);
|
||||
Properties info = connection.info();
|
||||
health.put("status", "ok");
|
||||
health.put("version", info.getProperty("redis_version"));
|
||||
health.up().withDetail("version", info.getProperty("redis_version"));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
health.put("status", "error");
|
||||
health.put("error", ex.getClass().getName() + ": " + ex.getMessage());
|
||||
health.down().withException(ex);
|
||||
}
|
||||
finally {
|
||||
RedisConnectionUtils.releaseConnection(connection,
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.springframework.boot.actuate.health;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
@@ -32,8 +31,9 @@ import org.springframework.util.StringUtils;
|
||||
/**
|
||||
* Simple implementation of {@link HealthIndicator} that returns a status and also
|
||||
* attempts a simple database test.
|
||||
*
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
public class SimpleDataSourceHealthIndicator implements
|
||||
HealthIndicator<Map<String, Object>> {
|
||||
@@ -72,9 +72,10 @@ public class SimpleDataSourceHealthIndicator implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> health() {
|
||||
LinkedHashMap<String, Object> health = new LinkedHashMap<String, Object>();
|
||||
health.put("status", "ok");
|
||||
public Health health() {
|
||||
Health health = new Health();
|
||||
health.up();
|
||||
|
||||
String product = "unknown";
|
||||
if (this.dataSource != null) {
|
||||
try {
|
||||
@@ -85,21 +86,19 @@ public class SimpleDataSourceHealthIndicator implements
|
||||
return connection.getMetaData().getDatabaseProductName();
|
||||
}
|
||||
});
|
||||
health.put("database", product);
|
||||
health.withDetail("database", product);
|
||||
}
|
||||
catch (DataAccessException ex) {
|
||||
health.put("status", "error");
|
||||
health.put("error", ex.getClass().getName() + ": " + ex.getMessage());
|
||||
health.down().withException(ex);
|
||||
}
|
||||
String query = detectQuery(product);
|
||||
if (StringUtils.hasText(query)) {
|
||||
try {
|
||||
health.put("hello",
|
||||
health.withDetail("hello",
|
||||
this.jdbcTemplate.queryForObject(query, Object.class));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
health.put("status", "error");
|
||||
health.put("error", ex.getClass().getName() + ": " + ex.getMessage());
|
||||
health.down().withException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.health;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Value object to express state of a component or subsystem.
|
||||
*
|
||||
* <p>
|
||||
* Status provides convenient constants for commonly used states like {@link #UP},
|
||||
* {@link #DOWN} or {@link #OUT_OF_SERVICE}.
|
||||
*
|
||||
* <p>
|
||||
* Custom states can also be created and used throughout the Spring Boot Health subsystem.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
public class Status {
|
||||
|
||||
/**
|
||||
* Convenient constant value representing unknown state
|
||||
*/
|
||||
public static final Status UNKOWN = new Status("UNKOWN");
|
||||
|
||||
/**
|
||||
* Convenient constant value representing up state
|
||||
*/
|
||||
public static final Status UP = new Status("UP");
|
||||
|
||||
/**
|
||||
* Convenient constant value representing down state
|
||||
*/
|
||||
public static final Status DOWN = new Status("DOWN");
|
||||
|
||||
/**
|
||||
* Convenient constant value representing out-of-service state
|
||||
*/
|
||||
public static final Status OUT_OF_SERVICE = new Status("OUT_OF_SERVICE");
|
||||
|
||||
private final String code;
|
||||
|
||||
private final String description;
|
||||
|
||||
public Status(String code) {
|
||||
this(code, "");
|
||||
}
|
||||
|
||||
public Status(String code, String description) {
|
||||
Assert.notNull(code, "Code must not be null");
|
||||
Assert.notNull(description, "Description must not be null");
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@JsonProperty("status")
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj != null && obj instanceof Status) {
|
||||
return ObjectUtils.nullSafeEquals(this.code, ((Status) obj).code);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.code.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -16,16 +16,18 @@
|
||||
|
||||
package org.springframework.boot.actuate.health;
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of {@link HealthIndicator} that simply returns {@literal "ok"}.
|
||||
*
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
public class VanillaHealthIndicator implements HealthIndicator<String> {
|
||||
public class VanillaHealthIndicator implements HealthIndicator {
|
||||
|
||||
@Override
|
||||
public String health() {
|
||||
return "ok";
|
||||
public Health health() {
|
||||
return new Health(Status.UP);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -31,6 +29,7 @@ import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.TraceEndpoint;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
|
||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||
import org.springframework.boot.test.EnvironmentTestUtils;
|
||||
@@ -43,10 +42,11 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for {@link EndpointAutoConfiguration}.
|
||||
*
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @author Greg Turnquist
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
public class EndpointAutoConfigurationTests {
|
||||
|
||||
@@ -80,7 +80,6 @@ public class EndpointAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void healthEndpoint() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
this.context.register(EmbeddedDataSourceConfiguration.class,
|
||||
@@ -88,12 +87,9 @@ public class EndpointAutoConfigurationTests {
|
||||
this.context.refresh();
|
||||
HealthEndpoint bean = this.context.getBean(HealthEndpoint.class);
|
||||
assertNotNull(bean);
|
||||
Map<String, Object> result = bean.invoke();
|
||||
Health result = bean.invoke();
|
||||
assertNotNull(result);
|
||||
assertTrue("Wrong result: " + result,
|
||||
((Map<String, Object>) result.get("db")).containsKey("status"));
|
||||
assertTrue("Wrong result: " + result,
|
||||
((Map<String, Object>) result.get("db")).containsKey("database"));
|
||||
assertTrue("Wrong result: " + result, result.getDetails().containsKey("database"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -104,9 +100,8 @@ public class EndpointAutoConfigurationTests {
|
||||
this.context.refresh();
|
||||
HealthEndpoint bean = this.context.getBean(HealthEndpoint.class);
|
||||
assertNotNull(bean);
|
||||
Map<String, Object> result = bean.invoke();
|
||||
Health result = bean.invoke();
|
||||
assertNotNull(result);
|
||||
assertTrue("Wrong result: " + result, result.containsKey("status"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -60,7 +60,6 @@ public class HealthIndicatorAutoConfigurationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void defaultHealthIndicator() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
@@ -73,7 +72,6 @@ public class HealthIndicatorAutoConfigurationTests {
|
||||
.getClass());
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void redisHealthIndicator() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
@@ -87,7 +85,6 @@ public class HealthIndicatorAutoConfigurationTests {
|
||||
.getClass());
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void notRedisHealthIndicator() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
@@ -102,7 +99,6 @@ public class HealthIndicatorAutoConfigurationTests {
|
||||
.getClass());
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void mongoHealthIndicator() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
@@ -116,7 +112,6 @@ public class HealthIndicatorAutoConfigurationTests {
|
||||
.getClass());
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void notMongoHealthIndicator() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
@@ -131,7 +126,6 @@ public class HealthIndicatorAutoConfigurationTests {
|
||||
.getClass());
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void combinedHealthIndicator() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
@@ -143,7 +137,6 @@ public class HealthIndicatorAutoConfigurationTests {
|
||||
assertEquals(2, beans.size());
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void dataSourceHealthIndicator() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
@@ -157,7 +150,6 @@ public class HealthIndicatorAutoConfigurationTests {
|
||||
.next().getClass());
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void notDataSourceHealthIndicator() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
@@ -172,7 +164,6 @@ public class HealthIndicatorAutoConfigurationTests {
|
||||
.getClass());
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void rabbitHealthIndicator() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
@@ -186,7 +177,6 @@ public class HealthIndicatorAutoConfigurationTests {
|
||||
.getClass());
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void notRabbitHealthIndicator() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
|
||||
@@ -16,11 +16,14 @@
|
||||
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthAggregator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -32,6 +35,7 @@ import static org.junit.Assert.assertThat;
|
||||
* Tests for {@link HealthEndpoint}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
public class HealthEndpointTests extends AbstractEndpointTests<HealthEndpoint> {
|
||||
|
||||
@@ -41,9 +45,8 @@ public class HealthEndpointTests extends AbstractEndpointTests<HealthEndpoint> {
|
||||
|
||||
@Test
|
||||
public void invoke() throws Exception {
|
||||
Map<String, Object> result = new HashMap<String, Object>();
|
||||
result.put("status", "fine");
|
||||
assertThat(getEndpointBean().invoke(), equalTo(result));
|
||||
Status result = new Status("FINE");
|
||||
assertThat(getEndpointBean().invoke().getStatus(), equalTo(result));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@@ -51,18 +54,25 @@ public class HealthEndpointTests extends AbstractEndpointTests<HealthEndpoint> {
|
||||
public static class Config {
|
||||
|
||||
@Bean
|
||||
public HealthEndpoint endpoint(Map<String, HealthIndicator<?>> healthIndicators) {
|
||||
return new HealthEndpoint(healthIndicators);
|
||||
public HealthEndpoint endpoint(HealthAggregator healthAggregator,
|
||||
Map<String, HealthIndicator> healthIndicators) {
|
||||
return new HealthEndpoint(healthAggregator, healthIndicators);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HealthIndicator<String> statusHealthIndicator() {
|
||||
return new HealthIndicator<String>() {
|
||||
public HealthIndicator statusHealthIndicator() {
|
||||
return new HealthIndicator() {
|
||||
|
||||
@Override
|
||||
public String health() {
|
||||
return "fine";
|
||||
public Health health() {
|
||||
return new Health().status(new Status("FINE"));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HealthAggregator healthAggregator() {
|
||||
return new OrderedHealthAggregator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.endpoint.mvc;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.actuate.endpoint.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Tests for {@link HealthMvcEndpoint}.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
public class HealthMvcEndpointTests {
|
||||
|
||||
private HealthEndpoint endpoint = null;
|
||||
|
||||
private HealthMvcEndpoint mvc = null;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
this.endpoint = mock(HealthEndpoint.class);
|
||||
when(this.endpoint.isEnabled()).thenReturn(true);
|
||||
this.mvc = new HealthMvcEndpoint(this.endpoint);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void up() {
|
||||
when(this.endpoint.invoke()).thenReturn(new Health().up());
|
||||
Object result = this.mvc.invoke();
|
||||
assertTrue(result instanceof Health);
|
||||
assertTrue(((Health) result).getStatus() == Status.UP);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void down() {
|
||||
when(this.endpoint.invoke()).thenReturn(new Health().down());
|
||||
Object result = this.mvc.invoke();
|
||||
assertTrue(result instanceof ResponseEntity);
|
||||
ResponseEntity<Health> response = (ResponseEntity<Health>) result;
|
||||
assertTrue(response.getBody().getStatus() == Status.DOWN);
|
||||
assertEquals(HttpStatus.SERVICE_UNAVAILABLE, response.getStatusCode());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void customMapping() {
|
||||
when(this.endpoint.invoke()).thenReturn(new Health().status(new Status("OK")));
|
||||
this.mvc.setStatusMapping(Collections.singletonMap("OK",
|
||||
HttpStatus.INTERNAL_SERVER_ERROR));
|
||||
Object result = this.mvc.invoke();
|
||||
assertTrue(result instanceof ResponseEntity);
|
||||
ResponseEntity<Health> response = (ResponseEntity<Health>) result;
|
||||
assertTrue(response.getBody().getStatus().equals(new Status("OK")));
|
||||
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
|
||||
}
|
||||
}
|
||||
@@ -24,71 +24,108 @@ import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasEntry;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
||||
/**
|
||||
* Tests for {@link CompositeHealthIndicator}
|
||||
*
|
||||
*
|
||||
* @author Tyler J. Frederick
|
||||
* @author Phillip Webb
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
public class CompositeHealthIndicatorTests {
|
||||
|
||||
@Mock
|
||||
private HealthIndicator<String> one;
|
||||
private HealthAggregator healthAggregator;
|
||||
|
||||
@Mock
|
||||
private HealthIndicator<String> two;
|
||||
private HealthIndicator one;
|
||||
|
||||
@Mock
|
||||
private HealthIndicator<String> three;
|
||||
private HealthIndicator two;
|
||||
|
||||
@Mock
|
||||
private HealthIndicator three;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
given(this.one.health()).willReturn("1");
|
||||
given(this.two.health()).willReturn("2");
|
||||
given(this.three.health()).willReturn("3");
|
||||
given(this.one.health()).willReturn(new Health().withDetail("1", "1"));
|
||||
given(this.two.health()).willReturn(new Health().withDetail("2", "2"));
|
||||
given(this.three.health()).willReturn(new Health().withDetail("3", "3"));
|
||||
|
||||
this.healthAggregator = new OrderedHealthAggregator();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithIndicators() throws Exception {
|
||||
Map<String, HealthIndicator<?>> indicators = new HashMap<String, HealthIndicator<?>>();
|
||||
Map<String, HealthIndicator> indicators = new HashMap<String, HealthIndicator>();
|
||||
indicators.put("one", this.one);
|
||||
indicators.put("two", this.two);
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator(indicators);
|
||||
Map<String, Object> result = composite.health();
|
||||
assertThat(result.size(), equalTo(2));
|
||||
assertThat(result, hasEntry("one", (Object) "1"));
|
||||
assertThat(result, hasEntry("two", (Object) "2"));
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator(
|
||||
this.healthAggregator, indicators);
|
||||
Health result = composite.health();
|
||||
assertThat(result.getDetails().size(), equalTo(2));
|
||||
assertThat(result.getDetails(),
|
||||
hasEntry("one", (Object) new Health().withDetail("1", "1")));
|
||||
assertThat(result.getDetails(),
|
||||
hasEntry("two", (Object) new Health().withDetail("2", "2")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithIndicatorsAndAdd() throws Exception {
|
||||
Map<String, HealthIndicator<?>> indicators = new HashMap<String, HealthIndicator<?>>();
|
||||
Map<String, HealthIndicator> indicators = new HashMap<String, HealthIndicator>();
|
||||
indicators.put("one", this.one);
|
||||
indicators.put("two", this.two);
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator(indicators);
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator(
|
||||
this.healthAggregator, indicators);
|
||||
composite.addHealthIndicator("three", this.three);
|
||||
Map<String, Object> result = composite.health();
|
||||
assertThat(result.size(), equalTo(3));
|
||||
assertThat(result, hasEntry("one", (Object) "1"));
|
||||
assertThat(result, hasEntry("two", (Object) "2"));
|
||||
assertThat(result, hasEntry("three", (Object) "3"));
|
||||
Health result = composite.health();
|
||||
assertThat(result.getDetails().size(), equalTo(3));
|
||||
assertThat(result.getDetails(),
|
||||
hasEntry("one", (Object) new Health().withDetail("1", "1")));
|
||||
assertThat(result.getDetails(),
|
||||
hasEntry("two", (Object) new Health().withDetail("2", "2")));
|
||||
assertThat(result.getDetails(),
|
||||
hasEntry("three", (Object) new Health().withDetail("3", "3")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithoutAndAdd() throws Exception {
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator();
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator(
|
||||
this.healthAggregator);
|
||||
composite.addHealthIndicator("one", this.one);
|
||||
composite.addHealthIndicator("two", this.two);
|
||||
Map<String, Object> result = composite.health();
|
||||
assertThat(result.size(), equalTo(2));
|
||||
assertThat(result, hasEntry("one", (Object) "1"));
|
||||
assertThat(result, hasEntry("two", (Object) "2"));
|
||||
Health result = composite.health();
|
||||
assertThat(result.getDetails().size(), equalTo(2));
|
||||
assertThat(result.getDetails(),
|
||||
hasEntry("one", (Object) new Health().withDetail("1", "1")));
|
||||
assertThat(result.getDetails(),
|
||||
hasEntry("two", (Object) new Health().withDetail("2", "2")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerialization() throws Exception {
|
||||
Map<String, HealthIndicator> indicators = new HashMap<String, HealthIndicator>();
|
||||
indicators.put("db1", this.one);
|
||||
indicators.put("db2", this.two);
|
||||
CompositeHealthIndicator innerComposite = new CompositeHealthIndicator(
|
||||
this.healthAggregator, indicators);
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator(
|
||||
this.healthAggregator);
|
||||
composite.addHealthIndicator("db", innerComposite);
|
||||
|
||||
Health result = composite.health();
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
assertEquals(
|
||||
"{\"status\":\"UNKOWN\",\"db\":{\"status\":\"UNKOWN\",\"db1\":{\"status\":\"UNKOWN\",\"1\":\"1\"},\"db2\":{\"status\":\"UNKOWN\",\"2\":\"2\"}}}",
|
||||
mapper.writeValueAsString(result));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.boot.actuate.health;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
@@ -38,7 +36,7 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for {@link MongoHealthIndicator}.
|
||||
*
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
public class MongoHealthIndicatorTests {
|
||||
@@ -73,9 +71,9 @@ public class MongoHealthIndicatorTests {
|
||||
commandResult);
|
||||
MongoHealthIndicator healthIndicator = new MongoHealthIndicator(mongoTemplate);
|
||||
|
||||
Map<String, Object> health = healthIndicator.health();
|
||||
assertEquals("ok", health.get("status"));
|
||||
assertEquals("2.6.4", health.get("version"));
|
||||
Health health = healthIndicator.health();
|
||||
assertEquals(Status.UP, health.getStatus());
|
||||
assertEquals("2.6.4", health.getDetails().get("version"));
|
||||
|
||||
Mockito.verify(commandResult).getString("version");
|
||||
Mockito.verify(mongoTemplate).executeCommand("{ serverStatus: 1 }");
|
||||
@@ -88,9 +86,10 @@ public class MongoHealthIndicatorTests {
|
||||
new MongoException("Connection failed"));
|
||||
MongoHealthIndicator healthIndicator = new MongoHealthIndicator(mongoTemplate);
|
||||
|
||||
Map<String, Object> health = healthIndicator.health();
|
||||
assertEquals("error", health.get("status"));
|
||||
assertTrue(((String) health.get("error")).contains("Connection failed"));
|
||||
Health health = healthIndicator.health();
|
||||
assertEquals(Status.DOWN, health.getStatus());
|
||||
assertTrue(((String) health.getDetails().get("error"))
|
||||
.contains("Connection failed"));
|
||||
|
||||
Mockito.verify(mongoTemplate).executeCommand("{ serverStatus: 1 }");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.health;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests for {@link OrderedHealthAggregator}.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
public class OrderedHealthAggregatorTests {
|
||||
|
||||
private OrderedHealthAggregator healthAggregator;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.healthAggregator = new OrderedHealthAggregator();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultOrdering() {
|
||||
Map<String, Health> healths = new HashMap<String, Health>();
|
||||
healths.put("h1", new Health(Status.DOWN));
|
||||
healths.put("h2", new Health(Status.UP));
|
||||
healths.put("h3", new Health(Status.UNKOWN));
|
||||
healths.put("h4", new Health(Status.OUT_OF_SERVICE));
|
||||
assertEquals(Status.DOWN, this.healthAggregator.aggregate(healths).getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultOrderingWithCustomStatus() {
|
||||
Map<String, Health> healths = new HashMap<String, Health>();
|
||||
healths.put("h1", new Health(Status.DOWN));
|
||||
healths.put("h2", new Health(Status.UP));
|
||||
healths.put("h3", new Health(Status.UNKOWN));
|
||||
healths.put("h4", new Health(Status.OUT_OF_SERVICE));
|
||||
healths.put("h5", new Health(new Status("CUSTOM")));
|
||||
assertEquals(new Status("CUSTOM"),
|
||||
this.healthAggregator.aggregate(healths).getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultOrderingWithCustomStatusAndOrder() {
|
||||
this.healthAggregator.setStatusOrder(Arrays.asList("DOWN", "OUT_OF_SERVICE",
|
||||
"UP", "UNKOWN", "CUSTOM"));
|
||||
Map<String, Health> healths = new HashMap<String, Health>();
|
||||
healths.put("h1", new Health(Status.DOWN));
|
||||
healths.put("h2", new Health(Status.UP));
|
||||
healths.put("h3", new Health(Status.UNKOWN));
|
||||
healths.put("h4", new Health(Status.OUT_OF_SERVICE));
|
||||
healths.put("h5", new Health(new Status("CUSTOM")));
|
||||
assertEquals(Status.DOWN, this.healthAggregator.aggregate(healths).getStatus());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.boot.actuate.health;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.After;
|
||||
@@ -37,7 +36,7 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for {@link RedisHealthIndicator}.
|
||||
*
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
public class RedisHealthIndicatorTests {
|
||||
@@ -76,9 +75,9 @@ public class RedisHealthIndicatorTests {
|
||||
RedisHealthIndicator healthIndicator = new RedisHealthIndicator(
|
||||
redisConnectionFactory);
|
||||
|
||||
Map<String, Object> health = healthIndicator.health();
|
||||
assertEquals("ok", health.get("status"));
|
||||
assertEquals("2.8.9", health.get("version"));
|
||||
Health health = healthIndicator.health();
|
||||
assertEquals(Status.UP, health.getStatus());
|
||||
assertEquals("2.8.9", health.getDetails().get("version"));
|
||||
|
||||
Mockito.verify(redisConnectionFactory).getConnection();
|
||||
Mockito.verify(redisConnection).info();
|
||||
@@ -95,9 +94,10 @@ public class RedisHealthIndicatorTests {
|
||||
RedisHealthIndicator healthIndicator = new RedisHealthIndicator(
|
||||
redisConnectionFactory);
|
||||
|
||||
Map<String, Object> health = healthIndicator.health();
|
||||
assertEquals("error", health.get("status"));
|
||||
assertTrue(((String) health.get("error")).contains("Connection failed"));
|
||||
Health health = healthIndicator.health();
|
||||
assertEquals(Status.DOWN, health.getStatus());
|
||||
assertTrue(((String) health.getDetails().get("error"))
|
||||
.contains("Connection failed"));
|
||||
|
||||
Mockito.verify(redisConnectionFactory).getConnection();
|
||||
Mockito.verify(redisConnection).info();
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.boot.actuate.health;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@@ -37,7 +36,7 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Tests for {@link SimpleDataSourceHealthIndicator}.
|
||||
*
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class SimpleDataSourceHealthIndicatorTests {
|
||||
@@ -55,31 +54,31 @@ public class SimpleDataSourceHealthIndicatorTests {
|
||||
@Test
|
||||
public void database() {
|
||||
this.indicator.setDataSource(this.dataSource);
|
||||
Map<String, Object> health = this.indicator.health();
|
||||
assertNotNull(health.get("database"));
|
||||
assertNotNull(health.get("hello"));
|
||||
Health health = this.indicator.health();
|
||||
assertNotNull(health.getDetails().get("database"));
|
||||
assertNotNull(health.getDetails().get("hello"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customQuery() {
|
||||
this.indicator.setDataSource(this.dataSource);
|
||||
new JdbcTemplate(this.dataSource)
|
||||
.execute("CREATE TABLE FOO (id INTEGER IDENTITY PRIMARY KEY)");
|
||||
.execute("CREATE TABLE FOO (id INTEGER IDENTITY PRIMARY KEY)");
|
||||
this.indicator.setQuery("SELECT COUNT(*) from FOO");
|
||||
Map<String, Object> health = this.indicator.health();
|
||||
Health health = this.indicator.health();
|
||||
System.err.println(health);
|
||||
assertNotNull(health.get("database"));
|
||||
assertEquals("ok", health.get("status"));
|
||||
assertNotNull(health.get("hello"));
|
||||
assertNotNull(health.getDetails().get("database"));
|
||||
assertEquals(Status.UP, health.getStatus());
|
||||
assertNotNull(health.getDetails().get("hello"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void error() {
|
||||
this.indicator.setDataSource(this.dataSource);
|
||||
this.indicator.setQuery("SELECT COUNT(*) from BAR");
|
||||
Map<String, Object> health = this.indicator.health();
|
||||
assertNotNull(health.get("database"));
|
||||
assertEquals("error", health.get("status"));
|
||||
Health health = this.indicator.health();
|
||||
assertNotNull(health.getDetails().get("database"));
|
||||
assertEquals(Status.DOWN, health.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -90,8 +89,8 @@ public class SimpleDataSourceHealthIndicatorTests {
|
||||
this.dataSource.getConnection().getMetaData());
|
||||
when(dataSource.getConnection()).thenReturn(connection);
|
||||
this.indicator.setDataSource(dataSource);
|
||||
Map<String, Object> health = this.indicator.health();
|
||||
assertNotNull(health.get("database"));
|
||||
Health health = this.indicator.health();
|
||||
assertNotNull(health.getDetails().get("database"));
|
||||
verify(connection, times(2)).close();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,11 @@ package org.springframework.boot.actuate.health;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests for {@link VanillaHealthIndicator}.
|
||||
*
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class VanillaHealthIndicatorTests {
|
||||
@@ -31,7 +30,7 @@ public class VanillaHealthIndicatorTests {
|
||||
@Test
|
||||
public void ok() throws Exception {
|
||||
VanillaHealthIndicator healthIndicator = new VanillaHealthIndicator();
|
||||
assertThat(healthIndicator.health(), equalTo("ok"));
|
||||
assertEquals(Status.UP, healthIndicator.health().getStatus());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public class SampleActuatorUiApplicationPortTests {
|
||||
ResponseEntity<String> entity = new TestRestTemplate().getForEntity(
|
||||
"http://localhost:" + this.managementPort + "/health", String.class);
|
||||
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||
assertEquals("{\"status\":\"ok\"}", entity.getBody());
|
||||
assertEquals("{\"status\":\"UP\"}", entity.getBody());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -68,6 +68,6 @@ public class EndpointsPropertiesSampleActuatorApplicationTests {
|
||||
"http://localhost:" + this.port + "/admin/health", String.class);
|
||||
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||
assertTrue("Wrong body: " + entity.getBody(),
|
||||
entity.getBody().contains("\"status\":\"ok\""));
|
||||
entity.getBody().contains("\"status\":\"UP\""));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ public class ManagementAddressActuatorApplicationTests {
|
||||
String.class);
|
||||
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||
assertTrue("Wrong body: " + entity.getBody(),
|
||||
entity.getBody().contains("\"status\":\"ok\""));
|
||||
entity.getBody().contains("\"status\":\"UP\""));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ public class ManagementPortSampleActuatorApplicationTests {
|
||||
"http://localhost:" + this.managementPort + "/health", String.class);
|
||||
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||
assertTrue("Wrong body: " + entity.getBody(),
|
||||
entity.getBody().contains("\"status\":\"ok\""));
|
||||
entity.getBody().contains("\"status\":\"UP\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -131,7 +131,7 @@ public class SampleActuatorApplicationTests {
|
||||
"http://localhost:" + this.port + "/health", String.class);
|
||||
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||
assertTrue("Wrong body: " + entity.getBody(),
|
||||
entity.getBody().contains("\"status\":\"ok\""));
|
||||
entity.getBody().contains("\"status\":\"UP\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user