mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Merge pull request #819 from cdupuis/health-indicator
Rework HealthIndicator support
This commit is contained in:
commit
dfd6f91aef
@ -76,6 +76,11 @@
|
||||
<artifactId>spring-data-redis</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-mongodb</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
|
@ -20,8 +20,6 @@ import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.actuate.endpoint.AutoConfigurationReportEndpoint;
|
||||
@ -38,10 +36,6 @@ 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.CompositeHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.SimpleHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.VanillaHealthIndicator;
|
||||
import org.springframework.boot.actuate.metrics.reader.MetricReader;
|
||||
import org.springframework.boot.actuate.metrics.repository.InMemoryMetricRepository;
|
||||
import org.springframework.boot.actuate.trace.InMemoryTraceRepository;
|
||||
@ -64,20 +58,15 @@ import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for common management
|
||||
* {@link Endpoint}s.
|
||||
*
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @author Greg Turnquist
|
||||
* @author Chiristian Dupuis
|
||||
*/
|
||||
@Configuration
|
||||
public class EndpointAutoConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private HealthIndicator<? extends Object> healthIndicator;
|
||||
|
||||
@Autowired(required = false)
|
||||
private Map<String, DataSource> dataSources;
|
||||
|
||||
@Autowired
|
||||
private InfoPropertiesConfiguration properties;
|
||||
|
||||
@ -98,28 +87,8 @@ public class EndpointAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public HealthEndpoint<?> healthEndpoint() {
|
||||
if (this.healthIndicator == null) {
|
||||
this.healthIndicator = createHealthIndicator();
|
||||
}
|
||||
return new HealthEndpoint<Object>(this.healthIndicator);
|
||||
}
|
||||
|
||||
private HealthIndicator<? extends Object> createHealthIndicator() {
|
||||
if (this.dataSources == null || this.dataSources.isEmpty()) {
|
||||
return new VanillaHealthIndicator();
|
||||
}
|
||||
|
||||
if (this.dataSources.size() == 1) {
|
||||
return new SimpleHealthIndicator(this.dataSources.values().iterator().next());
|
||||
}
|
||||
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator();
|
||||
for (Map.Entry<String, DataSource> entry : this.dataSources.entrySet()) {
|
||||
composite.addHealthIndicator(entry.getKey(),
|
||||
new SimpleHealthIndicator(entry.getValue()));
|
||||
}
|
||||
return composite;
|
||||
public HealthEndpoint healthEndpoint() {
|
||||
return new HealthEndpoint();
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 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.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.health.CompositeHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.MongoHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.RedisHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.SimpleDataSourceHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.VanillaHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.jdbc.CommonsDataSourceConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.HikariDataSourceConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.TomcatDataSourceConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoDataAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
|
||||
/**
|
||||
* @author Christian Dupuis
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureAfter({ DataSourceAutoConfiguration.class,
|
||||
EmbeddedDataSourceConfiguration.class, CommonsDataSourceConfiguration.class,
|
||||
HikariDataSourceConfiguration.class, TomcatDataSourceConfiguration.class,
|
||||
MongoAutoConfiguration.class, MongoDataAutoConfiguration.class,
|
||||
RedisAutoConfiguration.class })
|
||||
public class HealthIndicatorAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(HealthIndicator.class)
|
||||
public HealthIndicator<?> statusHealthIndicator() {
|
||||
return new VanillaHealthIndicator();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(DataSource.class)
|
||||
public static class DataSourcesHealthIndicatorConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private Map<String, DataSource> dataSources;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "dbHealthIndicator")
|
||||
public HealthIndicator<? extends Object> dbHealthIndicator() {
|
||||
if (this.dataSources.size() == 1) {
|
||||
return new SimpleDataSourceHealthIndicator(this.dataSources.values().iterator()
|
||||
.next());
|
||||
}
|
||||
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator();
|
||||
for (Map.Entry<String, DataSource> entry : this.dataSources.entrySet()) {
|
||||
composite.addHealthIndicator(entry.getKey(), new SimpleDataSourceHealthIndicator(
|
||||
entry.getValue()));
|
||||
}
|
||||
return composite;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(MongoTemplate.class)
|
||||
public static class MongoHealthIndicatorConfiguration {
|
||||
|
||||
@Autowired
|
||||
private Map<String, MongoTemplate> mongoTemplates;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "mongoHealthIndicator")
|
||||
public HealthIndicator<?> mongoHealthIndicator() {
|
||||
if (this.mongoTemplates.size() == 1) {
|
||||
return new MongoHealthIndicator(this.mongoTemplates.values().iterator()
|
||||
.next());
|
||||
}
|
||||
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator();
|
||||
for (Map.Entry<String, MongoTemplate> entry : this.mongoTemplates.entrySet()) {
|
||||
composite.addHealthIndicator(entry.getKey(), new MongoHealthIndicator(
|
||||
entry.getValue()));
|
||||
}
|
||||
return composite;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(RedisConnectionFactory.class)
|
||||
public static class RedisHealthIndicatorConfiguration {
|
||||
|
||||
@Autowired
|
||||
private Map<String, RedisConnectionFactory> redisConnectionFactories;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "redisHealthIndicator")
|
||||
public HealthIndicator<?> redisHealthIndicator() {
|
||||
if (this.redisConnectionFactories.size() == 1) {
|
||||
return new RedisHealthIndicator(this.redisConnectionFactories.values()
|
||||
.iterator().next());
|
||||
}
|
||||
|
||||
CompositeHealthIndicator composite = new CompositeHealthIndicator();
|
||||
for (Map.Entry<String, RedisConnectionFactory> entry : this.redisConnectionFactories
|
||||
.entrySet()) {
|
||||
composite.addHealthIndicator(entry.getKey(), new RedisHealthIndicator(
|
||||
entry.getValue()));
|
||||
}
|
||||
return composite;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -16,34 +16,53 @@
|
||||
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Endpoint} to expose application health.
|
||||
*
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "endpoints.health", ignoreUnknownFields = false)
|
||||
public class HealthEndpoint<T> extends AbstractEndpoint<T> {
|
||||
public class HealthEndpoint extends AbstractEndpoint<Map<String, Object>> {
|
||||
|
||||
private final HealthIndicator<? extends T> indicator;
|
||||
@Autowired(required = false)
|
||||
private Map<String, HealthIndicator<? extends Object>> healthIndicators;
|
||||
|
||||
/**
|
||||
* Create a new {@link HealthIndicator} instance.
|
||||
*
|
||||
* @param indicator the health indicator
|
||||
*/
|
||||
public HealthEndpoint(HealthIndicator<? extends T> indicator) {
|
||||
public HealthEndpoint() {
|
||||
super("health", false, true);
|
||||
Assert.notNull(indicator, "Indicator must not be null");
|
||||
this.indicator = indicator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke all {@link HealthIndicator} delegates and collect their health information.
|
||||
*/
|
||||
@Override
|
||||
public T invoke() {
|
||||
return this.indicator.health();
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns the bean name into a key that can be used in the map of health information.
|
||||
*/
|
||||
private String getKey(String name) {
|
||||
int x = name.toLowerCase().indexOf("healthindicator");
|
||||
if (x > 0) {
|
||||
return name.substring(0, x);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 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.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
|
||||
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>> {
|
||||
|
||||
private final MongoTemplate mongoTemplate;
|
||||
|
||||
public MongoHealthIndicator(MongoTemplate mongoTemplate) {
|
||||
this.mongoTemplate = mongoTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> health() {
|
||||
Map<String, Object> health = new HashMap<String, Object>();
|
||||
try {
|
||||
CommandResult result = this.mongoTemplate
|
||||
.executeCommand("{ serverStatus: 1 }");
|
||||
health.put("status", "ok");
|
||||
health.put("version", result.getString("version"));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
health.put("status", "error");
|
||||
health.put("error", ex.getClass().getName() + ": " + ex.getMessage());
|
||||
}
|
||||
return health;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 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.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisConnectionUtils;
|
||||
|
||||
/**
|
||||
* 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>> {
|
||||
|
||||
private final RedisConnectionFactory redisConnectionFactory;
|
||||
|
||||
public RedisHealthIndicator(RedisConnectionFactory connectionFactory) {
|
||||
this.redisConnectionFactory = connectionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> health() {
|
||||
Map<String, Object> health = new HashMap<String, Object>();
|
||||
|
||||
RedisConnection connection = null;
|
||||
try {
|
||||
connection = RedisConnectionUtils.getConnection(this.redisConnectionFactory);
|
||||
Properties info = connection.info();
|
||||
health.put("status", "ok");
|
||||
health.put("version", info.getProperty("redis_version"));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
health.put("status", "error");
|
||||
health.put("error", ex.getClass().getName() + ": " + ex.getMessage());
|
||||
}
|
||||
finally {
|
||||
RedisConnectionUtils.releaseConnection(connection,
|
||||
this.redisConnectionFactory);
|
||||
}
|
||||
return health;
|
||||
}
|
||||
}
|
@ -35,7 +35,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class SimpleHealthIndicator implements HealthIndicator<Map<String, Object>> {
|
||||
public class SimpleDataSourceHealthIndicator implements HealthIndicator<Map<String, Object>> {
|
||||
|
||||
private DataSource dataSource;
|
||||
|
||||
@ -55,16 +55,16 @@ public class SimpleHealthIndicator implements HealthIndicator<Map<String, Object
|
||||
private String query = null;
|
||||
|
||||
/**
|
||||
* Create a new {@link SimpleHealthIndicator} instance.
|
||||
* Create a new {@link SimpleDataSourceHealthIndicator} instance.
|
||||
*/
|
||||
public SimpleHealthIndicator() {
|
||||
public SimpleDataSourceHealthIndicator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link SimpleHealthIndicator} using the specified datasource.
|
||||
* Create a new {@link SimpleDataSourceHealthIndicator} using the specified datasource.
|
||||
* @param dataSource the data source
|
||||
*/
|
||||
public SimpleHealthIndicator(DataSource dataSource) {
|
||||
public SimpleDataSourceHealthIndicator(DataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
@ -4,6 +4,7 @@ org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.JolokiaAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration,\
|
||||
|
@ -43,7 +43,7 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for {@link EndpointAutoConfiguration}.
|
||||
*
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @author Greg Turnquist
|
||||
@ -80,18 +80,33 @@ public class EndpointAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void healthEndpoint() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
this.context.register(EndpointAutoConfiguration.class,
|
||||
EmbeddedDataSourceConfiguration.class);
|
||||
this.context.register(EmbeddedDataSourceConfiguration.class,
|
||||
EndpointAutoConfiguration.class, HealthIndicatorAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
HealthEndpoint<?> bean = this.context.getBean(HealthEndpoint.class);
|
||||
HealthEndpoint bean = this.context.getBean(HealthEndpoint.class);
|
||||
assertNotNull(bean);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> result = (Map<String, Object>) bean.invoke();
|
||||
Map<String, Object> 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"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthEndpointWithDefaultHealthIndicator() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
this.context.register(EndpointAutoConfiguration.class,
|
||||
HealthIndicatorAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
HealthEndpoint bean = this.context.getBean(HealthEndpoint.class);
|
||||
assertNotNull(bean);
|
||||
Map<String, Object> result = bean.invoke();
|
||||
assertNotNull(result);
|
||||
assertTrue("Wrong result: " + result, result.containsKey("status"));
|
||||
assertTrue("Wrong result: " + result, result.containsKey("database"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 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.Map;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.MongoHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.RedisHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.SimpleDataSourceHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.VanillaHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoDataAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Tests for {@link HealthIndicatorAutoConfiguration}.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
public class HealthIndicatorAutoConfigurationTests {
|
||||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
this.context.register(EndpointAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
}
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void defaultHealthIndicator() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
this.context.register(HealthIndicatorAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
Map<String, HealthIndicator> beans = this.context
|
||||
.getBeansOfType(HealthIndicator.class);
|
||||
assertEquals(1, beans.size());
|
||||
assertEquals(VanillaHealthIndicator.class, beans.values().iterator().next()
|
||||
.getClass());
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void redisHealthIndicator() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
this.context.register(RedisAutoConfiguration.class,
|
||||
HealthIndicatorAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
Map<String, HealthIndicator> beans = this.context
|
||||
.getBeansOfType(HealthIndicator.class);
|
||||
assertEquals(1, beans.size());
|
||||
assertEquals(RedisHealthIndicator.class, beans.values().iterator().next()
|
||||
.getClass());
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void mongoHealthIndicator() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
this.context.register(MongoAutoConfiguration.class,
|
||||
MongoDataAutoConfiguration.class, HealthIndicatorAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
Map<String, HealthIndicator> beans = this.context
|
||||
.getBeansOfType(HealthIndicator.class);
|
||||
assertEquals(1, beans.size());
|
||||
assertEquals(MongoHealthIndicator.class, beans.values().iterator().next()
|
||||
.getClass());
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void combinedHealthIndicator() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
this.context.register(MongoAutoConfiguration.class, RedisAutoConfiguration.class,
|
||||
MongoDataAutoConfiguration.class, HealthIndicatorAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
Map<String, HealthIndicator> beans = this.context
|
||||
.getBeansOfType(HealthIndicator.class);
|
||||
assertEquals(2, beans.size());
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Test
|
||||
public void dataSourceHealthIndicator() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
this.context.register(EmbeddedDataSourceConfiguration.class,
|
||||
HealthIndicatorAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
Map<String, HealthIndicator> beans = this.context
|
||||
.getBeansOfType(HealthIndicator.class);
|
||||
assertEquals(1, beans.size());
|
||||
assertEquals(SimpleDataSourceHealthIndicator.class, beans.values().iterator().next()
|
||||
.getClass());
|
||||
}
|
||||
}
|
@ -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.
|
||||
@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
@ -27,10 +30,10 @@ import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link HealthEndpoint}.
|
||||
*
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class HealthEndpointTests extends AbstractEndpointTests<HealthEndpoint<String>> {
|
||||
public class HealthEndpointTests extends AbstractEndpointTests<HealthEndpoint> {
|
||||
|
||||
public HealthEndpointTests() {
|
||||
super(Config.class, HealthEndpoint.class, "health", false, "endpoints.health");
|
||||
@ -38,7 +41,9 @@ public class HealthEndpointTests extends AbstractEndpointTests<HealthEndpoint<St
|
||||
|
||||
@Test
|
||||
public void invoke() throws Exception {
|
||||
assertThat(getEndpointBean().invoke(), equalTo("fine"));
|
||||
Map<String, Object> result = new HashMap<String, Object>();
|
||||
result.put("status", "fine");
|
||||
assertThat(getEndpointBean().invoke(), equalTo(result));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ -46,14 +51,18 @@ public class HealthEndpointTests extends AbstractEndpointTests<HealthEndpoint<St
|
||||
public static class Config {
|
||||
|
||||
@Bean
|
||||
public HealthEndpoint<String> endpoint() {
|
||||
return new HealthEndpoint<String>(new HealthIndicator<String>() {
|
||||
public HealthEndpoint endpoint() {
|
||||
return new HealthEndpoint();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HealthIndicator<String> statusHealthIndicator() {
|
||||
return new HealthIndicator<String>() {
|
||||
@Override
|
||||
public String health() {
|
||||
return "fine";
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 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;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoDataAutoConfiguration;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
|
||||
import com.mongodb.CommandResult;
|
||||
import com.mongodb.MongoException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for {@link MongoHealthIndicator}.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
public class MongoHealthIndicatorTests {
|
||||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void indicatorExists() {
|
||||
this.context = new AnnotationConfigApplicationContext(
|
||||
PropertyPlaceholderAutoConfiguration.class, MongoAutoConfiguration.class,
|
||||
MongoDataAutoConfiguration.class, EndpointAutoConfiguration.class,
|
||||
HealthIndicatorAutoConfiguration.class);
|
||||
assertEquals(1, this.context.getBeanNamesForType(MongoTemplate.class).length);
|
||||
MongoHealthIndicator healthIndicator = this.context
|
||||
.getBean(MongoHealthIndicator.class);
|
||||
assertNotNull(healthIndicator);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mongoIsUp() throws Exception {
|
||||
CommandResult commandResult = Mockito.mock(CommandResult.class);
|
||||
Mockito.when(commandResult.getString("version")).thenReturn("2.6.4");
|
||||
MongoTemplate mongoTemplate = Mockito.mock(MongoTemplate.class);
|
||||
Mockito.when(mongoTemplate.executeCommand("{ serverStatus: 1 }")).thenReturn(
|
||||
commandResult);
|
||||
MongoHealthIndicator healthIndicator = new MongoHealthIndicator(mongoTemplate);
|
||||
|
||||
Map<String, Object> health = healthIndicator.health();
|
||||
assertEquals("ok", health.get("status"));
|
||||
assertEquals("2.6.4", health.get("version"));
|
||||
|
||||
Mockito.verify(commandResult).getString("version");
|
||||
Mockito.verify(mongoTemplate).executeCommand("{ serverStatus: 1 }");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mongoIsDown() throws Exception {
|
||||
MongoTemplate mongoTemplate = Mockito.mock(MongoTemplate.class);
|
||||
Mockito.when(mongoTemplate.executeCommand("{ serverStatus: 1 }")).thenThrow(
|
||||
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"));
|
||||
|
||||
Mockito.verify(mongoTemplate).executeCommand("{ serverStatus: 1 }");
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 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;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.data.redis.RedisConnectionFailureException;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for {@link RedisHealthIndicator}.
|
||||
*
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
public class RedisHealthIndicatorTests {
|
||||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void indicatorExists() {
|
||||
this.context = new AnnotationConfigApplicationContext(
|
||||
PropertyPlaceholderAutoConfiguration.class, RedisAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class, HealthIndicatorAutoConfiguration.class);
|
||||
assertEquals(1,
|
||||
this.context.getBeanNamesForType(RedisConnectionFactory.class).length);
|
||||
RedisHealthIndicator healthIndicator = this.context
|
||||
.getBean(RedisHealthIndicator.class);
|
||||
assertNotNull(healthIndicator);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void redisIsUp() throws Exception {
|
||||
Properties info = new Properties();
|
||||
info.put("redis_version", "2.8.9");
|
||||
|
||||
RedisConnection redisConnection = Mockito.mock(RedisConnection.class);
|
||||
RedisConnectionFactory redisConnectionFactory = Mockito
|
||||
.mock(RedisConnectionFactory.class);
|
||||
Mockito.when(redisConnectionFactory.getConnection()).thenReturn(redisConnection);
|
||||
Mockito.when(redisConnection.info()).thenReturn(info);
|
||||
RedisHealthIndicator healthIndicator = new RedisHealthIndicator(
|
||||
redisConnectionFactory);
|
||||
|
||||
Map<String, Object> health = healthIndicator.health();
|
||||
assertEquals("ok", health.get("status"));
|
||||
assertEquals("2.8.9", health.get("version"));
|
||||
|
||||
Mockito.verify(redisConnectionFactory).getConnection();
|
||||
Mockito.verify(redisConnection).info();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void redisIsDown() throws Exception {
|
||||
RedisConnection redisConnection = Mockito.mock(RedisConnection.class);
|
||||
RedisConnectionFactory redisConnectionFactory = Mockito
|
||||
.mock(RedisConnectionFactory.class);
|
||||
Mockito.when(redisConnectionFactory.getConnection()).thenReturn(redisConnection);
|
||||
Mockito.when(redisConnection.info()).thenThrow(
|
||||
new RedisConnectionFailureException("Connection failed"));
|
||||
RedisHealthIndicator healthIndicator = new RedisHealthIndicator(
|
||||
redisConnectionFactory);
|
||||
|
||||
Map<String, Object> health = healthIndicator.health();
|
||||
assertEquals("error", health.get("status"));
|
||||
assertTrue(((String) health.get("error")).contains("Connection failed"));
|
||||
|
||||
Mockito.verify(redisConnectionFactory).getConnection();
|
||||
Mockito.verify(redisConnection).info();
|
||||
}
|
||||
}
|
@ -36,13 +36,13 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Tests for {@link SimpleHealthIndicator}.
|
||||
* Tests for {@link SimpleDataSourceHealthIndicator}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class SimpleHealthIndicatorTests {
|
||||
public class SimpleDataSourceHealthIndicatorTests {
|
||||
|
||||
private final SimpleHealthIndicator indicator = new SimpleHealthIndicator();
|
||||
private final SimpleDataSourceHealthIndicator indicator = new SimpleDataSourceHealthIndicator();
|
||||
private DriverManagerDataSource dataSource;
|
||||
|
||||
@Before
|
@ -1,5 +1,5 @@
|
||||
= Spring Boot Reference Guide
|
||||
Phillip Webb; Dave Syer; Josh Long; Stéphane Nicoll; Rob Winch; Andy Wilkinson; Marcel Overdijk;
|
||||
Phillip Webb; Dave Syer; Josh Long; Stéphane Nicoll; Rob Winch; Andy Wilkinson; Marcel Overdijk; Christian Dupuis;
|
||||
:doctype: book
|
||||
:toc:
|
||||
:toclevels: 4
|
||||
|
@ -162,9 +162,13 @@ To provide custom health information you can register a Spring bean that impleme
|
||||
}
|
||||
----
|
||||
|
||||
Spring Boot also provides a
|
||||
{sc-spring-boot-actuator}/health/SimpleHealthIndicator.{sc-ext}[`SimpleHealthIndicator`]
|
||||
implementation that attempts a simple database test.
|
||||
Spring Boot provides a
|
||||
{sc-spring-boot-actuator}/health/SimpleDatabaseHealthIndicator.{sc-ext}[`SimpleDatabaseHealthIndicator`]
|
||||
implementation that attempts a simple database test as well as implementations for
|
||||
Redis and MongoDB.
|
||||
|
||||
Spring Boot adds the `HealthIndicator` instances automatically if beans of type `DataSource`,
|
||||
`MongoTemplate` or `RedisConnectionFactory` are present in the `ApplicationContext`.
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user