Browse Source
This commit introduces a new property to globally disable metrics export. In integration tests, this property is automatically set to disable everything but in-memory metrics. This commit also introduces a `@AutoConfigureMetrics` annotation that can be used for integration tests that require metrics export to operate as they would in an application. See gh-21658pull/22571/head
48 changed files with 706 additions and 74 deletions
@ -0,0 +1,52 @@
@@ -0,0 +1,52 @@
|
||||
/* |
||||
* Copyright 2012-2019 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 |
||||
* |
||||
* https://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.metrics.export.condition; |
||||
|
||||
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 @Conditional} that checks whether or not a particular metrics |
||||
* exporter is enabled. If the {@code management.metrics.export.<name>.enabled} property |
||||
* is configured then its value is used to determine if it matches. Otherwise, matches if |
||||
* the value of the {@code management.metrics.export.enabled} property is {@code true} or |
||||
* if it is not configured. |
||||
* |
||||
* @author Chris Bono |
||||
* @since 2.4.0 |
||||
*/ |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Target({ ElementType.TYPE, ElementType.METHOD }) |
||||
@Documented |
||||
@Conditional(OnMetricsExportEnabledCondition.class) |
||||
public @interface ConditionalOnEnabledMetricsExport { |
||||
|
||||
/** |
||||
* The name of the metrics exporter, typically derived from the name of the |
||||
* corresponding auto-configuration class which follows the typical naming scheme of |
||||
* {@code <name>MetricsExportAutoConfiguration}. For example, the |
||||
* {@code DatadogMetricsExportAutoConfiguration} would have a name of 'datadog'. |
||||
* @return the name of the metrics exporter |
||||
*/ |
||||
String value(); |
||||
|
||||
} |
||||
@ -0,0 +1,75 @@
@@ -0,0 +1,75 @@
|
||||
/* |
||||
* Copyright 2012-2019 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 |
||||
* |
||||
* https://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.metrics.export.condition; |
||||
|
||||
import java.lang.annotation.Annotation; |
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage; |
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome; |
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition; |
||||
import org.springframework.context.annotation.ConditionContext; |
||||
import org.springframework.core.annotation.AnnotationAttributes; |
||||
import org.springframework.core.env.Environment; |
||||
import org.springframework.core.type.AnnotatedTypeMetadata; |
||||
|
||||
/** |
||||
* Metrics exporter enabled condition. All exporters can be disabled globally via the |
||||
* {@code management.metrics.export.enabled} property or individually via the |
||||
* {@code management.metrics.export.<name>.enabled} property (where {@code <name>} is the |
||||
* name of the exporter. |
||||
* |
||||
* @author Chris Bono |
||||
* @since 2.4.0 |
||||
*/ |
||||
public class OnMetricsExportEnabledCondition extends SpringBootCondition { |
||||
|
||||
private static final String PREFIX = "management.metrics.export"; |
||||
|
||||
private static final Class<? extends Annotation> ANNOTATION_TYPE = ConditionalOnEnabledMetricsExport.class; |
||||
|
||||
@Override |
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { |
||||
AnnotationAttributes annotationAttributes = AnnotationAttributes |
||||
.fromMap(metadata.getAnnotationAttributes(this.ANNOTATION_TYPE.getName())); |
||||
String exporterName = annotationAttributes.getString("value"); |
||||
ConditionOutcome outcome = getSpecificExporterOutcome(context, exporterName); |
||||
if (outcome != null) { |
||||
return outcome; |
||||
} |
||||
return getGlobalExporterOutcome(context); |
||||
} |
||||
|
||||
protected ConditionOutcome getSpecificExporterOutcome(ConditionContext context, String exporterName) { |
||||
Environment environment = context.getEnvironment(); |
||||
String enabledProperty = String.format("%s.%s.enabled", this.PREFIX, exporterName); |
||||
if (!environment.containsProperty(enabledProperty)) { |
||||
return null; |
||||
} |
||||
boolean match = environment.getProperty(enabledProperty, Boolean.class); |
||||
return new ConditionOutcome(match, ConditionMessage.forCondition(this.ANNOTATION_TYPE) |
||||
.because(String.format("%s is %b", enabledProperty, match))); |
||||
} |
||||
|
||||
protected ConditionOutcome getGlobalExporterOutcome(ConditionContext context) { |
||||
Environment environment = context.getEnvironment(); |
||||
String enabledProperty = String.format("%s.enabled", this.PREFIX); |
||||
boolean match = environment.getProperty(enabledProperty, Boolean.class, true); |
||||
return new ConditionOutcome(match, ConditionMessage.forCondition(this.ANNOTATION_TYPE) |
||||
.because(String.format("%s is considered %b", enabledProperty, match))); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,63 @@
@@ -0,0 +1,63 @@
|
||||
/* |
||||
* Copyright 2012-2019 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 |
||||
* |
||||
* https://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.metrics.export.condition; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; |
||||
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; |
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link ConditionalOnEnabledMetricsExport} - uses the |
||||
* {@link SimpleMetricsExportAutoConfiguration} as the target for the conditional |
||||
* enablement to avoid creating a test export auto config. |
||||
* |
||||
* @author Chris Bono |
||||
*/ |
||||
class ConditonalOnEnabledMetricsExportAutoConfigurationTests { |
||||
|
||||
private ApplicationContextRunner contextRunner = new ApplicationContextRunner().with(MetricsRun.simple()); |
||||
|
||||
@Test |
||||
void exporterIsEnabledByDefault() { |
||||
this.contextRunner.run((context) -> assertThat(context).hasBean("simpleMeterRegistry")); |
||||
} |
||||
|
||||
@Test |
||||
void exporterCanBeSpecificallyDisabled() { |
||||
this.contextRunner.withPropertyValues("management.metrics.export.simple.enabled=false") |
||||
.run((context) -> assertThat(context).doesNotHaveBean("simpleMeterRegistry")); |
||||
} |
||||
|
||||
@Test |
||||
void exporterCanBeGloballyDisabled() { |
||||
this.contextRunner.withPropertyValues("management.metrics.export.enabled=false") |
||||
.run((context) -> assertThat(context).doesNotHaveBean("simpleMeterRegistry")); |
||||
} |
||||
|
||||
@Test |
||||
void exporterCanBeGloballyDisabledWitSpecificOverride() { |
||||
this.contextRunner |
||||
.withPropertyValues("management.metrics.export.enabled=false", |
||||
"management.metrics.export.simple.enabled=true") |
||||
.run((context) -> assertThat(context).hasBean("simpleMeterRegistry")); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,39 @@
@@ -0,0 +1,39 @@
|
||||
/* |
||||
* Copyright 2012-2019 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 |
||||
* |
||||
* https://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.test.autoconfigure.metrics; |
||||
|
||||
import java.lang.annotation.Documented; |
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Inherited; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
/** |
||||
* Annotation that can be applied to a test class to enable auto-configuration for metrics |
||||
* exporters. |
||||
* |
||||
* @author Chris Bono |
||||
* @since 2.4.0 |
||||
*/ |
||||
@Target(ElementType.TYPE) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
@Documented |
||||
@Inherited |
||||
public @interface AutoConfigureMetrics { |
||||
|
||||
} |
||||
@ -0,0 +1,69 @@
@@ -0,0 +1,69 @@
|
||||
/* |
||||
* Copyright 2012-2019 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 |
||||
* |
||||
* https://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.test.autoconfigure.metrics; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.springframework.boot.test.util.TestPropertyValues; |
||||
import org.springframework.context.ConfigurableApplicationContext; |
||||
import org.springframework.core.annotation.MergedAnnotations; |
||||
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy; |
||||
import org.springframework.test.context.ContextConfigurationAttributes; |
||||
import org.springframework.test.context.ContextCustomizer; |
||||
import org.springframework.test.context.ContextCustomizerFactory; |
||||
import org.springframework.test.context.MergedContextConfiguration; |
||||
|
||||
/** |
||||
* {@link ContextCustomizerFactory} that creates a customizer that globally disables |
||||
* metrics exporters unless the {@link AutoConfigureMetrics} annotation is specified on |
||||
* the test class. |
||||
* |
||||
* @author Chris Bono |
||||
*/ |
||||
class ExcludeMetricExportersContextCustomizerFactory implements ContextCustomizerFactory { |
||||
|
||||
@Override |
||||
public ContextCustomizer createContextCustomizer(Class<?> testClass, |
||||
List<ContextConfigurationAttributes> configAttributes) { |
||||
boolean metricExportersEnabled = MergedAnnotations.from(testClass, SearchStrategy.TYPE_HIERARCHY) |
||||
.get(AutoConfigureMetrics.class).isPresent(); |
||||
return !metricExportersEnabled ? new ExcludeMetricExportersContextCustomizer() : null; |
||||
} |
||||
|
||||
static class ExcludeMetricExportersContextCustomizer implements ContextCustomizer { |
||||
|
||||
@Override |
||||
public void customizeContext(ConfigurableApplicationContext context, |
||||
MergedContextConfiguration mergedContextConfiguration) { |
||||
TestPropertyValues |
||||
.of("management.metrics.export.enabled=false", "management.metrics.export.simple.enabled=true") |
||||
.applyTo(context); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object obj) { |
||||
return (obj != null) && (getClass() == obj.getClass()); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return getClass().hashCode(); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
/* |
||||
* Copyright 2012-2019 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 |
||||
* |
||||
* https://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. |
||||
*/ |
||||
|
||||
/** |
||||
* Test auto-configuration support for actuator metrics. |
||||
*/ |
||||
package org.springframework.boot.test.autoconfigure.metrics; |
||||
@ -0,0 +1,45 @@
@@ -0,0 +1,45 @@
|
||||
/* |
||||
* Copyright 2012-2019 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 |
||||
* |
||||
* https://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.test.autoconfigure.metrics; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.core.env.Environment; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Integration test to verify behaviour when |
||||
* {@link AutoConfigureMetrics @AutoConfigureMetrics} is not present on the test class. |
||||
* |
||||
* @author Chris Bono |
||||
*/ |
||||
@SpringBootTest |
||||
class AutoConfigureMetricsMissingIntegrationTests { |
||||
|
||||
@Autowired |
||||
private Environment environment; |
||||
|
||||
@Test |
||||
void customizerRunsAndSetsExclusionPropertiesWhenNoAnnotationPresent() { |
||||
assertThat(this.environment.getProperty("management.metrics.export.enabled")).isEqualTo("false"); |
||||
assertThat(this.environment.getProperty("management.metrics.export.simple.enabled")).isEqualTo("true"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,46 @@
@@ -0,0 +1,46 @@
|
||||
/* |
||||
* Copyright 2012-2019 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 |
||||
* |
||||
* https://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.test.autoconfigure.metrics; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.test.context.SpringBootTest; |
||||
import org.springframework.core.env.Environment; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Integration test to verify behaviour when |
||||
* {@link AutoConfigureMetrics @AutoConfigureMetrics} is present on the test class. |
||||
* |
||||
* @author Chris Bono |
||||
*/ |
||||
@SpringBootTest |
||||
@AutoConfigureMetrics |
||||
class AutoConfigureMetricsPresentIntegrationTests { |
||||
|
||||
@Autowired |
||||
private Environment environment; |
||||
|
||||
@Test |
||||
void customizerDoesNotRunWhenAnnotationPresent() { |
||||
assertThat(this.environment.containsProperty("management.metrics.export.enabled")).isFalse(); |
||||
assertThat(this.environment.containsProperty("management.metrics.export.simple.enabled")).isFalse(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
/* |
||||
* Copyright 2012-2019 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 |
||||
* |
||||
* https://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.test.autoconfigure.metrics; |
||||
|
||||
import org.springframework.boot.SpringBootConfiguration; |
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
||||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
|
||||
/** |
||||
* Example {@link SpringBootApplication @SpringBootApplication} for use with |
||||
* {@link AutoConfigureMetrics @AutoConfigureMetrics} tests. |
||||
* |
||||
* @author Chris Bono |
||||
*/ |
||||
@SpringBootConfiguration |
||||
@EnableAutoConfiguration |
||||
class AutoConfigureMetricsSpringBootApplication { |
||||
|
||||
} |
||||
@ -0,0 +1,74 @@
@@ -0,0 +1,74 @@
|
||||
/* |
||||
* Copyright 2012-2019 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 |
||||
* |
||||
* https://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.test.autoconfigure.metrics; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.context.ConfigurableApplicationContext; |
||||
import org.springframework.context.support.GenericApplicationContext; |
||||
import org.springframework.test.context.ContextCustomizer; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link AutoConfigureMetrics} and |
||||
* {@link ExcludeMetricExportersContextCustomizerFactory} working together. |
||||
* |
||||
* @author Chris Bono |
||||
*/ |
||||
class ExcludeMetricExportersContextCustomizerFactoryTests { |
||||
|
||||
private ExcludeMetricExportersContextCustomizerFactory factory = new ExcludeMetricExportersContextCustomizerFactory(); |
||||
|
||||
@Test |
||||
void getContextCustomizerWhenHasNoAnnotationShouldReturnCustomizer() { |
||||
ContextCustomizer customizer = this.factory.createContextCustomizer(NoAnnotation.class, null); |
||||
assertThat(customizer).isNotNull(); |
||||
ConfigurableApplicationContext context = new GenericApplicationContext(); |
||||
customizer.customizeContext(context, null); |
||||
assertThat(context.getEnvironment().getProperty("management.metrics.export.enabled")).isEqualTo("false"); |
||||
assertThat(context.getEnvironment().getProperty("management.metrics.export.simple.enabled")).isEqualTo("true"); |
||||
} |
||||
|
||||
@Test |
||||
void getContextCustomizerWhenHasAnnotationShouldReturnNull() { |
||||
ContextCustomizer customizer = this.factory.createContextCustomizer(WithAnnotation.class, null); |
||||
assertThat(customizer).isNull(); |
||||
} |
||||
|
||||
@Test |
||||
void hashCodeAndEquals() { |
||||
ContextCustomizer customizer1 = this.factory.createContextCustomizer(NoAnnotation.class, null); |
||||
ContextCustomizer customizer2 = this.factory.createContextCustomizer(OtherWithNoAnnotation.class, null); |
||||
assertThat(customizer1.hashCode()).isEqualTo(customizer2.hashCode()); |
||||
assertThat(customizer1).isEqualTo(customizer1).isEqualTo(customizer2); |
||||
} |
||||
|
||||
static class NoAnnotation { |
||||
|
||||
} |
||||
|
||||
static class OtherWithNoAnnotation { |
||||
|
||||
} |
||||
|
||||
@AutoConfigureMetrics |
||||
static class WithAnnotation { |
||||
|
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue