Allow to customize the path of a web endpoint

This commit introduces a endpoints.<id>.web.path generic property that
allows to customize the path of an endpoint. By default the path is the
same as the id of the endpoint.

Such customization does not apply for the CloudFoundry specific
endpoints.

Closes gh-10181
pull/10511/merge
Stephane Nicoll 7 years ago
parent 622e65a290
commit 56afc25304

@ -82,7 +82,7 @@ public class CloudFoundryActuatorAutoConfiguration {
RestTemplateBuilder builder) {
WebAnnotationEndpointDiscoverer endpointDiscoverer = new WebAnnotationEndpointDiscoverer(
this.applicationContext, parameterMapper, cachingConfigurationFactory,
endpointMediaTypes);
endpointMediaTypes, (id) -> id);
return new CloudFoundryWebEndpointServletHandlerMapping(
new EndpointMapping("/cloudfoundryapplication"),
endpointDiscoverer.discoverEndpoints(), endpointMediaTypes,

@ -0,0 +1,42 @@
/*
* 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;
import org.springframework.boot.actuate.endpoint.web.EndpointPathResolver;
import org.springframework.core.env.Environment;
/**
* Default {@link EndpointPathResolver} implementation that use the
* {@link Environment} to determine if an endpoint has a custom path.
*
* @author Stephane Nicoll
*/
class DefaultEndpointPathResolver implements EndpointPathResolver {
private final Environment environment;
DefaultEndpointPathResolver(Environment environment) {
this.environment = environment;
}
@Override
public String resolvePath(String endpointId) {
String key = String.format("endpoints.%s.web.path", endpointId);
return this.environment.getProperty(key, String.class, endpointId);
}
}

@ -26,6 +26,7 @@ import org.springframework.boot.actuate.endpoint.cache.CachingConfigurationFacto
import org.springframework.boot.actuate.endpoint.convert.ConversionServiceOperationParameterMapper;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.EndpointPathResolver;
import org.springframework.boot.actuate.endpoint.web.WebEndpointOperation;
import org.springframework.boot.actuate.endpoint.web.annotation.WebAnnotationEndpointDiscoverer;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -77,14 +78,22 @@ public class EndpointAutoConfiguration {
return new EndpointMediaTypes(MEDIA_TYPES, MEDIA_TYPES);
}
@Bean
@ConditionalOnMissingBean
public EndpointPathResolver endpointPathResolver(
Environment environment) {
return new DefaultEndpointPathResolver(environment);
}
@Bean
public EndpointProvider<WebEndpointOperation> webEndpointProvider(
OperationParameterMapper parameterMapper,
DefaultCachingConfigurationFactory cachingConfigurationFactory) {
DefaultCachingConfigurationFactory cachingConfigurationFactory,
EndpointPathResolver endpointPathResolver) {
Environment environment = this.applicationContext.getEnvironment();
WebAnnotationEndpointDiscoverer endpointDiscoverer = new WebAnnotationEndpointDiscoverer(
this.applicationContext, parameterMapper, cachingConfigurationFactory,
endpointMediaTypes());
endpointMediaTypes(), endpointPathResolver);
return new EndpointProvider<>(environment, endpointDiscoverer,
EndpointExposure.WEB);
}

@ -219,6 +219,22 @@ public class CloudFoundryActuatorAutoConfigurationTests {
assertThat(endpoints.get(0).getId()).isEqualTo("test");
}
@Test
public void endpointPathCustomizationIsNotApplied()
throws Exception {
TestPropertyValues.of("endpoints.test.web.path=another/custom")
.applyTo(this.context);
this.context.register(TestConfiguration.class);
this.context.refresh();
CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping();
List<EndpointInfo<WebEndpointOperation>> endpoints = (List<EndpointInfo<WebEndpointOperation>>) handlerMapping
.getEndpoints();
assertThat(endpoints.size()).isEqualTo(1);
assertThat(endpoints.get(0).getOperations()).hasSize(1);
assertThat(endpoints.get(0).getOperations().iterator().next()
.getRequestPredicate().getPath()).isEqualTo("test");
}
private CloudFoundryWebEndpointServletHandlerMapping getHandlerMapping() {
TestPropertyValues
.of("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id",

@ -219,7 +219,7 @@ public class CloudFoundryMvcWebEndpointIntegrationTests {
DefaultConversionService.getSharedInstance());
return new WebAnnotationEndpointDiscoverer(applicationContext,
parameterMapper, (id) -> new CachingConfiguration(0),
endpointMediaTypes);
endpointMediaTypes, (id) -> id);
}
@Bean

