Drop status endpoint
Drop the status endpoint and merge functionality back into the health endpoint. The `management.endpoint.health.show-details` property can be used to change if full details, or just the status is displayed. Fixes gh-11113
This commit is contained in:
parent
d99625fa78
commit
31025d9f6c
|
|
@ -66,5 +66,4 @@ include::endpoints/prometheus.adoc[leveloffset=+1]
|
||||||
include::endpoints/scheduledtasks.adoc[leveloffset=+1]
|
include::endpoints/scheduledtasks.adoc[leveloffset=+1]
|
||||||
include::endpoints/sessions.adoc[leveloffset=+1]
|
include::endpoints/sessions.adoc[leveloffset=+1]
|
||||||
include::endpoints/shutdown.adoc[leveloffset=+1]
|
include::endpoints/shutdown.adoc[leveloffset=+1]
|
||||||
include::endpoints/status.adoc[leveloffset=+1]
|
|
||||||
include::endpoints/threaddump.adoc[leveloffset=+1]
|
include::endpoints/threaddump.adoc[leveloffset=+1]
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ public class WebEndpointAutoConfiguration {
|
||||||
public ExposeExcludePropertyEndpointFilter<WebOperation> webIncludeExcludePropertyEndpointFilter() {
|
public ExposeExcludePropertyEndpointFilter<WebOperation> webIncludeExcludePropertyEndpointFilter() {
|
||||||
return new ExposeExcludePropertyEndpointFilter<>(
|
return new ExposeExcludePropertyEndpointFilter<>(
|
||||||
WebAnnotationEndpointDiscoverer.class, this.properties.getExpose(),
|
WebAnnotationEndpointDiscoverer.class, this.properties.getExpose(),
|
||||||
this.properties.getExclude(), "info", "status");
|
this.properties.getExclude(), "info", "health");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,9 @@ import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||||
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
|
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
|
||||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||||
import org.springframework.boot.actuate.health.StatusEndpoint;
|
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
@ -44,6 +44,7 @@ import org.springframework.util.ClassUtils;
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@EnableConfigurationProperties(HealthEndpointProperties.class)
|
||||||
public class HealthEndpointAutoConfiguration {
|
public class HealthEndpointAutoConfiguration {
|
||||||
|
|
||||||
private final HealthIndicator healthIndicator;
|
private final HealthIndicator healthIndicator;
|
||||||
|
|
@ -69,15 +70,8 @@ public class HealthEndpointAutoConfiguration {
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
@ConditionalOnEnabledEndpoint
|
@ConditionalOnEnabledEndpoint
|
||||||
public HealthEndpoint healthEndpoint() {
|
public HealthEndpoint healthEndpoint(HealthEndpointProperties properties) {
|
||||||
return new HealthEndpoint(this.healthIndicator);
|
return new HealthEndpoint(this.healthIndicator, properties.isShowDetails());
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean
|
|
||||||
@ConditionalOnEnabledEndpoint
|
|
||||||
public StatusEndpoint statusEndpoint() {
|
|
||||||
return new StatusEndpoint(this.healthIndicator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ReactiveHealthIndicators {
|
private static class ReactiveHealthIndicators {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2017 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.health;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration properties for {@link HealthEndpoint}.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
@ConfigurationProperties("management.endpoint.health")
|
||||||
|
public class HealthEndpointProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to show full health details instead of just the status.
|
||||||
|
*/
|
||||||
|
private boolean showDetails;
|
||||||
|
|
||||||
|
public boolean isShowDetails() {
|
||||||
|
return this.showDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShowDetails(boolean showDetails) {
|
||||||
|
this.showDetails = showDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -31,9 +31,6 @@ import org.springframework.boot.actuate.health.HealthStatusHttpMapper;
|
||||||
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
|
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
|
||||||
import org.springframework.boot.actuate.health.ReactiveHealthEndpointWebExtension;
|
import org.springframework.boot.actuate.health.ReactiveHealthEndpointWebExtension;
|
||||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||||
import org.springframework.boot.actuate.health.ReactiveStatusEndpointWebExtension;
|
|
||||||
import org.springframework.boot.actuate.health.StatusEndpoint;
|
|
||||||
import org.springframework.boot.actuate.health.StatusEndpointWebExtension;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
|
|
@ -85,19 +82,10 @@ public class HealthWebEndpointManagementContextConfiguration {
|
||||||
@ConditionalOnEnabledEndpoint
|
@ConditionalOnEnabledEndpoint
|
||||||
@ConditionalOnBean(HealthEndpoint.class)
|
@ConditionalOnBean(HealthEndpoint.class)
|
||||||
public ReactiveHealthEndpointWebExtension reactiveHealthEndpointWebExtension(
|
public ReactiveHealthEndpointWebExtension reactiveHealthEndpointWebExtension(
|
||||||
HealthStatusHttpMapper healthStatusHttpMapper) {
|
HealthStatusHttpMapper healthStatusHttpMapper,
|
||||||
|
HealthEndpointProperties properties) {
|
||||||
return new ReactiveHealthEndpointWebExtension(this.reactiveHealthIndicator,
|
return new ReactiveHealthEndpointWebExtension(this.reactiveHealthIndicator,
|
||||||
healthStatusHttpMapper);
|
healthStatusHttpMapper, properties.isShowDetails());
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean
|
|
||||||
@ConditionalOnEnabledEndpoint
|
|
||||||
@ConditionalOnBean(StatusEndpoint.class)
|
|
||||||
public ReactiveStatusEndpointWebExtension reactiveStatusEndpointWebExtension(
|
|
||||||
HealthStatusHttpMapper healthStatusHttpMapper) {
|
|
||||||
return new ReactiveStatusEndpointWebExtension(this.reactiveHealthIndicator,
|
|
||||||
healthStatusHttpMapper);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -115,15 +103,6 @@ public class HealthWebEndpointManagementContextConfiguration {
|
||||||
return new HealthEndpointWebExtension(delegate, healthStatusHttpMapper);
|
return new HealthEndpointWebExtension(delegate, healthStatusHttpMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean
|
|
||||||
@ConditionalOnEnabledEndpoint
|
|
||||||
@ConditionalOnBean(StatusEndpoint.class)
|
|
||||||
public StatusEndpointWebExtension statusEndpointWebExtension(
|
|
||||||
StatusEndpoint delegate, HealthStatusHttpMapper healthStatusHttpMapper) {
|
|
||||||
return new StatusEndpointWebExtension(delegate, healthStatusHttpMapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,8 @@ public class HealthEndpointDocumentationTests extends AbstractEndpointDocumentat
|
||||||
fieldWithPath("status").description(
|
fieldWithPath("status").description(
|
||||||
"Overall status of the application."),
|
"Overall status of the application."),
|
||||||
fieldWithPath("details")
|
fieldWithPath("details")
|
||||||
.description("Details of the health of the application."),
|
.description("Details of the health of the application "
|
||||||
|
+ "(only included when `management.endpoint.health.show-details` is `true`)."),
|
||||||
fieldWithPath("details.*.status").description(
|
fieldWithPath("details.*.status").description(
|
||||||
"Status of a specific part of the application."),
|
"Status of a specific part of the application."),
|
||||||
subsectionWithPath("details.*.details").description(
|
subsectionWithPath("details.*.details").description(
|
||||||
|
|
@ -73,7 +74,7 @@ public class HealthEndpointDocumentationTests extends AbstractEndpointDocumentat
|
||||||
@Bean
|
@Bean
|
||||||
public HealthEndpoint endpoint(Map<String, HealthIndicator> healthIndicators) {
|
public HealthEndpoint endpoint(Map<String, HealthIndicator> healthIndicators) {
|
||||||
return new HealthEndpoint(new CompositeHealthIndicator(
|
return new HealthEndpoint(new CompositeHealthIndicator(
|
||||||
new OrderedHealthAggregator(), healthIndicators));
|
new OrderedHealthAggregator(), healthIndicators), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2012-2017 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.endpoint.web.documentation;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import org.springframework.boot.actuate.health.CompositeHealthIndicator;
|
|
||||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
|
||||||
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
|
|
||||||
import org.springframework.boot.actuate.health.StatusEndpoint;
|
|
||||||
import org.springframework.boot.actuate.jdbc.DataSourceHealthIndicator;
|
|
||||||
import org.springframework.boot.actuate.system.DiskSpaceHealthIndicator;
|
|
||||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
|
||||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.Import;
|
|
||||||
|
|
||||||
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
|
||||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
|
||||||
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for generating documentation describing the {@link StatusEndpoint}.
|
|
||||||
*
|
|
||||||
* @author Andy Wilkinson
|
|
||||||
*/
|
|
||||||
public class StatusEndpointDocumentationTests extends AbstractEndpointDocumentationTests {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void health() throws Exception {
|
|
||||||
this.mockMvc.perform(get("/application/status")).andExpect(status().isOk())
|
|
||||||
.andDo(document("status", responseFields(fieldWithPath("status")
|
|
||||||
.description("Overall status of the application."))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@Import(BaseDocumentationConfiguration.class)
|
|
||||||
@ImportAutoConfiguration(DataSourceAutoConfiguration.class)
|
|
||||||
static class TestConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public StatusEndpoint endpoint(Map<String, HealthIndicator> healthIndicators) {
|
|
||||||
return new StatusEndpoint(new CompositeHealthIndicator(
|
|
||||||
new OrderedHealthAggregator(), healthIndicators));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public DiskSpaceHealthIndicator diskSpaceHealthIndicator() {
|
|
||||||
return new DiskSpaceHealthIndicator(new File("."), 1024 * 1024 * 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public DataSourceHealthIndicator dataSourceHealthIndicator(
|
|
||||||
DataSource dataSource) {
|
|
||||||
return new DataSourceHealthIndicator(dataSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -24,7 +24,6 @@ import org.springframework.boot.actuate.health.HealthEndpoint;
|
||||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||||
import org.springframework.boot.actuate.health.Status;
|
import org.springframework.boot.actuate.health.Status;
|
||||||
import org.springframework.boot.actuate.health.StatusEndpoint;
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
@ -48,9 +47,25 @@ public class HealthEndpointAutoConfigurationTests {
|
||||||
.withConfiguration(
|
.withConfiguration(
|
||||||
AutoConfigurations.of(HealthEndpointAutoConfiguration.class));
|
AutoConfigurations.of(HealthEndpointAutoConfiguration.class));
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void healthEndpointShowDetailsDefault() {
|
||||||
|
this.contextRunner
|
||||||
|
.withUserConfiguration(ReactiveHealthIndicatorConfiguration.class)
|
||||||
|
.run((context) -> {
|
||||||
|
ReactiveHealthIndicator indicator = context.getBean(
|
||||||
|
"reactiveHealthIndicator", ReactiveHealthIndicator.class);
|
||||||
|
verify(indicator, times(0)).health();
|
||||||
|
Health health = context.getBean(HealthEndpoint.class).health();
|
||||||
|
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||||
|
assertThat(health.getDetails()).isEmpty();
|
||||||
|
verify(indicator, times(1)).health();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void healthEndpointAdaptReactiveHealthIndicator() {
|
public void healthEndpointAdaptReactiveHealthIndicator() {
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
|
.withPropertyValues("management.endpoint.health.show-details=true")
|
||||||
.withUserConfiguration(ReactiveHealthIndicatorConfiguration.class)
|
.withUserConfiguration(ReactiveHealthIndicatorConfiguration.class)
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
ReactiveHealthIndicator indicator = context.getBean(
|
ReactiveHealthIndicator indicator = context.getBean(
|
||||||
|
|
@ -65,8 +80,11 @@ public class HealthEndpointAutoConfigurationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void healthEndpointMergeRegularAndReactive() {
|
public void healthEndpointMergeRegularAndReactive() {
|
||||||
this.contextRunner.withUserConfiguration(HealthIndicatorConfiguration.class,
|
this.contextRunner
|
||||||
ReactiveHealthIndicatorConfiguration.class).run((context) -> {
|
.withPropertyValues("management.endpoint.health.show-details=true")
|
||||||
|
.withUserConfiguration(HealthIndicatorConfiguration.class,
|
||||||
|
ReactiveHealthIndicatorConfiguration.class)
|
||||||
|
.run((context) -> {
|
||||||
HealthIndicator indicator = context.getBean("simpleHealthIndicator",
|
HealthIndicator indicator = context.getBean("simpleHealthIndicator",
|
||||||
HealthIndicator.class);
|
HealthIndicator.class);
|
||||||
ReactiveHealthIndicator reactiveHealthIndicator = context.getBean(
|
ReactiveHealthIndicator reactiveHealthIndicator = context.getBean(
|
||||||
|
|
@ -82,22 +100,6 @@ public class HealthEndpointAutoConfigurationTests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void runShouldHaveStatusEndpointBeanEvenIfDefaultIsDisabled() {
|
|
||||||
// FIXME
|
|
||||||
this.contextRunner.withPropertyValues("management.endpoint.default.enabled:false")
|
|
||||||
.run((context) -> assertThat(context)
|
|
||||||
.hasSingleBean(StatusEndpoint.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void runWhenEnabledPropertyIsFalseShouldNotHaveStatusEndpointBean()
|
|
||||||
throws Exception {
|
|
||||||
this.contextRunner.withPropertyValues("management.endpoint.status.enabled:false")
|
|
||||||
.run((context) -> assertThat(context)
|
|
||||||
.doesNotHaveBean(StatusEndpoint.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
static class HealthIndicatorConfiguration {
|
static class HealthIndicatorConfiguration {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.health.HealthStatusHttpMapper;
|
import org.springframework.boot.actuate.health.HealthStatusHttpMapper;
|
||||||
import org.springframework.boot.actuate.health.ReactiveHealthEndpointWebExtension;
|
import org.springframework.boot.actuate.health.ReactiveHealthEndpointWebExtension;
|
||||||
import org.springframework.boot.actuate.health.ReactiveStatusEndpointWebExtension;
|
|
||||||
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
|
@ -46,7 +45,6 @@ public class HealthWebEndpointReactiveManagementContextConfigurationTests {
|
||||||
@Test
|
@Test
|
||||||
public void runShouldCreateExtensionBeans() throws Exception {
|
public void runShouldCreateExtensionBeans() throws Exception {
|
||||||
this.contextRunner.run((context) -> assertThat(context)
|
this.contextRunner.run((context) -> assertThat(context)
|
||||||
.hasSingleBean(ReactiveStatusEndpointWebExtension.class)
|
|
||||||
.hasSingleBean(ReactiveHealthEndpointWebExtension.class));
|
.hasSingleBean(ReactiveHealthEndpointWebExtension.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,19 +56,10 @@ public class HealthWebEndpointReactiveManagementContextConfigurationTests {
|
||||||
.doesNotHaveBean(ReactiveHealthEndpointWebExtension.class));
|
.doesNotHaveBean(ReactiveHealthEndpointWebExtension.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void runWhenStatusEndpointIsDisabledShouldNotCreateExtensionBeans()
|
|
||||||
throws Exception {
|
|
||||||
this.contextRunner.withPropertyValues("management.endpoint.status.enabled:false")
|
|
||||||
.run((context) -> assertThat(context)
|
|
||||||
.doesNotHaveBean(ReactiveStatusEndpointWebExtension.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void runWithCustomHealthMappingShouldMapStatusCode() throws Exception {
|
public void runWithCustomHealthMappingShouldMapStatusCode() throws Exception {
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
.withPropertyValues(
|
.withPropertyValues("management.health.status.http-mapping.CUSTOM=500")
|
||||||
"management.health.status.http-mapping.CUSTOM=500")
|
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
Object extension = context
|
Object extension = context
|
||||||
.getBean(ReactiveHealthEndpointWebExtension.class);
|
.getBean(ReactiveHealthEndpointWebExtension.class);
|
||||||
|
|
@ -83,21 +72,4 @@ public class HealthWebEndpointReactiveManagementContextConfigurationTests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void runWithCustomStatusMappingShouldMapStatusCode() throws Exception {
|
|
||||||
this.contextRunner
|
|
||||||
.withPropertyValues(
|
|
||||||
"management.health.status.http-mapping.CUSTOM=500")
|
|
||||||
.run((context) -> {
|
|
||||||
Object extension = context
|
|
||||||
.getBean(ReactiveStatusEndpointWebExtension.class);
|
|
||||||
HealthStatusHttpMapper mapper = (HealthStatusHttpMapper) ReflectionTestUtils
|
|
||||||
.getField(extension, "statusHttpMapper");
|
|
||||||
Map<String, Integer> statusMappings = mapper.getStatusMapping();
|
|
||||||
assertThat(statusMappings).containsEntry("DOWN", 503);
|
|
||||||
assertThat(statusMappings).containsEntry("OUT_OF_SERVICE", 503);
|
|
||||||
assertThat(statusMappings).containsEntry("CUSTOM", 500);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.health.HealthEndpointWebExtension;
|
import org.springframework.boot.actuate.health.HealthEndpointWebExtension;
|
||||||
import org.springframework.boot.actuate.health.HealthStatusHttpMapper;
|
import org.springframework.boot.actuate.health.HealthStatusHttpMapper;
|
||||||
import org.springframework.boot.actuate.health.StatusEndpointWebExtension;
|
|
||||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
|
@ -46,7 +45,6 @@ public class HealthWebEndpointServletManagementContextConfigurationTests {
|
||||||
@Test
|
@Test
|
||||||
public void runShouldCreateExtensionBeans() throws Exception {
|
public void runShouldCreateExtensionBeans() throws Exception {
|
||||||
this.contextRunner.run((context) -> assertThat(context)
|
this.contextRunner.run((context) -> assertThat(context)
|
||||||
.hasSingleBean(StatusEndpointWebExtension.class)
|
|
||||||
.hasSingleBean(HealthEndpointWebExtension.class));
|
.hasSingleBean(HealthEndpointWebExtension.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,14 +56,6 @@ public class HealthWebEndpointServletManagementContextConfigurationTests {
|
||||||
.doesNotHaveBean(HealthEndpointWebExtension.class));
|
.doesNotHaveBean(HealthEndpointWebExtension.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void runWhenStatusEndpointIsDisabledShouldNotCreateExtensionBeans()
|
|
||||||
throws Exception {
|
|
||||||
this.contextRunner.withPropertyValues("management.endpoint.status.enabled:false")
|
|
||||||
.run((context) -> assertThat(context)
|
|
||||||
.doesNotHaveBean(StatusEndpointWebExtension.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void runWithCustomHealthMappingShouldMapStatusCode() throws Exception {
|
public void runWithCustomHealthMappingShouldMapStatusCode() throws Exception {
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
|
|
@ -81,19 +71,4 @@ public class HealthWebEndpointServletManagementContextConfigurationTests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void runWithCustomStatusMappingShouldMapStatusCode() throws Exception {
|
|
||||||
this.contextRunner
|
|
||||||
.withPropertyValues("management.health.status.http-mapping.CUSTOM=500")
|
|
||||||
.run((context) -> {
|
|
||||||
Object extension = context.getBean(StatusEndpointWebExtension.class);
|
|
||||||
HealthStatusHttpMapper mapper = (HealthStatusHttpMapper) ReflectionTestUtils
|
|
||||||
.getField(extension, "statusHttpMapper");
|
|
||||||
Map<String, Integer> statusMappings = mapper.getStatusMapping();
|
|
||||||
assertThat(statusMappings).containsEntry("DOWN", 503);
|
|
||||||
assertThat(statusMappings).containsEntry("OUT_OF_SERVICE", 503);
|
|
||||||
assertThat(statusMappings).containsEntry("CUSTOM", 500);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ public class JmxEndpointIntegrationTests {
|
||||||
MBeanServer mBeanServer = context.getBean(MBeanServer.class);
|
MBeanServer mBeanServer = context.getBean(MBeanServer.class);
|
||||||
checkEndpointMBeans(mBeanServer,
|
checkEndpointMBeans(mBeanServer,
|
||||||
new String[] { "beans", "conditions", "configprops", "env", "health",
|
new String[] { "beans", "conditions", "configprops", "env", "health",
|
||||||
"info", "mappings", "status", "threaddump", "trace" },
|
"info", "mappings", "threaddump", "trace" },
|
||||||
new String[] { "shutdown" });
|
new String[] { "shutdown" });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,6 @@ import org.junit.Test;
|
||||||
import org.springframework.boot.SpringBootConfiguration;
|
import org.springframework.boot.SpringBootConfiguration;
|
||||||
import org.springframework.boot.actuate.health.HealthEndpointWebExtension;
|
import org.springframework.boot.actuate.health.HealthEndpointWebExtension;
|
||||||
import org.springframework.boot.actuate.health.ReactiveHealthEndpointWebExtension;
|
import org.springframework.boot.actuate.health.ReactiveHealthEndpointWebExtension;
|
||||||
import org.springframework.boot.actuate.health.ReactiveStatusEndpointWebExtension;
|
|
||||||
import org.springframework.boot.actuate.health.StatusEndpointWebExtension;
|
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
|
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration;
|
import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration;
|
||||||
|
|
@ -62,24 +60,12 @@ public class WebEndpointsAutoConfigurationIntegrationTests {
|
||||||
.hasSingleBean(HealthEndpointWebExtension.class));
|
.hasSingleBean(HealthEndpointWebExtension.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void statusEndpointWebExtensionIsAutoConfigured() {
|
|
||||||
servletWebRunner().run((context) -> assertThat(context)
|
|
||||||
.hasSingleBean(StatusEndpointWebExtension.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void healthEndpointReactiveWebExtensionIsAutoConfigured() {
|
public void healthEndpointReactiveWebExtensionIsAutoConfigured() {
|
||||||
reactiveWebRunner().run((context) -> assertThat(context)
|
reactiveWebRunner().run((context) -> assertThat(context)
|
||||||
.hasSingleBean(ReactiveHealthEndpointWebExtension.class));
|
.hasSingleBean(ReactiveHealthEndpointWebExtension.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void statusEndpointReactiveWebExtensionIsAutoConfigured() {
|
|
||||||
reactiveWebRunner().run((context) -> assertThat(context)
|
|
||||||
.hasSingleBean(ReactiveStatusEndpointWebExtension.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
private WebApplicationContextRunner servletWebRunner() {
|
private WebApplicationContextRunner servletWebRunner() {
|
||||||
return new WebApplicationContextRunner()
|
return new WebApplicationContextRunner()
|
||||||
.withConfiguration(
|
.withConfiguration(
|
||||||
|
|
|
||||||
|
|
@ -69,11 +69,10 @@ public class WebMvcEndpointExposureIntegrationTests {
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "conditions")).isFalse();
|
assertThat(isExposed(mvc, HttpMethod.GET, "conditions")).isFalse();
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "configprops")).isFalse();
|
assertThat(isExposed(mvc, HttpMethod.GET, "configprops")).isFalse();
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "env")).isFalse();
|
assertThat(isExposed(mvc, HttpMethod.GET, "env")).isFalse();
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "health")).isFalse();
|
assertThat(isExposed(mvc, HttpMethod.GET, "health")).isTrue();
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isTrue();
|
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isTrue();
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "mappings")).isFalse();
|
assertThat(isExposed(mvc, HttpMethod.GET, "mappings")).isFalse();
|
||||||
assertThat(isExposed(mvc, HttpMethod.POST, "shutdown")).isFalse();
|
assertThat(isExposed(mvc, HttpMethod.POST, "shutdown")).isFalse();
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "status")).isTrue();
|
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "threaddump")).isFalse();
|
assertThat(isExposed(mvc, HttpMethod.GET, "threaddump")).isFalse();
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "trace")).isFalse();
|
assertThat(isExposed(mvc, HttpMethod.GET, "trace")).isFalse();
|
||||||
});
|
});
|
||||||
|
|
@ -93,7 +92,6 @@ public class WebMvcEndpointExposureIntegrationTests {
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isTrue();
|
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isTrue();
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "mappings")).isTrue();
|
assertThat(isExposed(mvc, HttpMethod.GET, "mappings")).isTrue();
|
||||||
assertThat(isExposed(mvc, HttpMethod.POST, "shutdown")).isFalse();
|
assertThat(isExposed(mvc, HttpMethod.POST, "shutdown")).isFalse();
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "status")).isTrue();
|
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "threaddump")).isTrue();
|
assertThat(isExposed(mvc, HttpMethod.GET, "threaddump")).isTrue();
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "trace")).isTrue();
|
assertThat(isExposed(mvc, HttpMethod.GET, "trace")).isTrue();
|
||||||
});
|
});
|
||||||
|
|
@ -113,7 +111,6 @@ public class WebMvcEndpointExposureIntegrationTests {
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isFalse();
|
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isFalse();
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "mappings")).isFalse();
|
assertThat(isExposed(mvc, HttpMethod.GET, "mappings")).isFalse();
|
||||||
assertThat(isExposed(mvc, HttpMethod.POST, "shutdown")).isFalse();
|
assertThat(isExposed(mvc, HttpMethod.POST, "shutdown")).isFalse();
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "status")).isFalse();
|
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "threaddump")).isFalse();
|
assertThat(isExposed(mvc, HttpMethod.GET, "threaddump")).isFalse();
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "trace")).isFalse();
|
assertThat(isExposed(mvc, HttpMethod.GET, "trace")).isFalse();
|
||||||
});
|
});
|
||||||
|
|
@ -134,7 +131,6 @@ public class WebMvcEndpointExposureIntegrationTests {
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isTrue();
|
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isTrue();
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "mappings")).isTrue();
|
assertThat(isExposed(mvc, HttpMethod.GET, "mappings")).isTrue();
|
||||||
assertThat(isExposed(mvc, HttpMethod.POST, "shutdown")).isFalse();
|
assertThat(isExposed(mvc, HttpMethod.POST, "shutdown")).isFalse();
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "status")).isTrue();
|
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "threaddump")).isTrue();
|
assertThat(isExposed(mvc, HttpMethod.GET, "threaddump")).isTrue();
|
||||||
assertThat(isExposed(mvc, HttpMethod.GET, "trace")).isTrue();
|
assertThat(isExposed(mvc, HttpMethod.GET, "trace")).isTrue();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link Endpoint} to expose application health.
|
* {@link Endpoint} to expose application health information.
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
* @author Christian Dupuis
|
* @author Christian Dupuis
|
||||||
|
|
@ -32,17 +32,25 @@ public class HealthEndpoint {
|
||||||
|
|
||||||
private final HealthIndicator healthIndicator;
|
private final HealthIndicator healthIndicator;
|
||||||
|
|
||||||
|
private final boolean showDetails;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link HealthEndpoint} instance.
|
* Create a new {@link HealthEndpoint} instance.
|
||||||
* @param healthIndicator the health indicator
|
* @param healthIndicator the health indicator
|
||||||
|
* @param showDetails if full details should be returned instead of just the status
|
||||||
*/
|
*/
|
||||||
public HealthEndpoint(HealthIndicator healthIndicator) {
|
public HealthEndpoint(HealthIndicator healthIndicator, boolean showDetails) {
|
||||||
this.healthIndicator = healthIndicator;
|
this.healthIndicator = healthIndicator;
|
||||||
|
this.showDetails = showDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReadOperation
|
@ReadOperation
|
||||||
public Health health() {
|
public Health health() {
|
||||||
return this.healthIndicator.health();
|
Health health = this.healthIndicator.health();
|
||||||
|
if (this.showDetails) {
|
||||||
|
return health;
|
||||||
|
}
|
||||||
|
return Health.status(health.getStatus()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,16 +35,22 @@ public class ReactiveHealthEndpointWebExtension {
|
||||||
|
|
||||||
private final HealthStatusHttpMapper statusHttpMapper;
|
private final HealthStatusHttpMapper statusHttpMapper;
|
||||||
|
|
||||||
|
private final boolean showDetails;
|
||||||
|
|
||||||
public ReactiveHealthEndpointWebExtension(ReactiveHealthIndicator delegate,
|
public ReactiveHealthEndpointWebExtension(ReactiveHealthIndicator delegate,
|
||||||
HealthStatusHttpMapper statusHttpMapper) {
|
HealthStatusHttpMapper statusHttpMapper, boolean showDetails) {
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
this.statusHttpMapper = statusHttpMapper;
|
this.statusHttpMapper = statusHttpMapper;
|
||||||
|
this.showDetails = showDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReadOperation
|
@ReadOperation
|
||||||
public Mono<WebEndpointResponse<Health>> health() {
|
public Mono<WebEndpointResponse<Health>> health() {
|
||||||
return this.delegate.health().map((health) -> {
|
return this.delegate.health().map((health) -> {
|
||||||
Integer status = this.statusHttpMapper.mapStatus(health.getStatus());
|
Integer status = this.statusHttpMapper.mapStatus(health.getStatus());
|
||||||
|
if (!this.showDetails) {
|
||||||
|
health = Health.status(health.getStatus()).build();
|
||||||
|
}
|
||||||
return new WebEndpointResponse<>(health, status);
|
return new WebEndpointResponse<>(health, status);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2012-2017 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 reactor.core.publisher.Mono;
|
|
||||||
|
|
||||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
|
||||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
|
||||||
import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reactive {@link EndpointWebExtension} for the {@link StatusEndpoint}.
|
|
||||||
*
|
|
||||||
* @author Stephane Nicoll
|
|
||||||
* @since 2.0.0
|
|
||||||
*/
|
|
||||||
@EndpointWebExtension(endpoint = StatusEndpoint.class)
|
|
||||||
public class ReactiveStatusEndpointWebExtension {
|
|
||||||
|
|
||||||
private final ReactiveHealthIndicator delegate;
|
|
||||||
|
|
||||||
private final HealthStatusHttpMapper statusHttpMapper;
|
|
||||||
|
|
||||||
public ReactiveStatusEndpointWebExtension(ReactiveHealthIndicator delegate,
|
|
||||||
HealthStatusHttpMapper statusHttpMapper) {
|
|
||||||
this.delegate = delegate;
|
|
||||||
this.statusHttpMapper = statusHttpMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ReadOperation
|
|
||||||
public Mono<WebEndpointResponse<Health>> health() {
|
|
||||||
return this.delegate.health().map((health) -> {
|
|
||||||
Integer status = this.statusHttpMapper.mapStatus(health.getStatus());
|
|
||||||
return new WebEndpointResponse<>(Health.status(health.getStatus()).build(),
|
|
||||||
status);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2012-2017 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.boot.actuate.endpoint.annotation.Endpoint;
|
|
||||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link Endpoint} to expose application {@link Status}.
|
|
||||||
*
|
|
||||||
* @author Stephane Nicoll
|
|
||||||
* @since 2.0.0
|
|
||||||
*/
|
|
||||||
@Endpoint(id = "status")
|
|
||||||
public class StatusEndpoint {
|
|
||||||
|
|
||||||
private final HealthIndicator healthIndicator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link StatusEndpoint} instance.
|
|
||||||
* @param healthIndicator the health indicator
|
|
||||||
*/
|
|
||||||
public StatusEndpoint(HealthIndicator healthIndicator) {
|
|
||||||
this.healthIndicator = healthIndicator;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ReadOperation
|
|
||||||
public Health health() {
|
|
||||||
return Health.status(this.healthIndicator.health().getStatus()).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2012-2017 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.boot.actuate.endpoint.annotation.ReadOperation;
|
|
||||||
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
|
|
||||||
import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link EndpointWebExtension} for the {@link StatusEndpoint}.
|
|
||||||
*
|
|
||||||
* @author Stephane Nicoll
|
|
||||||
* @since 2.0.0
|
|
||||||
*/
|
|
||||||
@EndpointWebExtension(endpoint = StatusEndpoint.class)
|
|
||||||
public class StatusEndpointWebExtension {
|
|
||||||
|
|
||||||
private final StatusEndpoint delegate;
|
|
||||||
|
|
||||||
private final HealthStatusHttpMapper statusHttpMapper;
|
|
||||||
|
|
||||||
public StatusEndpointWebExtension(StatusEndpoint delegate,
|
|
||||||
HealthStatusHttpMapper statusHttpMapper) {
|
|
||||||
this.delegate = delegate;
|
|
||||||
this.statusHttpMapper = statusHttpMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ReadOperation
|
|
||||||
public WebEndpointResponse<Health> getHealth() {
|
|
||||||
Health health = this.delegate.health();
|
|
||||||
Integer status = this.statusHttpMapper.mapStatus(health.getStatus());
|
|
||||||
return new WebEndpointResponse<>(health, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -41,7 +41,7 @@ public class HealthEndpointTests {
|
||||||
healthIndicators.put("upAgain", () -> new Health.Builder().status(Status.UP)
|
healthIndicators.put("upAgain", () -> new Health.Builder().status(Status.UP)
|
||||||
.withDetail("second", "2").build());
|
.withDetail("second", "2").build());
|
||||||
HealthEndpoint endpoint = new HealthEndpoint(
|
HealthEndpoint endpoint = new HealthEndpoint(
|
||||||
createHealthIndicator(healthIndicators));
|
createHealthIndicator(healthIndicators), true);
|
||||||
Health health = endpoint.health();
|
Health health = endpoint.health();
|
||||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||||
assertThat(health.getDetails()).containsOnlyKeys("up", "upAgain");
|
assertThat(health.getDetails()).containsOnlyKeys("up", "upAgain");
|
||||||
|
|
@ -51,6 +51,20 @@ public class HealthEndpointTests {
|
||||||
assertThat(upAgainHealth.getDetails()).containsOnly(entry("second", "2"));
|
assertThat(upAgainHealth.getDetails()).containsOnly(entry("second", "2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onlyStatusIsExposed() {
|
||||||
|
Map<String, HealthIndicator> healthIndicators = new HashMap<>();
|
||||||
|
healthIndicators.put("up", () -> new Health.Builder().status(Status.UP)
|
||||||
|
.withDetail("first", "1").build());
|
||||||
|
healthIndicators.put("upAgain", () -> new Health.Builder().status(Status.UP)
|
||||||
|
.withDetail("second", "2").build());
|
||||||
|
HealthEndpoint endpoint = new HealthEndpoint(
|
||||||
|
createHealthIndicator(healthIndicators), false);
|
||||||
|
Health health = endpoint.health();
|
||||||
|
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||||
|
assertThat(health.getDetails()).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
private HealthIndicator createHealthIndicator(
|
private HealthIndicator createHealthIndicator(
|
||||||
Map<String, HealthIndicator> healthIndicators) {
|
Map<String, HealthIndicator> healthIndicators) {
|
||||||
return new CompositeHealthIndicatorFactory()
|
return new CompositeHealthIndicatorFactory()
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,8 @@ public class HealthEndpointWebIntegrationTests {
|
||||||
Map<String, HealthIndicator> healthIndicators) {
|
Map<String, HealthIndicator> healthIndicators) {
|
||||||
return new HealthEndpoint(
|
return new HealthEndpoint(
|
||||||
new CompositeHealthIndicatorFactory().createHealthIndicator(
|
new CompositeHealthIndicatorFactory().createHealthIndicator(
|
||||||
new OrderedHealthAggregator(), healthIndicators));
|
new OrderedHealthAggregator(), healthIndicators),
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2012-2017 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.junit.Test;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link StatusEndpoint}.
|
|
||||||
*
|
|
||||||
* @author Stephane Nicoll
|
|
||||||
*/
|
|
||||||
public class StatusEndpointTests {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onlyStatusIsExposed() {
|
|
||||||
Map<String, HealthIndicator> healthIndicators = new HashMap<>();
|
|
||||||
healthIndicators.put("up", () -> new Health.Builder().status(Status.UP)
|
|
||||||
.withDetail("first", "1").build());
|
|
||||||
healthIndicators.put("upAgain", () -> new Health.Builder().status(Status.UP)
|
|
||||||
.withDetail("second", "2").build());
|
|
||||||
StatusEndpoint endpoint = new StatusEndpoint(
|
|
||||||
createHealthIndicator(healthIndicators));
|
|
||||||
Health health = endpoint.health();
|
|
||||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
|
||||||
assertThat(health.getDetails()).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private HealthIndicator createHealthIndicator(
|
|
||||||
Map<String, HealthIndicator> healthIndicators) {
|
|
||||||
return new CompositeHealthIndicatorFactory()
|
|
||||||
.createHealthIndicator(new OrderedHealthAggregator(), healthIndicators);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2012-2017 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.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointRunners;
|
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Integration tests for {@link StatusEndpoint} and {@link StatusEndpointWebExtension}
|
|
||||||
* exposed by Jersey, Spring MVC, and WebFlux.
|
|
||||||
*
|
|
||||||
* @author Stephane Nicoll
|
|
||||||
*/
|
|
||||||
@RunWith(WebEndpointRunners.class)
|
|
||||||
public class StatusEndpointWebIntegrationTests {
|
|
||||||
|
|
||||||
private static WebTestClient client;
|
|
||||||
|
|
||||||
private static ConfigurableApplicationContext context;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void whenStatusIsUp200ResponseIsReturned() throws Exception {
|
|
||||||
client.get().uri("/application/status").exchange().expectStatus().isOk()
|
|
||||||
.expectBody().json("{\"status\":\"UP\"}");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void whenStatusIsDown503ResponseIsReturned() throws Exception {
|
|
||||||
context.getBean("alphaHealthIndicator", TestHealthIndicator.class)
|
|
||||||
.setHealth(Health.down().build());
|
|
||||||
client.get().uri("/application/status").exchange().expectStatus()
|
|
||||||
.isEqualTo(HttpStatus.SERVICE_UNAVAILABLE).expectBody()
|
|
||||||
.json("{\"status\":\"DOWN\"}");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
public static class TestConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public StatusEndpoint statusEndpoint(
|
|
||||||
Map<String, HealthIndicator> healthIndicators) {
|
|
||||||
return new StatusEndpoint(
|
|
||||||
new CompositeHealthIndicatorFactory().createHealthIndicator(
|
|
||||||
new OrderedHealthAggregator(), healthIndicators));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public StatusEndpointWebExtension statusWebEndpointExtension(
|
|
||||||
StatusEndpoint delegate) {
|
|
||||||
return new StatusEndpointWebExtension(delegate, new HealthStatusHttpMapper());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public TestHealthIndicator alphaHealthIndicator() {
|
|
||||||
return new TestHealthIndicator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public TestHealthIndicator bravoHealthIndicator() {
|
|
||||||
return new TestHealthIndicator();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TestHealthIndicator implements HealthIndicator {
|
|
||||||
|
|
||||||
private Health health = Health.up().build();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Health health() {
|
|
||||||
Health result = this.health;
|
|
||||||
this.health = Health.up().build();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setHealth(Health health) {
|
|
||||||
this.health = health;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1165,6 +1165,7 @@ content into your application. Rather, pick only the properties that you need.
|
||||||
# HEALTH ENDPOINT ({sc-spring-boot-actuator}/health/HealthEndpoint.{sc-ext}[HealthEndpoint])
|
# HEALTH ENDPOINT ({sc-spring-boot-actuator}/health/HealthEndpoint.{sc-ext}[HealthEndpoint])
|
||||||
management.endpoint.health.cache.time-to-live=0ms # Maximum time that a response can be cached.
|
management.endpoint.health.cache.time-to-live=0ms # Maximum time that a response can be cached.
|
||||||
management.endpoint.health.enabled= # Whether to enable the health endpoint.
|
management.endpoint.health.enabled= # Whether to enable the health endpoint.
|
||||||
|
management.endpoint.health.show-details= # Whether to show full health details
|
||||||
|
|
||||||
# HEAP DUMP ENDPOINT ({sc-spring-boot-actuator}/management/HeapDumpWebEndpoint.{sc-ext}[HeapDumpWebEndpoint])
|
# HEAP DUMP ENDPOINT ({sc-spring-boot-actuator}/management/HeapDumpWebEndpoint.{sc-ext}[HeapDumpWebEndpoint])
|
||||||
management.endpoint.heapdump.cache.time-to-live=0ms # Maximum time that a response can be cached.
|
management.endpoint.heapdump.cache.time-to-live=0ms # Maximum time that a response can be cached.
|
||||||
|
|
|
||||||
|
|
@ -111,10 +111,6 @@ The following technology-agnostic endpoints are available:
|
||||||
|`shutdown`
|
|`shutdown`
|
||||||
|Lets the application be gracefully shutdown (not enabled by default).
|
|Lets the application be gracefully shutdown (not enabled by default).
|
||||||
|
|
||||||
|`status`
|
|
||||||
|Shows application status information (that is, `health` status with no additional
|
|
||||||
details).
|
|
||||||
|
|
||||||
|`threaddump`
|
|`threaddump`
|
||||||
|Performs a thread dump.
|
|Performs a thread dump.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||||
protected void configure(HttpSecurity http) throws Exception {
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
http.authorizeRequests()
|
http.authorizeRequests()
|
||||||
.requestMatchers(EndpointRequest.to("status", "info")).permitAll()
|
.requestMatchers(EndpointRequest.to("health", "info")).permitAll()
|
||||||
.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ACTUATOR")
|
.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ACTUATOR")
|
||||||
.requestMatchers(StaticResourceRequest.toCommonLocations()).permitAll()
|
.requestMatchers(StaticResourceRequest.toCommonLocations()).permitAll()
|
||||||
.antMatchers("/foo").permitAll()
|
.antMatchers("/foo").permitAll()
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
management.endpoints.web.expose=*
|
management.endpoints.web.expose=*
|
||||||
|
management.endpoint.health.show-details=true
|
||||||
|
|
|
||||||
|
|
@ -57,9 +57,9 @@ public class ManagementPortAndPathSampleActuatorApplicationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSecureActuator() throws Exception {
|
public void testSecureActuator() throws Exception {
|
||||||
ResponseEntity<String> entity = new TestRestTemplate()
|
ResponseEntity<String> entity = new TestRestTemplate().getForEntity(
|
||||||
.getForEntity("http://localhost:" + this.managementPort
|
"http://localhost:" + this.managementPort + "/management/application/env",
|
||||||
+ "/management/application/health", String.class);
|
String.class);
|
||||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,7 +67,7 @@ public class ManagementPortAndPathSampleActuatorApplicationTests {
|
||||||
public void testInsecureActuator() throws Exception {
|
public void testInsecureActuator() throws Exception {
|
||||||
ResponseEntity<String> entity = new TestRestTemplate()
|
ResponseEntity<String> entity = new TestRestTemplate()
|
||||||
.getForEntity("http://localhost:" + this.managementPort
|
.getForEntity("http://localhost:" + this.managementPort
|
||||||
+ "/management/application/status", String.class);
|
+ "/management/application/health", String.class);
|
||||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||||
assertThat(entity.getBody()).contains("\"status\":\"UP\"");
|
assertThat(entity.getBody()).contains("\"status\":\"UP\"");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ public class SampleActuatorCustomSecurityApplicationTests {
|
||||||
@Test
|
@Test
|
||||||
public void insecureActuator() throws Exception {
|
public void insecureActuator() throws Exception {
|
||||||
ResponseEntity<String> entity = this.restTemplate
|
ResponseEntity<String> entity = this.restTemplate
|
||||||
.getForEntity("/application/status", String.class);
|
.getForEntity("/application/health", String.class);
|
||||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||||
assertThat(entity.getBody()).contains("\"status\":\"UP\"");
|
assertThat(entity.getBody()).contains("\"status\":\"UP\"");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
server.error.path: /oops
|
server.error.path: /oops
|
||||||
|
management.endpoint.health.show-details: true
|
||||||
management.endpoints.web.base-path: /admin
|
management.endpoints.web.base-path: /admin
|
||||||
|
|
@ -61,7 +61,7 @@ public class SampleJerseyApplicationTests {
|
||||||
@Test
|
@Test
|
||||||
public void actuatorStatus() {
|
public void actuatorStatus() {
|
||||||
ResponseEntity<String> entity = this.restTemplate
|
ResponseEntity<String> entity = this.restTemplate
|
||||||
.getForEntity("/application/status", String.class);
|
.getForEntity("/application/health", String.class);
|
||||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||||
assertThat(entity.getBody()).isEqualTo("{\"status\":\"UP\"}");
|
assertThat(entity.getBody()).isEqualTo("{\"status\":\"UP\"}");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ public class SampleSecureWebFluxApplicationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void actuatorsSecureByDefault() {
|
public void actuatorsSecureByDefault() {
|
||||||
this.webClient.get().uri("/application/status").accept(MediaType.APPLICATION_JSON)
|
this.webClient.get().uri("/application/health").accept(MediaType.APPLICATION_JSON)
|
||||||
.exchange().expectStatus().isUnauthorized();
|
.exchange().expectStatus().isUnauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,7 +61,7 @@ public class SampleSecureWebFluxApplicationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void actuatorsAccessibleOnLogin() {
|
public void actuatorsAccessibleOnLogin() {
|
||||||
this.webClient.get().uri("/application/status").accept(MediaType.APPLICATION_JSON)
|
this.webClient.get().uri("/application/health").accept(MediaType.APPLICATION_JSON)
|
||||||
.header("Authorization", "basic " + getBasicAuth()).exchange()
|
.header("Authorization", "basic " + getBasicAuth()).exchange()
|
||||||
.expectBody(String.class).isEqualTo("{\"status\":\"UP\"}");
|
.expectBody(String.class).isEqualTo("{\"status\":\"UP\"}");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ public class SampleWebFluxApplicationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testActuatorStatus() {
|
public void testActuatorStatus() {
|
||||||
this.webClient.get().uri("/application/status").accept(MediaType.APPLICATION_JSON)
|
this.webClient.get().uri("/application/health").accept(MediaType.APPLICATION_JSON)
|
||||||
.exchange().expectStatus().isOk().expectBody()
|
.exchange().expectStatus().isOk().expectBody()
|
||||||
.json("{\"status\":\"UP\"}");
|
.json("{\"status\":\"UP\"}");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue