diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ConditionalOnEnabledInfoContributor.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ConditionalOnEnabledInfoContributor.java new file mode 100644 index 0000000000..af8b47e401 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ConditionalOnEnabledInfoContributor.java @@ -0,0 +1,49 @@ +/* + * Copyright 2012-2016 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.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Conditional; + +/** + * {@link Conditional} that checks whether or not a default info contributor is enabled. + * Matches if the value of the {@code management.info..enabled} property is + * {@code true}. Otherwise, matches if the value of the + * {@code management.info.defaults.enabled} property is {@code true} or if it is not + * configured. + * + * @author Stephane Nicoll + * @since 1.4.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +@Documented +@Conditional(OnEnabledInfoContributorCondition.class) +public @interface ConditionalOnEnabledInfoContributor { + + /** + * The name of the info contributor. + * @return the name of the info contributor + */ + String value(); + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java index 4f84782bb6..8661b8e93e 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java @@ -46,7 +46,7 @@ import org.springframework.boot.actuate.endpoint.TraceEndpoint; import org.springframework.boot.actuate.health.HealthAggregator; import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.OrderedHealthAggregator; -import org.springframework.boot.actuate.info.InfoProvider; +import org.springframework.boot.actuate.info.InfoContributor; import org.springframework.boot.actuate.trace.InMemoryTraceRepository; import org.springframework.boot.actuate.trace.TraceRepository; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -89,7 +89,7 @@ public class EndpointAutoConfiguration { private Map healthIndicators = new HashMap(); @Autowired(required = false) - private Map infoProviders = new HashMap(); + private List infoContributors = new ArrayList(); @Autowired(required = false) private Collection publicMetrics; @@ -118,7 +118,7 @@ public class EndpointAutoConfiguration { @Bean @ConditionalOnMissingBean public InfoEndpoint infoEndpoint() throws Exception { - return new InfoEndpoint(this.infoProviders); + return new InfoEndpoint(this.infoContributors); } @Bean diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoContributorAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoContributorAutoConfiguration.java new file mode 100644 index 0000000000..96f7fe7d6b --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoContributorAutoConfiguration.java @@ -0,0 +1,68 @@ +/* + * Copyright 2012-2015 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.io.IOException; + +import org.springframework.boot.actuate.info.EnvironmentInfoContributor; +import org.springframework.boot.actuate.info.InfoContributor; +import org.springframework.boot.actuate.info.SimpleInfoContributor; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; +import org.springframework.boot.autoconfigure.info.GitInfo; +import org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.core.env.ConfigurableEnvironment; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for standard {@link InfoContributor}s. + * + * @author Meang Akira Tanaka + * @author Stephane Nicoll + * @since 1.4.0 + */ +@Configuration +@AutoConfigureAfter(ProjectInfoAutoConfiguration.class) +@AutoConfigureBefore(EndpointAutoConfiguration.class) +public class InfoContributorAutoConfiguration { + + /** + * The default order for the core {@link InfoContributor} beans. + */ + public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10; + + @Bean + @ConditionalOnEnabledInfoContributor("env") + @Order(DEFAULT_ORDER) + public EnvironmentInfoContributor envInfoContributor(ConfigurableEnvironment environment) { + return new EnvironmentInfoContributor(environment); + } + + @Bean + @ConditionalOnEnabledInfoContributor("git") + @ConditionalOnSingleCandidate(GitInfo.class) + @Order(DEFAULT_ORDER) + public InfoContributor gitInfoContributor(GitInfo gitInfo) throws IOException { + return new SimpleInfoContributor("git", gitInfo); + } + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoProviderAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoProviderAutoConfiguration.java deleted file mode 100644 index 60ed68d302..0000000000 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/InfoProviderAutoConfiguration.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2012-2015 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 org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.actuate.info.EnvironmentInfoProvider; -import org.springframework.boot.actuate.info.InfoProvider; -import org.springframework.boot.actuate.info.ScmGitPropertiesInfoProvider; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.StandardEnvironment; -import org.springframework.core.io.Resource; - -/** - * {@link EnableAutoConfiguration Auto-configuration} for standard {@link InfoProvider}s. - * - * @author Meang Akira Tanaka - * @since 1.3.0 - */ -@Configuration -@AutoConfigureBefore({EndpointAutoConfiguration.class}) -public class InfoProviderAutoConfiguration { - - @Autowired - private final ConfigurableEnvironment environment = new StandardEnvironment(); - - @Value("${spring.git.properties:classpath:git.properties}") - private Resource gitProperties; - - @Bean - @ConditionalOnMissingBean(name = "environmentInfoProvider") - public InfoProvider environmentInfoProvider() throws Exception { - return new EnvironmentInfoProvider(this.environment); - } - - @Bean - @ConditionalOnMissingBean(name = "scmInfoProvider") - public InfoProvider scmInfoProvider() throws Exception { - return new ScmGitPropertiesInfoProvider(this.gitProperties); - } - -} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledEndpointElementCondition.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledEndpointElementCondition.java new file mode 100644 index 0000000000..ae5454d511 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledEndpointElementCondition.java @@ -0,0 +1,84 @@ +/* + * Copyright 2012-2016 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 org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.boot.bind.RelaxedPropertyResolver; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.type.AnnotatedTypeMetadata; + +/** + * Base endpoint element condition. An element can be disabled globally via the + * `defaults` name or individually via the name of the element. + * + * @author Stephane Nicoll + */ +abstract class OnEnabledEndpointElementCondition extends SpringBootCondition { + + private final String prefix; + + private final Class annotationType; + + OnEnabledEndpointElementCondition(String prefix, Class annotationType) { + this.prefix = prefix; + this.annotationType = annotationType; + } + + protected String getEndpointElementOutcomeMessage(String name, boolean match) { + return "The endpoint element " + name + " is " + (match ? "enabled" : "disabled"); + } + + protected String getDefaultEndpointElementOutcomeMessage(boolean match) { + return "All default endpoint elements are " + (match ? "enabled" : "disabled") + + " by default"; + } + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, + AnnotatedTypeMetadata metadata) { + AnnotationAttributes annotationAttributes = AnnotationAttributes + .fromMap(metadata.getAnnotationAttributes(this.annotationType.getName())); + String endpointName = annotationAttributes.getString("value"); + ConditionOutcome outcome = getEndpointOutcome(context, endpointName); + if (outcome != null) { + return outcome; + } + return getDefaultEndpointsOutcome(context); + } + + protected ConditionOutcome getEndpointOutcome(ConditionContext context, + String endpointName) { + RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( + context.getEnvironment(), this.prefix + endpointName + "."); + if (resolver.containsProperty("enabled")) { + boolean match = resolver.getProperty("enabled", Boolean.class, true); + return new ConditionOutcome(match, + getEndpointElementOutcomeMessage(endpointName, match)); + } + return null; + } + + protected ConditionOutcome getDefaultEndpointsOutcome(ConditionContext context) { + RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( + context.getEnvironment(), this.prefix + "defaults."); + boolean match = Boolean.valueOf(resolver.getProperty("enabled", "true")); + return new ConditionOutcome(match, getDefaultEndpointElementOutcomeMessage(match)); + } + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledHealthIndicatorCondition.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledHealthIndicatorCondition.java index 4cbb0a369d..35bceaf1e4 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledHealthIndicatorCondition.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledHealthIndicatorCondition.java @@ -16,55 +16,28 @@ package org.springframework.boot.actuate.autoconfigure; -import org.springframework.boot.autoconfigure.condition.ConditionOutcome; -import org.springframework.boot.autoconfigure.condition.SpringBootCondition; -import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.context.annotation.Condition; -import org.springframework.context.annotation.ConditionContext; -import org.springframework.core.annotation.AnnotationAttributes; -import org.springframework.core.type.AnnotatedTypeMetadata; /** * {@link Condition} that checks if a health indicator is enabled. * * @author Stephane Nicoll */ -class OnEnabledHealthIndicatorCondition extends SpringBootCondition { +class OnEnabledHealthIndicatorCondition extends OnEnabledEndpointElementCondition { - private static final String ANNOTATION_CLASS = ConditionalOnEnabledHealthIndicator.class - .getName(); + OnEnabledHealthIndicatorCondition() { + super("management.health.", ConditionalOnEnabledHealthIndicator.class); + } @Override - public ConditionOutcome getMatchOutcome(ConditionContext context, - AnnotatedTypeMetadata metadata) { - AnnotationAttributes annotationAttributes = AnnotationAttributes - .fromMap(metadata.getAnnotationAttributes(ANNOTATION_CLASS)); - String endpointName = annotationAttributes.getString("value"); - ConditionOutcome outcome = getHealthIndicatorOutcome(context, endpointName); - if (outcome != null) { - return outcome; - } - return getDefaultIndicatorsOutcome(context); + protected String getEndpointElementOutcomeMessage(String name, boolean match) { + return "The health indicator " + name + " is " + (match ? "enabled" : "disabled"); } - private ConditionOutcome getHealthIndicatorOutcome(ConditionContext context, - String endpointName) { - RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( - context.getEnvironment(), "management.health." + endpointName + "."); - if (resolver.containsProperty("enabled")) { - boolean match = resolver.getProperty("enabled", Boolean.class, true); - return new ConditionOutcome(match, "The health indicator " + endpointName - + " is " + (match ? "enabled" : "disabled")); - } - return null; - } - - private ConditionOutcome getDefaultIndicatorsOutcome(ConditionContext context) { - RelaxedPropertyResolver resolver = new RelaxedPropertyResolver( - context.getEnvironment(), "management.health.defaults."); - boolean match = Boolean.valueOf(resolver.getProperty("enabled", "true")); - return new ConditionOutcome(match, "All default health indicators are " - + (match ? "enabled" : "disabled") + " by default"); + @Override + protected String getDefaultEndpointElementOutcomeMessage(boolean match) { + return "All default health indicators are " + (match ? "enabled" : "disabled") + + " by default"; } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledInfoContributorCondition.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledInfoContributorCondition.java new file mode 100644 index 0000000000..a591ce25a0 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEnabledInfoContributorCondition.java @@ -0,0 +1,42 @@ +/* + * Copyright 2012-2016 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 org.springframework.context.annotation.Condition; + +/** + * {@link Condition} that checks if a info indicator is enabled. + * + * @author Stephane Nicoll + */ +class OnEnabledInfoContributorCondition extends OnEnabledEndpointElementCondition { + + OnEnabledInfoContributorCondition() { + super("management.info.", ConditionalOnEnabledInfoContributor.class); + } + + @Override + protected String getEndpointElementOutcomeMessage(String name, boolean match) { + return "The info contributor " + name + " is " + (match ? "enabled" : "disabled"); + } + + @Override + protected String getDefaultEndpointElementOutcomeMessage(boolean match) { + return "All default info contributors are " + (match ? "enabled" : "disabled") + + " by default"; + } +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java index 0f8bd3d02f..d41fe6897f 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InfoEndpoint.java @@ -16,60 +16,56 @@ package org.springframework.boot.actuate.endpoint; +import java.util.Collections; +import java.util.List; import java.util.Map; import org.springframework.boot.actuate.info.Info; -import org.springframework.boot.actuate.info.InfoProvider; +import org.springframework.boot.actuate.info.InfoContributor; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.util.Assert; /** * {@link Endpoint} to expose arbitrary application information. * - * The information, which the {@link InfoEndpoint} can provide can be customized to - * display any information, however initially the info endpoint will provide git version - * information (if available) and environment information,whose entries are prefixed with - * info. - * - * In order to add additional information to the endpoint, one has to implement a class, - * which implements the {@link org.springframework.boot.actuate.info.InfoProvider} - * interface and register it in the application context. The InfoEndpoint will - * automatically pick it up, when it is being instantiated. - * - * The standard InfoProvider for GIT is registered as the scmInfoProvider, and the - * registration can be changed in case standard provider does not meet ones requirements. - * - * @see org.springframework.boot.actuate.info.ScmGitPropertiesInfoProvider - * @see org.springframework.boot.actuate.info.EnvironmentInfoProvider - * * @author Dave Syer * @author Meang Akira Tanaka + * @author Stephane Nicoll */ -@ConfigurationProperties(prefix = "endpoints.info", ignoreUnknownFields = false) +@ConfigurationProperties(prefix = "endpoints.info") public class InfoEndpoint extends AbstractEndpoint { - private final Map infoProviders; + private final List infoContributors; /** * Create a new {@link InfoEndpoint} instance. - * - * @param infoProviders the infoProviders to be used + * @param infoContributors the info contributors to use */ - public InfoEndpoint(Map infoProviders) { + public InfoEndpoint(List infoContributors) { super("info", false); - Assert.notNull(infoProviders, "Info providers must not be null"); - this.infoProviders = infoProviders; + Assert.notNull(infoContributors, "Info contributors must not be null"); + this.infoContributors = infoContributors; } + @SuppressWarnings("deprecation") @Override public Info invoke() { - Info result = new Info(); - for (InfoProvider provider : this.infoProviders.values()) { - Info info = provider.provide(); - if (info != null) { - result.put(provider.name(), info); - } + Info.Builder builder = new Info.Builder(); + for (InfoContributor contributor : this.infoContributors) { + contributor.contribute(builder); } - return result; + builder.withDetails(getAdditionalInfo()); + return builder.build(); } + + /** + * Return additional information to include in the output. + * @return additional information + * @deprecated define an additional {@link InfoContributor} bean instead. + */ + @Deprecated + protected Map getAdditionalInfo() { + return Collections.emptyMap(); + } + } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/AbstractEnvironmentInfoContributor.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/AbstractEnvironmentInfoContributor.java new file mode 100644 index 0000000000..d529969baf --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/AbstractEnvironmentInfoContributor.java @@ -0,0 +1,78 @@ +/* + * Copyright 2012-2016 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.info; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.boot.bind.PropertiesConfigurationFactory; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; +import org.springframework.validation.BindException; + +/** + * A base {@link InfoContributor} implementation working on the {@link Environment}. + * + * @author Stephane Nicoll + * @since 1.4.0 + */ +public abstract class AbstractEnvironmentInfoContributor implements InfoContributor { + + private final ConfigurableEnvironment environment; + + protected AbstractEnvironmentInfoContributor(ConfigurableEnvironment environment) { + this.environment = environment; + } + + public final ConfigurableEnvironment getEnvironment() { + return this.environment; + } + + + /** + * Extract the keys from the environment using the specified {@code prefix}. The + * prefix won't be included. + *

Any key that starts with the {@code prefix} will be included + * @param prefix the prefix to use + * @return the keys from the environment matching the prefix + */ + protected Map extract(String prefix) { + Map content = new LinkedHashMap(); + bindEnvironmentTo(prefix, content); + return content; + } + + /** + * Bind the specified {@code target} from the environment using the {@code prefix}. + *

Any key that starts with the {@code prefix} will be bound to the {@code target}. + * @param prefix the prefix to use + * @param target the object to bind to + */ + protected void bindEnvironmentTo(String prefix, Object target) { + PropertiesConfigurationFactory factory = + new PropertiesConfigurationFactory(target); + factory.setTargetName(prefix); + factory.setPropertySources(this.environment.getPropertySources()); + try { + factory.bindPropertiesToTarget(); + } + catch (BindException ex) { + throw new IllegalStateException("Cannot bind to " + target, ex); + } + } + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoContributor.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoContributor.java new file mode 100644 index 0000000000..9d34a4212d --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoContributor.java @@ -0,0 +1,45 @@ +/* + * Copyright 2012-2015 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.info; + +import java.util.Map; + +import org.springframework.core.env.ConfigurableEnvironment; + +/** + * A {@link InfoContributor} that provides all environment entries prefixed with + * info. + * + * @author Meang Akira Tanaka + * @author Stephane Nicoll + * @since 1.4.0 + */ +public class EnvironmentInfoContributor extends AbstractEnvironmentInfoContributor { + + private final Map info; + + public EnvironmentInfoContributor(ConfigurableEnvironment environment) { + super(environment); + this.info = extract("info"); + } + + @Override + public void contribute(Info.Builder builder) { + builder.withDetails(this.info); + } + +} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoProvider.java deleted file mode 100644 index 062f8d75eb..0000000000 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoProvider.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2012-2015 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.info; - -import java.util.LinkedHashMap; -import java.util.Map; - -import org.springframework.boot.bind.PropertiesConfigurationFactory; -import org.springframework.core.env.ConfigurableEnvironment; - -/** - * A {@link InfoProvider} that provides all environment entries prefixed with - * info. - * - * @author Meang Akira Tanaka - * @since 1.3.0 - */ -public class EnvironmentInfoProvider implements InfoProvider { - - private final ConfigurableEnvironment environment; - - private final Info info; - - public EnvironmentInfoProvider(ConfigurableEnvironment environment) throws Exception { - this.environment = environment; - this.info = new Info(extractInfoFromEnvironment()); - } - - @Override - public String name() { - return "environment"; - } - - @Override - public Info provide() { - return this.info; - } - - private Map extractInfoFromEnvironment() throws Exception { - PropertiesConfigurationFactory> factory = new PropertiesConfigurationFactory>( - new LinkedHashMap()); - factory.setTargetName("info"); - factory.setPropertySources(this.environment.getPropertySources()); - return factory.getObject(); - } -} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/Info.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/Info.java index 064e966685..1895eff417 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/Info.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/Info.java @@ -16,7 +16,7 @@ package org.springframework.boot.actuate.info; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import com.fasterxml.jackson.annotation.JsonAnyGetter; @@ -24,22 +24,23 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; /** - * Carries information from a specific info provider. + * Carries information of the application. + *

+ * Each detail element can singular or a hierarchical object such as a pojo or a nested + * Map. * * @author Meang Akira Tanaka - * @since 1.3.0 - * @see org.springframework.boot.actuate.endpoint.InfoEndpoint + * @author Stephane Nicoll + * @since 1.4.0 */ @JsonInclude(Include.NON_EMPTY) public final class Info { - private final Map details = new HashMap(); + private final Map details; - public Info() { - } - - public Info(Map details) { - this.details.putAll(details); + private Info(Builder builder) { + this.details = new LinkedHashMap(); + this.details.putAll(builder.content); } /** @@ -51,13 +52,17 @@ public final class Info { return this.details; } - public void put(String infoId, Object value) { - this.details.put(infoId, value); + public Object get(String id) { + return this.details.get(id); } @SuppressWarnings("unchecked") - public T get(String infoId) { - return (T) this.details.get(infoId); + public T get(String id, Class type) { + Object value = get(id); + if (value != null && type != null && !type.isInstance(value)) { + throw new IllegalStateException("Info entry is not of required type [" + type.getName() + "]: " + value); + } + return (T) value; } @Override @@ -81,4 +86,47 @@ public final class Info { public String toString() { return getDetails().toString(); } + + /** + * Builder for creating immutable {@link Info} instances. + */ + public static class Builder { + + private final Map content; + + public Builder() { + this.content = new LinkedHashMap(); + } + + /** + * Record detail using {@code key} and {@code value}. + * @param key the detail key + * @param data the detail data + * @return this {@link Builder} instance + */ + public Builder withDetail(String key, Object data) { + this.content.put(key, data); + return this; + } + + /** + * Record several details. + * @param details the details + * @return this {@link Builder} instance + * @see #withDetail(String, Object) + */ + public Builder withDetails(Map details) { + this.content.putAll(details); + return this; + } + + /** + * Create a new {@link Info} instance base on the state of this builder. + * @return a new {@link Info} instance + */ + public Info build() { + return new Info(this); + } + + } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoContributor.java similarity index 71% rename from spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoProvider.java rename to spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoContributor.java index 1a76553676..f4c7628e75 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoProvider.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoContributor.java @@ -17,18 +17,17 @@ package org.springframework.boot.actuate.info; /** - * information provider for the info endpoint. + * Contributes additional info details. * - * @author Meang Akira Tanaka + * @author Stephane Nicoll + * @since 1.4.0 */ -public interface InfoProvider { - - String name(); +public interface InfoContributor { /** - * Return the {@link Info} instance. - * @return a collection of information + * Contributes additional details using the specified {@link Info.Builder Builder}. + * @param builder the builder to use */ - Info provide(); + void contribute(Info.Builder builder); } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProvider.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProvider.java deleted file mode 100644 index 8b12488b7b..0000000000 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProvider.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2012-2016 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.info; - -import java.util.Properties; - -import org.springframework.boot.bind.PropertiesConfigurationFactory; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PropertiesLoaderUtils; - -/** - * A {@link InfoProvider} that provides git information extracted from the - * git.properties file generated by the maven plugin - * pl.project13.maven:git-commit-id-plugin. - * - * @author Meang Akira Tanaka - * @since 1.3.0 - */ -public class ScmGitPropertiesInfoProvider implements InfoProvider { - - private final Resource gitPropertiesResource; - - private final GitInfo gitInfo; - - public ScmGitPropertiesInfoProvider(Resource gitPropertiesResource) throws Exception { - this.gitPropertiesResource = gitPropertiesResource; - this.gitInfo = extractGitInfo(); - } - - @Override - public String name() { - return "git"; - } - - @Override - public Info provide() { - if (this.gitInfo == null) { - return null; - } - - Info result = new Info(); - - result.put("branch", this.gitInfo.getBranch()); - result.put("commit", this.gitInfo.getCommit()); - - return result; - } - - - private GitInfo extractGitInfo() throws Exception { - PropertiesConfigurationFactory factory = new PropertiesConfigurationFactory( - new GitInfo()); - factory.setTargetName("git"); - Properties properties = new Properties(); - if (this.gitPropertiesResource.exists()) { - properties = PropertiesLoaderUtils.loadProperties(this.gitPropertiesResource); - } - else { - return null; - } - factory.setProperties(properties); - return factory.getObject(); - } - - - /** - * Git info. - */ - public static class GitInfo { - - private String branch; - - private final Commit commit = new Commit(); - - public String getBranch() { - return this.branch; - } - - public void setBranch(String branch) { - this.branch = branch; - } - - public Commit getCommit() { - return this.commit; - } - - /** - * Commit information. - */ - public static class Commit { - - private String id; - - private String time; - - public String getId() { - return this.id == null ? "" - : (this.id.length() > 7 ? this.id.substring(0, 7) : this.id); - } - - public void setId(String id) { - this.id = id; - } - - public String getTime() { - return this.time; - } - - public void setTime(String time) { - this.time = time; - } - - } - - } -} diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/SimpleInfoContributor.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/SimpleInfoContributor.java new file mode 100644 index 0000000000..b6bd85cc19 --- /dev/null +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/SimpleInfoContributor.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2016 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.info; + +import org.springframework.util.Assert; + +/** + * A simple {@link InfoContributor} that exposes a single detail. + * + * @author Stephane Nicoll + * @since 1.4.0 + */ +public class SimpleInfoContributor implements InfoContributor { + + private final String prefix; + + private final Object detail; + + public SimpleInfoContributor(String prefix, Object detail) { + Assert.notNull(prefix, "Prefix must not be null"); + this.prefix = prefix; + this.detail = detail; + } + + @Override + public void contribute(Info.Builder builder) { + if (this.detail != null) { + builder.withDetail(this.prefix, this.detail); + } + } + +} diff --git a/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json index fd726b13c2..674c2c69da 100644 --- a/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -123,6 +123,24 @@ "description": "Enable Mail health check.", "defaultValue": true }, + { + "name": "management.info.defaults.enabled", + "type": "java.lang.Boolean", + "description": "Enable default info contributors.", + "defaultValue": true + }, + { + "name": "management.info.env.enabled", + "type": "java.lang.Boolean", + "description": "Enable environment info.", + "defaultValue": true + }, + { + "name": "management.info.git.enabled", + "type": "java.lang.Boolean", + "description": "Enable git info.", + "defaultValue": true + }, { "name": "spring.git.properties", "type": "java.lang.String", diff --git a/spring-boot-actuator/src/main/resources/META-INF/spring.factories b/spring-boot-actuator/src/main/resources/META-INF/spring.factories index 40a1efafd0..41a4f14ced 100644 --- a/spring-boot-actuator/src/main/resources/META-INF/spring.factories +++ b/spring-boot-actuator/src/main/resources/META-INF/spring.factories @@ -6,7 +6,7 @@ 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.InfoProviderAutoConfiguration,\ +org.springframework.boot.actuate.autoconfigure.InfoContributorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.JolokiaAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.ManagementWebSecurityAutoConfiguration,\ diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java index b42bb062ca..0c3eab8261 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java @@ -16,9 +16,12 @@ package org.springframework.boot.actuate.autoconfigure; +import java.io.IOException; import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.Properties; import org.junit.After; import org.junit.Test; @@ -37,16 +40,24 @@ import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint; import org.springframework.boot.actuate.endpoint.ShutdownEndpoint; import org.springframework.boot.actuate.endpoint.TraceEndpoint; import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.info.Info; +import org.springframework.boot.actuate.info.InfoContributor; import org.springframework.boot.actuate.metrics.Metric; import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport; import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; import org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration; +import org.springframework.boot.autoconfigure.info.ProjectInfoProperties; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; +import org.springframework.boot.bind.PropertiesConfigurationFactory; import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PropertiesLoaderUtils; +import org.springframework.validation.BindException; import static org.assertj.core.api.Assertions.assertThat; @@ -139,10 +150,11 @@ public class EndpointAutoConfigurationTests { } @Test - public void testInfoEndpointConfiguration() throws Exception { + public void testInfoEndpoint() throws Exception { this.context = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(this.context, "info.foo:bar"); - this.context.register(ProjectInfoAutoConfiguration.class, EndpointAutoConfiguration.class); + this.context.register(ProjectInfoAutoConfiguration.class, + InfoContributorAutoConfiguration.class, EndpointAutoConfiguration.class); this.context.refresh(); InfoEndpoint endpoint = this.context.getBean(InfoEndpoint.class); @@ -152,17 +164,34 @@ public class EndpointAutoConfigurationTests { } @Test - public void testNoGitProperties() throws Exception { + public void testInfoEndpointNoGitProperties() throws Exception { this.context = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(this.context, "spring.info.git.location:classpath:nonexistent"); - this.context.register(EndpointAutoConfiguration.class); + this.context.register(InfoContributorAutoConfiguration.class, EndpointAutoConfiguration.class); this.context.refresh(); InfoEndpoint endpoint = this.context.getBean(InfoEndpoint.class); assertThat(endpoint).isNotNull(); assertThat(endpoint.invoke().get("git")).isNull(); } + @Test + public void testInfoEndpointOrdering() throws Exception { + this.context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, "info.name:foo"); + this.context.register(CustomInfoContributorsConfig.class, ProjectInfoAutoConfiguration.class, + InfoContributorAutoConfiguration.class, EndpointAutoConfiguration.class); + this.context.refresh(); + + InfoEndpoint endpoint = this.context.getBean(InfoEndpoint.class); + Info info = endpoint.invoke(); + assertThat(info).isNotNull(); + assertThat(info.get("name")).isEqualTo("foo"); + assertThat(info.get("version")).isEqualTo("1.0"); + Object git = info.get("git"); + assertThat(git).isInstanceOf(Map.class); + } + @Test public void testFlywayEndpoint() { this.context = new AnnotationConfigApplicationContext(); @@ -206,4 +235,53 @@ public class EndpointAutoConfigurationTests { } } + + @Configuration + static class CustomInfoContributorsConfig { + + @Bean + @Order(InfoContributorAutoConfiguration.DEFAULT_ORDER - 1) + public InfoContributor myInfoContributor() { + return new InfoContributor() { + @Override + public void contribute(Info.Builder builder) { + builder.withDetail("name", "bar"); + builder.withDetail("version", "1.0"); + } + }; + } + + @Bean + @Order(InfoContributorAutoConfiguration.DEFAULT_ORDER + 1) + public InfoContributor myAnotherContributor(ProjectInfoProperties properties) + throws IOException, BindException { + return new GitFullInfoContributor(properties.getGit().getLocation()); + } + + private static class GitFullInfoContributor implements InfoContributor { + + private final Map content; + + GitFullInfoContributor(Resource location) throws BindException, IOException { + this.content = new LinkedHashMap(); + if (location.exists()) { + PropertiesConfigurationFactory> factory + = new PropertiesConfigurationFactory>(this.content); + factory.setTargetName("git"); + Properties gitInfoProperties = PropertiesLoaderUtils + .loadProperties(location); + factory.setProperties(gitInfoProperties); + factory.bindPropertiesToTarget(); + } + } + + @Override + public void contribute(Info.Builder builder) { + if (!this.content.isEmpty()) { + builder.withDetail("git", this.content); + } + } + } + + } } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/InfoContributorAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/InfoContributorAutoConfigurationTests.java new file mode 100644 index 0000000000..0f0c5cfb57 --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/InfoContributorAutoConfigurationTests.java @@ -0,0 +1,125 @@ +/* + * Copyright 2012-2016 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.Test; + +import org.springframework.boot.actuate.info.Info; +import org.springframework.boot.actuate.info.InfoContributor; +import org.springframework.boot.autoconfigure.info.GitInfo; +import org.springframework.boot.test.EnvironmentTestUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link InfoContributorAutoConfiguration}. + * + * @author Stephane Nicoll + */ +public class InfoContributorAutoConfigurationTests { + + private AnnotationConfigApplicationContext context; + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void disableEnvContributor() { + load("management.info.env.enabled:false"); + Map beans = this.context + .getBeansOfType(InfoContributor.class); + assertThat(beans).hasSize(0); + } + + @Test + public void defaultInfoContributorsDisabled() { + load("management.info.defaults.enabled:false"); + Map beans = this.context + .getBeansOfType(InfoContributor.class); + assertThat(beans).hasSize(0); + } + + @Test + public void defaultInfoContributorsDisabledWithCustomOne() { + load(CustomInfoProviderConfiguration.class, + "management.info.defaults.enabled:false"); + Map beans = this.context + .getBeansOfType(InfoContributor.class); + assertThat(beans).hasSize(1); + assertThat(this.context.getBean("customInfoContributor")) + .isSameAs(beans.values().iterator().next()); + } + + @Test + public void gitInfoAvailable() { + load(GitInfoConfiguration.class); + Map beans = this.context + .getBeansOfType(InfoContributor.class); + assertThat(beans).containsKeys("gitInfoContributor"); + } + + private void load(String... environment) { + load(null, environment); + } + + private void load(Class config, String... environment) { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + if (config != null) { + context.register(config); + } + context.register(InfoContributorAutoConfiguration.class); + EnvironmentTestUtils.addEnvironment(context, environment); + context.refresh(); + this.context = context; + } + + @Configuration + static class GitInfoConfiguration { + + @Bean + public GitInfo gitInfo() { + GitInfo gitInfo = new GitInfo(); + gitInfo.setBranch("master"); + gitInfo.getCommit().setId("abcdefg"); + return gitInfo; + } + } + + @Configuration + static class CustomInfoProviderConfiguration { + + @Bean + public InfoContributor customInfoContributor() { + return new InfoContributor() { + @Override + public void contribute(Info.Builder builder) { + } + }; + } + } + +} diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java index b88294eb0a..29306e73dd 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InfoEndpointTests.java @@ -16,12 +16,12 @@ package org.springframework.boot.actuate.endpoint; -import java.util.Map; +import java.util.List; import org.junit.Test; import org.springframework.boot.actuate.info.Info; -import org.springframework.boot.actuate.info.InfoProvider; +import org.springframework.boot.actuate.info.InfoContributor; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -43,7 +43,7 @@ public class InfoEndpointTests extends AbstractEndpointTests { @Test public void invoke() throws Exception { - Info actual = getEndpointBean().invoke().get("environment"); + Info actual = getEndpointBean().invoke(); assertThat(actual.get("key1")).isEqualTo("value1"); } @@ -52,29 +52,22 @@ public class InfoEndpointTests extends AbstractEndpointTests { public static class Config { @Bean - public InfoProvider infoProvider() { - return new InfoProvider() { + public InfoContributor infoProvider() { + return new InfoContributor() { @Override - public String name() { - return "environment"; - } - - @Override - public Info provide() { - Info result = new Info(); - result.put("key1", "value1"); - - return result; + public void contribute(Info.Builder builder) { + builder.withDetail("key1", "value1"); } }; } - @Bean - public InfoEndpoint endpoint(Map infoProviders) { - return new InfoEndpoint(infoProviders); + public InfoEndpoint endpoint(List infoContributors) { + return new InfoEndpoint(infoContributors); } + } + } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointTests.java index d122c6621c..6cb5d009c3 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointTests.java @@ -16,9 +16,10 @@ package org.springframework.boot.actuate.endpoint.mvc; +import java.util.Arrays; +import java.util.LinkedHashMap; import java.util.Map; -import org.elasticsearch.common.collect.Maps; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -29,7 +30,7 @@ import org.springframework.boot.actuate.autoconfigure.ManagementServerProperties import org.springframework.boot.actuate.endpoint.InfoEndpoint; import org.springframework.boot.actuate.endpoint.mvc.InfoMvcEndpointTests.TestConfiguration; import org.springframework.boot.actuate.info.Info; -import org.springframework.boot.actuate.info.InfoProvider; +import org.springframework.boot.actuate.info.InfoContributor; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; @@ -53,6 +54,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. * Tests for {@link InfoMvcEndpointTests} * * @author Meang Akira Tanaka + * @author Stephane Nicoll */ @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = {TestConfiguration.class}) @@ -75,8 +77,10 @@ public class InfoMvcEndpointTests { public void home() throws Exception { this.mvc.perform(get("/info")).andExpect(status().isOk()) .andExpect(content().string( - containsString("\"beanName2\":{\"key22\":\"value22\",\"key21\":\"value21\"}," + - "\"beanName1\":{\"key12\":\"value12\",\"key11\":\"value11\"}"))); + containsString("\"beanName1\":{\"key11\":\"value11\",\"key12\":\"value12\"}") + )) + .andExpect(content().string( + containsString("\"beanName2\":{\"key21\":\"value21\",\"key22\":\"value22\"}"))); } @Import({JacksonAutoConfiguration.class, @@ -87,47 +91,36 @@ public class InfoMvcEndpointTests { @Configuration public static class TestConfiguration { - private Map infoProviders = Maps.newHashMap(); - - public TestConfiguration() { - InfoProvider infoProvider1 = new InfoProvider() { - - @Override - public Info provide() { - Info result = new Info(); - result.put("key11", "value11"); - result.put("key12", "value12"); - return result; - } - - @Override - public String name() { - return "beanName1"; - } - }; - this.infoProviders.put("beanName1", infoProvider1); - - InfoProvider infoProvider2 = new InfoProvider() { - - @Override - public Info provide() { - Info result = new Info(); - result.put("key21", "value21"); - result.put("key22", "value22"); - return result; - } - - @Override - public String name() { - return "beanName2"; - } - }; - this.infoProviders.put("beanName2", infoProvider2); + @Bean + public InfoEndpoint endpoint() { + return new InfoEndpoint(Arrays.asList(beanName1(), beanName2())); } @Bean - public InfoEndpoint endpoint() { - return new InfoEndpoint(this.infoProviders); + public InfoContributor beanName1() { + return new InfoContributor() { + + @Override + public void contribute(Info.Builder builder) { + Map content = new LinkedHashMap(); + content.put("key11", "value11"); + content.put("key12", "value12"); + builder.withDetail("beanName1", content); + } + }; + } + + @Bean + public InfoContributor beanName2() { + return new InfoContributor() { + @Override + public void contribute(Info.Builder builder) { + Map content = new LinkedHashMap(); + content.put("key21", "value21"); + content.put("key22", "value22"); + builder.withDetail("beanName2", content); + } + }; } } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointWithoutAnyInfoProvidersTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointWithoutAnyInfoProvidersTests.java index 9cb7bc6e9f..8d48d92c35 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointWithoutAnyInfoProvidersTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/InfoMvcEndpointWithoutAnyInfoProvidersTests.java @@ -16,9 +16,8 @@ package org.springframework.boot.actuate.endpoint.mvc; -import java.util.Map; +import java.util.Collections; -import org.elasticsearch.common.collect.Maps; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -28,7 +27,7 @@ import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfigur import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration; import org.springframework.boot.actuate.endpoint.InfoEndpoint; import org.springframework.boot.actuate.endpoint.mvc.InfoMvcEndpointWithoutAnyInfoProvidersTests.TestConfiguration; -import org.springframework.boot.actuate.info.InfoProvider; +import org.springframework.boot.actuate.info.InfoContributor; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; @@ -79,11 +78,9 @@ public class InfoMvcEndpointWithoutAnyInfoProvidersTests { @Configuration public static class TestConfiguration { - private Map infoProviders = Maps.newHashMap(); - @Bean public InfoEndpoint endpoint() { - return new InfoEndpoint(this.infoProviders); + return new InfoEndpoint(Collections.emptyList()); } } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoContributorTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoContributorTests.java new file mode 100644 index 0000000000..5b1d460d14 --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoContributorTests.java @@ -0,0 +1,60 @@ +/* + * Copyright 2012-2016 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.info; + +import org.junit.Test; + +import org.springframework.boot.test.EnvironmentTestUtils; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.StandardEnvironment; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link EnvironmentInfoContributor} + */ +public class EnvironmentInfoContributorTests { + + private final StandardEnvironment environment = new StandardEnvironment(); + + @Test + public void extractOnlyInfoProperty() { + EnvironmentTestUtils.addEnvironment(this.environment, + "info.app=my app", "info.version=1.0.0", "foo=bar"); + + Info actual = contributeFrom(this.environment); + assertThat(actual.get("app", String.class)).isEqualTo("my app"); + assertThat(actual.get("version", String.class)).isEqualTo("1.0.0"); + assertThat(actual.getDetails().size()).isEqualTo(2); + } + + @Test + public void extractNoEntry() { + EnvironmentTestUtils.addEnvironment(this.environment, "foo=bar"); + + Info actual = contributeFrom(this.environment); + assertThat(actual.getDetails().size()).isEqualTo(0); + } + + private static Info contributeFrom(ConfigurableEnvironment environment) { + EnvironmentInfoContributor contributor = new EnvironmentInfoContributor(environment); + Info.Builder builder = new Info.Builder(); + contributor.contribute(builder); + return builder.build(); + } + +} diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoProviderTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoProviderTests.java deleted file mode 100644 index e9d775ada1..0000000000 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoProviderTests.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2012-2016 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.info; - -import java.util.Properties; - -import org.junit.Test; - -import org.springframework.core.env.PropertiesPropertySource; -import org.springframework.core.env.PropertySource; -import org.springframework.core.env.StandardEnvironment; - -import static org.assertj.core.api.Assertions.assertThat; - -public class EnvironmentInfoProviderTests { - - @Test - public void provide_HasTwoRelevantEntries_ShowOnlyRelevantEntries() throws Exception { - String expectedAppName = "my app name"; - String expectedLanguage = "da-DK"; - - Properties properties = new Properties(); - properties.setProperty("info.app", expectedAppName); - properties.setProperty("info.lang", expectedLanguage); - properties.setProperty("logging.path", "notExpected"); - - PropertySource propertySource = new PropertiesPropertySource("mysettings", properties); - - StandardEnvironment environment = new StandardEnvironment(); - environment.getPropertySources().addLast(propertySource); - - EnvironmentInfoProvider environmentInfoProvider = new EnvironmentInfoProvider(environment); - - Info actual = environmentInfoProvider.provide(); - assertThat(actual.getDetails().size()).isEqualTo(2); - assertThat((String) actual.get("app")).isEqualTo(expectedAppName); - assertThat((String) actual.get("lang")).isEqualTo(expectedLanguage); - } - - @Test - public void provide_HasNoRelevantEntries_NoEntries() throws Exception { - Properties properties = new Properties(); - properties.setProperty("logging.path", "notExpected"); - - PropertySource propertySource = new PropertiesPropertySource("mysettings", properties); - - StandardEnvironment environment = new StandardEnvironment(); - environment.getPropertySources().addLast(propertySource); - - EnvironmentInfoProvider environmentInfoProvider = new EnvironmentInfoProvider(environment); - - Info actual = environmentInfoProvider.provide(); - assertThat(actual.getDetails().size()).isEqualTo(0); - } - - - @Test - public void provide_HasNoEntries_NoEntries() throws Exception { - EnvironmentInfoProvider environmentInfoProvider = new EnvironmentInfoProvider(new StandardEnvironment()); - - Info actual = environmentInfoProvider.provide(); - assertThat(actual.getDetails().size()).isEqualTo(0); - } - -} diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProviderTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProviderTests.java deleted file mode 100644 index 1a6dba7055..0000000000 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ScmGitPropertiesInfoProviderTests.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2012-2016 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.info; - -import org.junit.Test; - -import org.springframework.boot.actuate.info.ScmGitPropertiesInfoProvider.GitInfo.Commit; -import org.springframework.core.io.ByteArrayResource; -import org.springframework.core.io.Resource; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -public class ScmGitPropertiesInfoProviderTests { - - - @Test - public void provide_HasBadFormatButExists_EmptyInfoReturned() throws Exception { - Resource resource = new ByteArrayResource("GARBAGE".getBytes()); - ScmGitPropertiesInfoProvider scmGitPropertiesInfoProvider = new ScmGitPropertiesInfoProvider(resource); - - Info actual = scmGitPropertiesInfoProvider.provide(); - assertThat(actual).isNotNull(); - assertThat((String) actual.get("branch")).isNull(); - Commit actualCommit = actual.get("commit"); - assertThat(actualCommit).isNotNull(); - assertThat(actualCommit.getId()).isEqualTo(""); - assertThat(actualCommit.getTime()).isNull(); - } - - @Test - public void provide_HasValidFormat_ExpectedDataReturned() throws Exception { - String gitProperties = "git.commit.id.abbrev=e02a4f3\r\n" - + "git.commit.user.email=dsyer@vmware.com\r\n" - + "git.commit.message.full=Update Spring\r\n" - + "git.commit.id=e02a4f3b6f452cdbf6dd311f1362679eb4c31ced\r\n" - + "git.commit.message.short=Update Spring\r\n" - + "git.commit.user.name=Dave Syer\r\n" - + "git.build.user.name=Dave Syer\r\n" - + "git.build.user.email=dsyer@vmware.com\r\n" - + "git.branch=develop\r\n" - + "git.commit.time=2013-04-24T08\\:42\\:13+0100\r\n" - + "git.build.time=2013-05-23T09\\:26\\:42+0100\r\n"; - - Resource resource = new ByteArrayResource(gitProperties.getBytes()); - ScmGitPropertiesInfoProvider scmGitPropertiesInfoProvider = new ScmGitPropertiesInfoProvider(resource); - - Info actual = scmGitPropertiesInfoProvider.provide(); - assertThat(actual).isNotNull(); - assertThat((String) actual.get("branch")).isEqualTo("develop"); - Commit actualCommit = actual.get("commit"); - assertThat(actualCommit).isNotNull(); - assertThat(actualCommit.getId()).isEqualTo("e02a4f3"); - assertThat(actualCommit.getTime()).isEqualTo("2013-04-24T08:42:13+0100"); - } - - - @Test - public void provide_HasValidFormatButMissingCommitTime_ExpectedDataReturnedWithoutCommitTime() throws Exception { - String gitProperties = "git.commit.id.abbrev=e02a4f3\r\n" - + "git.commit.user.email=dsyer@vmware.com\r\n" - + "git.commit.message.full=Update Spring\r\n" - + "git.commit.id=e02a4f3b6f452cdbf6dd311f1362679eb4c31ced\r\n" - + "git.commit.message.short=Update Spring\r\n" - + "git.commit.user.name=Dave Syer\r\n" - + "git.build.user.name=Dave Syer\r\n" - + "git.build.user.email=dsyer@vmware.com\r\n" - + "git.branch=develop\r\n" - + "git.build.time=2013-05-23T09\\:26\\:42+0100\r\n"; - - Resource resource = new ByteArrayResource(gitProperties.getBytes()); - ScmGitPropertiesInfoProvider scmGitPropertiesInfoProvider = new ScmGitPropertiesInfoProvider(resource); - - Info actual = scmGitPropertiesInfoProvider.provide(); - assertThat(actual).isNotNull(); - assertThat((String) actual.get("branch")).isEqualTo("develop"); - Commit actualCommit = (Commit) actual.get("commit"); - assertThat(actualCommit).isNotNull(); - assertThat(actualCommit.getId()).isEqualTo("e02a4f3"); - assertThat(actualCommit.getTime()).isNull(); - } - - @Test - public void provide_DoesNotExists_NullReturned() throws Exception { - Resource resource = mock(Resource.class); - given(resource.exists()).willReturn(false); - ScmGitPropertiesInfoProvider scmGitPropertiesInfoProvider = new ScmGitPropertiesInfoProvider(resource); - - Info actual = scmGitPropertiesInfoProvider.provide(); - assertThat(actual).isNull(); - } - -} diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/SimpleInfoContributorTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/SimpleInfoContributorTests.java new file mode 100644 index 0000000000..9b75e4f7b3 --- /dev/null +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/SimpleInfoContributorTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012-2016 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.info; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link SimpleInfoContributor}. + * + * @author Stephane Nicoll + */ +public class SimpleInfoContributorTests { + + @Rule + public final ExpectedException thrown = ExpectedException.none(); + + @Test + public void prefixIsMandatory() { + this.thrown.expect(IllegalArgumentException.class); + new SimpleInfoContributor(null, new Object()); + } + + @Test + public void mapSimpleObject() { + Object o = new Object(); + Info info = contributeFrom("test", o); + assertThat(info.get("test")).isSameAs(o); + } + + + private static Info contributeFrom(String prefix, Object detail) { + SimpleInfoContributor contributor = new SimpleInfoContributor(prefix, detail); + Info.Builder builder = new Info.Builder(); + contributor.contribute(builder); + return builder.build(); + } + +} diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 94dd7e1899..7670bbba3f 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -884,6 +884,11 @@ content into your application; rather pick only the properties that you need. management.health.solr.enabled=true # Enable Solr health check. management.health.status.order=DOWN, OUT_OF_SERVICE, UNKNOWN, UP # Comma-separated list of health statuses in order of severity. + # INFO CONTRIBUTORS + management.info.defaults.enabled=true # Enable default health indicators. + management.info.env.enabled=true # Enable environment info. + management.info.git.enabled=true # Enable git info. + # TRACING (({sc-spring-boot-actuator}/trace/TraceProperties.{sc-ext}[TraceProperties]) management.trace.include=request-headers,response-headers,errors # Items to be included in the trace. diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoContributor.java b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoContributor.java new file mode 100644 index 0000000000..4d976d6930 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoContributor.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012-2016 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 sample.actuator; + +import java.util.Collections; + +import org.springframework.boot.actuate.info.Info; +import org.springframework.boot.actuate.info.InfoContributor; +import org.springframework.stereotype.Component; + +@Component +public class ExampleInfoContributor implements InfoContributor { + + @Override + public void contribute(Info.Builder builder) { + builder.withDetail("example", + Collections.singletonMap("someKey", "someValue")); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoProvider.java b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoProvider.java deleted file mode 100644 index 822d5b8d33..0000000000 --- a/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleInfoProvider.java +++ /dev/null @@ -1,21 +0,0 @@ -package sample.actuator; - -import org.springframework.boot.actuate.info.Info; -import org.springframework.boot.actuate.info.InfoProvider; -import org.springframework.stereotype.Component; - -@Component -public class ExampleInfoProvider implements InfoProvider { - - @Override - public Info provide() { - Info result = new Info(); - result.put("somekey", "somevalue"); - return result; - } - - @Override - public String name() { - return "example"; - } -} diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java index 2277acbfc3..436b564db6 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java @@ -45,6 +45,7 @@ import static org.assertj.core.api.Assertions.assertThat; * Basic integration tests for service demo application. * * @author Dave Syer + * @author Stephane Nicoll */ @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(SampleActuatorApplication.class) @@ -145,6 +146,8 @@ public class SampleActuatorApplicationTests { assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(entity.getBody()) .contains("\"artifact\":\"spring-boot-sample-actuator\""); + assertThat(entity.getBody()) + .contains("\"someKey\":\"someValue\""); } @Test