@ -0,0 +1,49 @@
/*
* 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;
import org.junit.Test;
import org.springframework.boot.actuate.endpoint.web.EndpointPathResolver;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DefaultEndpointPathResolver}.
*
* @author Stephane Nicoll
*/
public class DefaultEndpointPathResolverTests {
private final MockEnvironment environment = new MockEnvironment();
private final EndpointPathResolver resolver = new DefaultEndpointPathResolver(
this.environment);
@Test
public void defaultConfiguration() {
assertThat(this.resolver.resolvePath("test")).isEqualTo("test");
}
@Test
public void userConfiguration() {
this.environment.setProperty("endpoints.test.web.path", "custom");
assertThat(this.resolver.resolvePath("test")).isEqualTo("custom");
}
}

@ -0,0 +1,35 @@
/*
* 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.endpoint.web;
/**
* Resolve the path of an endpoint.
*
* @author Stephane Nicoll
* @since 2.0.0
*/
@FunctionalInterface
public interface EndpointPathResolver {
/**
* Resolve the path for the endpoint with the specified {@code endpointId}.
* @param endpointId the id of an endpoint
* @return the path of the endpoint
*/
String resolvePath(String endpointId);
}

@ -40,6 +40,7 @@ import org.springframework.boot.actuate.endpoint.cache.CachingConfiguration;
import org.springframework.boot.actuate.endpoint.cache.CachingConfigurationFactory;
import org.springframework.boot.actuate.endpoint.cache.CachingOperationInvoker;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.EndpointPathResolver;
import org.springframework.boot.actuate.endpoint.web.OperationRequestPredicate;
import org.springframework.boot.actuate.endpoint.web.WebEndpointHttpMethod;
import org.springframework.boot.actuate.endpoint.web.WebEndpointOperation;
@ -71,14 +72,17 @@ public class WebAnnotationEndpointDiscoverer extends
* @param cachingConfigurationFactory the {@link CachingConfiguration} factory to use
* @param endpointMediaTypes the media types produced and consumed by web endpoint
* operations
* @param endpointPathResolver the {@link EndpointPathResolver} used to resolve
* endpoint paths
*/
public WebAnnotationEndpointDiscoverer(ApplicationContext applicationContext,
OperationParameterMapper operationParameterMapper,
CachingConfigurationFactory cachingConfigurationFactory,
EndpointMediaTypes endpointMediaTypes) {
EndpointMediaTypes endpointMediaTypes,
EndpointPathResolver endpointPathResolver) {
super(applicationContext,
new WebEndpointOperationFactory(operationParameterMapper,
endpointMediaTypes),
endpointMediaTypes, endpointPathResolver),
WebEndpointOperation::getRequestPredicate, cachingConfigurationFactory);
}
@ -121,10 +125,14 @@ public class WebAnnotationEndpointDiscoverer extends
private final EndpointMediaTypes endpointMediaTypes;
private final EndpointPathResolver endpointPathResolver;
private WebEndpointOperationFactory(OperationParameterMapper parameterMapper,
EndpointMediaTypes endpointMediaTypes) {
EndpointMediaTypes endpointMediaTypes,
EndpointPathResolver endpointPathResolver) {
this.parameterMapper = parameterMapper;
this.endpointMediaTypes = endpointMediaTypes;
this.endpointPathResolver = endpointPathResolver;
}
@Override
@ -147,7 +155,8 @@ public class WebAnnotationEndpointDiscoverer extends
}
private String determinePath(String endpointId, Method operationMethod) {
StringBuilder path = new StringBuilder(endpointId);
StringBuilder path = new StringBuilder(
this.endpointPathResolver.resolvePath(endpointId));
Stream.of(operationMethod.getParameters())
.filter((
parameter) -> parameter.getAnnotation(Selector.class) != null)

@ -385,7 +385,7 @@ public abstract class AbstractWebEndpointIntegrationTests<T extends Configurable
DefaultConversionService.getSharedInstance());
return new WebAnnotationEndpointDiscoverer(applicationContext,
parameterMapper, (id) -> new CachingConfiguration(0),
endpointMediaTypes());
endpointMediaTypes(), (id) -> id);
}
@Bean

@ -189,8 +189,8 @@ public class WebAnnotationEndpointDiscovererTests {
@Test
public void endpointMainReadOperationIsCachedWithMatchingId() {
load((id) -> new CachingConfiguration(500), TestEndpointConfiguration.class,
(discoverer) -> {
load((id) -> new CachingConfiguration(500), (id) -> id,
TestEndpointConfiguration.class, (discoverer) -> {
Map<String, EndpointInfo<WebEndpointOperation>> endpoints = mapEndpoints(
discoverer.discoverEndpoints());
assertThat(endpoints).containsOnlyKeys("test");
@ -237,12 +237,29 @@ public class WebAnnotationEndpointDiscovererTests {
});
}
@Test
public void endpointPathCanBeCustomized() {
load((id) -> null, (id) -> "custom/" + id,
AdditionalOperationWebEndpointConfiguration.class, (discoverer) -> {
Map<String, EndpointInfo<WebEndpointOperation>> endpoints = mapEndpoints(
discoverer.discoverEndpoints());
assertThat(endpoints).containsOnlyKeys("test");
EndpointInfo<WebEndpointOperation> endpoint = endpoints.get("test");
assertThat(requestPredicates(endpoint)).has(requestPredicates(
path("custom/test").httpMethod(WebEndpointHttpMethod.GET).consumes()
.produces("application/json"),
path("custom/test/{id}").httpMethod(WebEndpointHttpMethod.GET).consumes()
.produces("application/json")));
});
}
private void load(Class<?> configuration,
Consumer<WebAnnotationEndpointDiscoverer> consumer) {
this.load((id) -> null, configuration, consumer);
this.load((id) -> null, (id) -> id, configuration, consumer);
}
private void load(CachingConfigurationFactory cachingConfigurationFactory,
EndpointPathResolver endpointPathResolver,
Class<?> configuration, Consumer<WebAnnotationEndpointDiscoverer> consumer) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
configuration);
@ -254,7 +271,8 @@ public class WebAnnotationEndpointDiscovererTests {
cachingConfigurationFactory,
new EndpointMediaTypes(
Collections.singletonList("application/json"),
Collections.singletonList("application/json"))));
Collections.singletonList("application/json")),
endpointPathResolver));
}
finally {
context.close();

@ -99,7 +99,7 @@ class JerseyEndpointsRunner extends AbstractWebEndpointRunner {
WebAnnotationEndpointDiscoverer discoverer = new WebAnnotationEndpointDiscoverer(
this.applicationContext,
new ConversionServiceOperationParameterMapper(), (id) -> null,
endpointMediaTypes);
endpointMediaTypes, (id) -> id);
Collection<Resource> resources = new JerseyEndpointResourceFactory()
.createEndpointResources(new EndpointMapping("/application"),
discoverer.discoverEndpoints(), endpointMediaTypes);

@ -105,7 +105,7 @@ class WebFluxEndpointsRunner extends AbstractWebEndpointRunner {
WebAnnotationEndpointDiscoverer discoverer = new WebAnnotationEndpointDiscoverer(
this.applicationContext,
new ConversionServiceOperationParameterMapper(), (id) -> null,
endpointMediaTypes);
endpointMediaTypes, (id) -> id);
return new WebFluxEndpointHandlerMapping(new EndpointMapping("/application"),
discoverer.discoverEndpoints(), endpointMediaTypes,
new CorsConfiguration());

@ -88,7 +88,7 @@ class WebMvcEndpointRunner extends AbstractWebEndpointRunner {
WebAnnotationEndpointDiscoverer discoverer = new WebAnnotationEndpointDiscoverer(
this.applicationContext,
new ConversionServiceOperationParameterMapper(), (id) -> null,
endpointMediaTypes);
endpointMediaTypes, (id) -> id);
return new WebMvcEndpointHandlerMapping(new EndpointMapping("/application"),
discoverer.discoverEndpoints(), endpointMediaTypes,
new CorsConfiguration());

@ -1077,18 +1077,21 @@ content into your application; rather pick only the properties that you need.
endpoints.auditevents.enabled= # Enable the auditevents endpoint.
endpoints.auditevents.jmx.enabled= # Expose the auditevents endpoint as a JMX MBean.
endpoints.auditevents.web.enabled= # Expose the auditevents endpoint as a Web endpoint.
endpoints.auditevents.web.path=auditevents # Path of the auditevents endpoint.
# AUTO-CONFIGURATION REPORT ENDPOINT ({sc-spring-boot-actuator-autoconfigure}/condition/AutoConfigurationReportEndpoint.{sc-ext}[AutoConfigurationReportEndpoint])
endpoints.autoconfig.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
endpoints.autoconfig.enabled= # Enable the autoconfig endpoint.
endpoints.autoconfig.jmx.enabled= # Expose the autoconfig endpoint as a JMX MBean.
endpoints.autoconfig.web.enabled= # Expose the autoconfig endpoint as a Web endpoint.
endpoints.autoconfig.web.path=autoconfig # Path of the autoconfig endpoint.
# BEANS ENDPOINT ({sc-spring-boot-actuator}/beans/BeansEndpoint.{sc-ext}[BeansEndpoint])
endpoints.beans.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
endpoints.beans.enabled= # Enable the beans endpoint.
endpoints.beans.jmx.enabled= # Expose the beans endpoint as a JMX MBean.
endpoints.beans.web.enabled= # Expose the beans endpoint as a Web endpoint.
endpoints.beans.web.path=beans # Path of the beans endpoint.
# CONFIGURATION PROPERTIES REPORT ENDPOINT ({sc-spring-boot-actuator}/context/properties/ConfigurationPropertiesReportEndpoint.{sc-ext}[ConfigurationPropertiesReportEndpoint])
endpoints.configprops.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
@ -1096,6 +1099,7 @@ content into your application; rather pick only the properties that you need.
endpoints.configprops.jmx.enabled= # Expose the configprops endpoint as a JMX MBean.
endpoints.configprops.keys-to-sanitize=password,secret,key,token,.*credentials.*,vcap_services # Keys that should be sanitized. Keys can be simple strings that the property ends with or regular expressions.
endpoints.configprops.web.enabled= # Expose the configprops endpoint as a Web endpoint.
endpoints.configprops.web.path=configprops # Path of the configprops endpoint.
# ENDPOINT DEFAULT SETTINGS
endpoints.default.enabled=true # Enable all endpoints by default.
@ -1108,94 +1112,110 @@ content into your application; rather pick only the properties that you need.
endpoints.env.jmx.enabled= # Expose the env endpoint as a JMX MBean.
endpoints.env.keys-to-sanitize=password,secret,key,token,.*credentials.*,vcap_services # Keys that should be sanitized. Keys can be simple strings that the property ends with or regular expressions.
endpoints.env.web.enabled= # Expose the env endpoint as a Web endpoint.
endpoints.env.web.path=env # Path of the env endpoint.
# FLYWAY ENDPOINT ({sc-spring-boot-actuator}/flyway/FlywayEndpoint.{sc-ext}[FlywayEndpoint])
endpoints.flyway.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
endpoints.flyway.enabled= # Enable the flyway endpoint.
endpoints.flyway.jmx.enabled= # Expose the flyway endpoint as a JMX MBean.
endpoints.flyway.web.enabled= # Expose the flyway endpoint as a Web endpoint.
endpoints.flyway.web.path=flyway # Path of the flyway endpoint.
# HEALTH ENDPOINT ({sc-spring-boot-actuator}/health/HealthEndpoint.{sc-ext}[HealthEndpoint])
endpoints.health.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
endpoints.health.enabled= # Enable the health endpoint.
endpoints.health.jmx.enabled= # Expose the health endpoint as a JMX MBean.
endpoints.health.web.enabled= # Expose the health endpoint as a Web endpoint.
endpoints.health.web.path=health # Path of the health endpoint.
# HEAP DUMP ENDPOINT ({sc-spring-boot-actuator}/management/HeapDumpWebEndpoint.{sc-ext}[HeapDumpWebEndpoint])
endpoints.heapdump.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
endpoints.heapdump.enabled= # Enable the heapdump endpoint.
endpoints.heapdump.web.enabled= # Expose the heapdump endpoint as a Web endpoint.
endpoints.heapdump.web.path=heapdump # Path of the heapdump endpoint.
# INFO ENDPOINT ({sc-spring-boot-actuator}/info/InfoEndpoint.{sc-ext}[InfoEndpoint])
endpoints.info.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
endpoints.info.enabled=true # Enable the info endpoint.
endpoints.info.jmx.enabled=true # Expose the info endpoint as a JMX MBean.
endpoints.info.web.enabled=true # Expose the info endpoint as a Web endpoint.
endpoints.info.web.path=info # Path of the info endpoint.
# LIQUIBASE ENDPOINT ({sc-spring-boot-actuator}/liquibase/LiquibaseEndpoint.{sc-ext}[LiquibaseEndpoint])
endpoints.liquibase.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
endpoints.liquibase.enabled= # Enable the liquibase endpoint.
endpoints.liquibase.jmx.enabled= # Expose the liquibase endpoint as a JMX MBean.
endpoints.liquibase.web.enabled= # Expose the liquibase endpoint as a Web endpoint.
endpoints.liquibase.web.path=liquibase # Path of the liquibase endpoint.
# LOG FILE ENDPOINT ({sc-spring-boot-actuator}/logging/LogFileWebEndpoint.{sc-ext}[LogFileWebEndpoint])
endpoints.logfile.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
endpoints.logfile.enabled= # Enable the logfile endpoint.
endpoints.logfile.external-file= # External Logfile to be accessed. Can be used if the logfile is written by output redirect and not by the logging system itself.
endpoints.logfile.web.enabled= # Expose the logfile endpoint as a Web endpoint.
endpoints.logfile.web.path=logfile # Path of the logfile endpoint.
# LOGGERS ENDPOINT ({sc-spring-boot-actuator}/logging/LoggersEndpoint.{sc-ext}[LoggersEndpoint])
endpoints.loggers.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
endpoints.loggers.enabled= # Enable the loggers endpoint.
endpoints.loggers.jmx.enabled= # Expose the loggers endpoint as a JMX MBean.
endpoints.loggers.web.enabled= # Expose the loggers endpoint as a Web endpoint.
endpoints.loggers.web.path=loggers # Path of the loggers endpoint.
# REQUEST MAPPING ENDPOINT ({sc-spring-boot-actuator-autoconfigure}/web/servlet/RequestMappingEndpoint.{sc-ext}[RequestMappingEndpoint])
endpoints.mappings.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
endpoints.mappings.enabled= # Enable the mappings endpoint.
endpoints.mappings.jmx.enabled= # Expose the mappings endpoint as a JMX MBean.
endpoints.mappings.web.enabled= # Expose the mappings endpoint as a Web endpoint.
endpoints.mappings.web.path=mappings # Path of the mappings endpoint.
# METRICS ENDPOINT ({sc-spring-boot-actuator}/metrics/MetricsEndpoint.{sc-ext}[MetricsEndpoint])
endpoints.metrics.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
endpoints.metrics.enabled= # Enable the metrics endpoint.
endpoints.metrics.jmx.enabled= # Expose the metrics endpoint as a JMX MBean.
endpoints.metrics.web.enabled= # Expose the metrics endpoint as a Web endpoint.
endpoints.metrics.web.path=metrics # Path of the metrics endpoint.
# PROMETHEUS ENDPOINT ({sc-spring-boot-actuator}/metrics/export/prometheus/PrometheusScrapeEndpoint.{sc-ext}[PrometheusScrapeEndpoint])
endpoints.prometheus.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
endpoints.prometheus.enabled= # Enable the metrics endpoint.
endpoints.prometheus.web.enabled= # Expose the metrics endpoint as a Web endpoint.
endpoints.prometheus.web.path=prometheus # Path of the prometheus endpoint.
# SESSIONS ENDPOINT ({sc-spring-boot-actuator}/session/SessionsEndpoint.{sc-ext}[SessionsEndpoint])
endpoints.sessions.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
endpoints.sessions.enabled= # Enable the sessions endpoint.
endpoints.sessions.jmx.enabled= # Expose the sessions endpoint as a JMX MBean.
endpoints.sessions.web.enabled= # Expose the sessions endpoint as a Web endpoint.
endpoints.sessions.web.path=sessions # Path of the sessions endpoint.
# SHUTDOWN ENDPOINT ({sc-spring-boot-actuator}/context/ShutdownEndpoint.{sc-ext}[ShutdownEndpoint])
endpoints.shutdown.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
endpoints.shutdown.enabled=false # Enable the shutdown endpoint.
endpoints.shutdown.jmx.enabled=false # Expose the shutdown endpoint as a JMX MBean.
endpoints.shutdown.web.enabled=false # Expose the shutdown endpoint as a Web endpoint.
endpoints.shutdown.web.path=shutdown # Path of the shutdown endpoint.
# STATUS ENDPOINT ({sc-spring-boot-actuator}/health/StatusEndpoint.{sc-ext}[StatusEndpoint])
endpoints.status.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
endpoints.status.enabled=true # Enable the status endpoint.
endpoints.status.jmx.enabled=true # Expose the status endpoint as a JMX MBean.
endpoints.status.web.enabled=true # Expose the status endpoint as a Web endpoint.
endpoints.status.web.path=status # Path of the status endpoint.
# THREAD DUMP ENDPOINT ({sc-spring-boot-actuator}/management/ThreadDumpEndpoint.{sc-ext}[ThreadDumpEndpoint])
endpoints.threaddump.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
endpoints.threaddump.enabled= # Enable the threaddump endpoint.
endpoints.threaddump.jmx.enabled= # Expose the threaddump endpoint as a JMX MBean.
endpoints.threaddump.web.enabled= # Expose the threaddump endpoint as a Web endpoint.
endpoints.threaddump.web.path=threaddump # Path of the threaddump endpoint.
# TRACE ENDPOINT ({sc-spring-boot-actuator}/trace/TraceEndpoint.{sc-ext}[TraceEndpoint])
endpoints.trace.cache.time-to-live=0 # Maximum time in milliseconds that a response can be cached.
endpoints.trace.enabled= # Enable the trace endpoint.
endpoints.trace.jmx.enabled= # Expose the trace endpoint as a JMX MBean.
endpoints.trace.web.enabled= # Expose the trace endpoint as a Web endpoint.
endpoints.trace.web.path=trace # Path of the trace endpoint.
# MANAGEMENT HTTP SERVER ({sc-spring-boot-actuator-autoconfigure}/web/server/ManagementServerProperties.{sc-ext}[ManagementServerProperties])
management.server.add-application-context-header=false # Add the "X-Application-Context" HTTP header in each response. Requires a custom management.server.port.

@ -394,6 +394,10 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor
type, null, String.format("Expose the %s endpoint as a Web endpoint.",
endpointId),
enabledByDefault, null));
this.metadataCollector.add(ItemMetadata.newProperty(
endpointKey(endpointId), "web.path", String.class.getName(), type,
null, String.format("Path of the %s endpoint.", endpointId),
endpointId, null));
}
}

@ -539,8 +539,9 @@ public class ConfigurationMetadataAnnotationProcessorTests {
assertThat(metadata).has(enabledFlag("simple", null));
assertThat(metadata).has(jmxEnabledFlag("simple", null));
assertThat(metadata).has(webEnabledFlag("simple", null));
assertThat(metadata).has(webPath("simple"));
assertThat(metadata).has(cacheTtl("simple"));
assertThat(metadata.getItems()).hasSize(5);
assertThat(metadata.getItems()).hasSize(6);
}
@Test
@ -551,8 +552,9 @@ public class ConfigurationMetadataAnnotationProcessorTests {
assertThat(metadata).has(enabledFlag("disabled", false));
assertThat(metadata).has(jmxEnabledFlag("disabled", false));
assertThat(metadata).has(webEnabledFlag("disabled", false));
assertThat(metadata).has(webPath("disabled"));
assertThat(metadata).has(cacheTtl("disabled"));
assertThat(metadata.getItems()).hasSize(5);
assertThat(metadata.getItems()).hasSize(6);
}
@Test
@ -563,8 +565,9 @@ public class ConfigurationMetadataAnnotationProcessorTests {
assertThat(metadata).has(enabledFlag("enabled", true));
assertThat(metadata).has(jmxEnabledFlag("enabled", true));
assertThat(metadata).has(webEnabledFlag("enabled", true));
assertThat(metadata).has(webPath("enabled"));
assertThat(metadata).has(cacheTtl("enabled"));
assertThat(metadata.getItems()).hasSize(5);
assertThat(metadata.getItems()).hasSize(6);
}
@Test
@ -577,8 +580,9 @@ public class ConfigurationMetadataAnnotationProcessorTests {
assertThat(metadata).has(enabledFlag("customprops", null));
assertThat(metadata).has(jmxEnabledFlag("customprops", null));
assertThat(metadata).has(webEnabledFlag("customprops", null));
assertThat(metadata).has(webPath("customprops"));
assertThat(metadata).has(cacheTtl("customprops"));
assertThat(metadata.getItems()).hasSize(6);
assertThat(metadata.getItems()).hasSize(7);
}
@Test
@ -599,8 +603,9 @@ public class ConfigurationMetadataAnnotationProcessorTests {
Metadata.withGroup("endpoints.web").fromSource(OnlyWebEndpoint.class));
assertThat(metadata).has(enabledFlag("web", null));
assertThat(metadata).has(webEnabledFlag("web", null));
assertThat(metadata).has(webPath("web"));
assertThat(metadata).has(cacheTtl("web"));
assertThat(metadata.getItems()).hasSize(4);
assertThat(metadata.getItems()).hasSize(5);
}
@Test
@ -613,8 +618,9 @@ public class ConfigurationMetadataAnnotationProcessorTests {
assertThat(metadata).has(enabledFlag("incremental", null));
assertThat(metadata).has(jmxEnabledFlag("incremental", null));
assertThat(metadata).has(webEnabledFlag("incremental", null));
assertThat(metadata).has(webPath("incremental"));
assertThat(metadata).has(cacheTtl("incremental"));
assertThat(metadata.getItems()).hasSize(5);
assertThat(metadata.getItems()).hasSize(6);
project.replaceText(IncrementalEndpoint.class, "id = \"incremental\"",
"id = \"incremental\", defaultEnablement = org.springframework.boot."
+ "configurationsample.DefaultEnablement.DISABLED");
@ -624,8 +630,9 @@ public class ConfigurationMetadataAnnotationProcessorTests {
assertThat(metadata).has(enabledFlag("incremental", false));
assertThat(metadata).has(jmxEnabledFlag("incremental", false));
assertThat(metadata).has(webEnabledFlag("incremental", false));
assertThat(metadata).has(webPath("incremental"));
assertThat(metadata).has(cacheTtl("incremental"));
assertThat(metadata.getItems()).hasSize(5);
assertThat(metadata.getItems()).hasSize(6);
}
@Test
@ -638,8 +645,9 @@ public class ConfigurationMetadataAnnotationProcessorTests {
assertThat(metadata).has(enabledFlag("incremental", null));
assertThat(metadata).has(jmxEnabledFlag("incremental", null));
assertThat(metadata).has(webEnabledFlag("incremental", null));
assertThat(metadata).has(webPath("incremental"));
assertThat(metadata).has(cacheTtl("incremental"));
assertThat(metadata.getItems()).hasSize(5);
assertThat(metadata.getItems()).hasSize(6);
project.replaceText(IncrementalEndpoint.class, "id = \"incremental\"",
"id = \"incremental\", exposure = org.springframework.boot."
+ "configurationsample.EndpointExposure.WEB");
@ -648,8 +656,9 @@ public class ConfigurationMetadataAnnotationProcessorTests {
.fromSource(IncrementalEndpoint.class));
assertThat(metadata).has(enabledFlag("incremental", null));
assertThat(metadata).has(webEnabledFlag("incremental", null));
assertThat(metadata).has(webPath("incremental"));
assertThat(metadata).has(cacheTtl("incremental"));
assertThat(metadata.getItems()).hasSize(4);
assertThat(metadata.getItems()).hasSize(5);
}
@Test
@ -671,8 +680,9 @@ public class ConfigurationMetadataAnnotationProcessorTests {
assertThat(metadata).has(enabledFlag("incremental", null));
assertThat(metadata).has(jmxEnabledFlag("incremental", null));
assertThat(metadata).has(webEnabledFlag("incremental", null));
assertThat(metadata).has(webPath("incremental"));
assertThat(metadata).has(cacheTtl("incremental"));
assertThat(metadata.getItems()).hasSize(5);
assertThat(metadata.getItems()).hasSize(6);
}
private Metadata.MetadataItemCondition enabledFlag(String endpointId,
@ -696,6 +706,12 @@ public class ConfigurationMetadataAnnotationProcessorTests {
.format("Expose the %s endpoint as a Web endpoint.", endpointId));
}
private Metadata.MetadataItemCondition webPath(String endpointId) {
return Metadata.withProperty("endpoints." + endpointId + ".web.path")
.ofType(String.class).withDefaultValue(endpointId).withDescription(String
.format("Path of the %s endpoint.", endpointId));
}
private Metadata.MetadataItemCondition cacheTtl(String endpointId) {
return Metadata.withProperty("endpoints." + endpointId + ".cache.time-to-live")
.ofType(Long.class).withDefaultValue(0).withDescription(

Loading…
Cancel
Save