Only use micrometer composites when necessary
Update micrometer auto-configuration so that a `CompositeMeterRegistry` is only created when more than one `MeterRegistry` bean is declared. When a composite is crated, it is marked as `@Primary` so that it can be directly injected. Meter registries can now be defined directly as beans, and auto-configuration can back off in the usual way. The `MeterRegistryConfigurer` is now called `MeterRegistryCustomizer` and is generically types so it's easy to apply customizations to a particular `MeterRegistry` implementation. Fixes gh-11799 Co-authored-by: Jon Schneider <jschneider@pivotal.io>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.metrics;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.atlas.AtlasExportConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.datadog.DatadogExportConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.ganglia.GangliaExportConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.graphite.GraphiteExportConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.influx.InfluxExportConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.jmx.JmxExportConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusExportConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleExportConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.statsd.StatsdExportConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* Imports for registry configurations.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
*/
|
||||
@Configuration
|
||||
@Import({ AtlasExportConfiguration.class, DatadogExportConfiguration.class,
|
||||
GangliaExportConfiguration.class, GraphiteExportConfiguration.class,
|
||||
InfluxExportConfiguration.class, JmxExportConfiguration.class,
|
||||
PrometheusExportConfiguration.class, SimpleExportConfiguration.class,
|
||||
StatsdExportConfiguration.class })
|
||||
class MeterRegistriesConfiguration {
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 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.
|
||||
@@ -23,19 +23,20 @@ import io.micrometer.core.instrument.MeterRegistry;
|
||||
* Callback interface that can be used to customize auto-configured {@link MeterRegistry
|
||||
* MeterRegistries}.
|
||||
* <p>
|
||||
* Configurers are guaranteed to be applied before any {@link Meter} is registered with
|
||||
* Customizers are guaranteed to be applied before any {@link Meter} is registered with
|
||||
* the registry.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @param <T> The registry type to customize
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface MeterRegistryConfigurer {
|
||||
public interface MeterRegistryCustomizer<T extends MeterRegistry> {
|
||||
|
||||
/**
|
||||
* Configure the given {@code registry}.
|
||||
* @param registry the registry to configure
|
||||
* Customize the given {@code registry}.
|
||||
* @param registry the registry to customize
|
||||
*/
|
||||
void configureRegistry(MeterRegistry registry);
|
||||
void customize(T registry);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.metrics;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Metrics;
|
||||
import io.micrometer.core.instrument.binder.MeterBinder;
|
||||
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.util.LambdaSafe;
|
||||
|
||||
/**
|
||||
* {@link BeanPostProcessor} to apply {@link MeterRegistryCustomizer customizers} and
|
||||
* {@link MeterBinder binters} and {@link Metrics#addRegistry global registration} to
|
||||
* {@link MeterRegistry meter registries}. This post processor intentionally skips
|
||||
* {@link CompositeMeterRegistry} with the assumptions that the registries it contains are
|
||||
* beans and will be customized directly.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class MeterRegistryPostProcessor implements BeanPostProcessor {
|
||||
|
||||
private final Collection<MeterRegistryCustomizer<?>> customizers;
|
||||
|
||||
private final Collection<MeterBinder> binders;
|
||||
|
||||
private final boolean addToGlobalRegistry;
|
||||
|
||||
MeterRegistryPostProcessor(ObjectProvider<Collection<MeterBinder>> binders,
|
||||
ObjectProvider<Collection<MeterRegistryCustomizer<?>>> customizers,
|
||||
boolean addToGlobalRegistry) {
|
||||
this.binders = binders.getIfAvailable(Collections::emptyList);
|
||||
this.customizers = customizers.getIfAvailable(Collections::emptyList);
|
||||
this.addToGlobalRegistry = addToGlobalRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
if (bean instanceof MeterRegistry) {
|
||||
postProcess((MeterRegistry) bean);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
private void postProcess(MeterRegistry registry) {
|
||||
if (registry instanceof CompositeMeterRegistry) {
|
||||
return;
|
||||
}
|
||||
// Customizers must be applied before binders, as they may add custom tags or
|
||||
// alter timer or summary configuration.
|
||||
customize(registry);
|
||||
addBinders(registry);
|
||||
if (this.addToGlobalRegistry && registry != Metrics.globalRegistry) {
|
||||
Metrics.addRegistry(registry);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void customize(MeterRegistry registry) {
|
||||
LambdaSafe.callbacks(MeterRegistryCustomizer.class, this.customizers, registry)
|
||||
.withLogger(MeterRegistryPostProcessor.class)
|
||||
.invoke((customizer) -> customizer.customize(registry));
|
||||
}
|
||||
|
||||
private void addBinders(MeterRegistry registry) {
|
||||
this.binders.forEach((binder) -> binder.bindTo(registry));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,28 +17,17 @@
|
||||
package org.springframework.boot.actuate.autoconfigure.metrics;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.micrometer.core.instrument.Clock;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Metrics;
|
||||
import io.micrometer.core.instrument.binder.MeterBinder;
|
||||
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.amqp.RabbitMetricsConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.cache.CacheMetricsConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.atlas.AtlasExportConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.datadog.DatadogExportConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.ganglia.GangliaExportConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.graphite.GraphiteExportConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.influx.InfluxExportConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.jmx.JmxExportConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusExportConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleExportConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.statsd.StatsdExportConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.CompositeMeterRegistryConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.reactive.server.WebFluxMetricsConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMetricsConfiguration;
|
||||
@@ -61,14 +50,13 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.integration.config.EnableIntegrationManagement;
|
||||
import org.springframework.integration.support.management.IntegrationManagementConfigurer;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Micrometer-based metrics.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @author Jon Schneider
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(Timed.class)
|
||||
@@ -76,32 +64,19 @@ import org.springframework.util.Assert;
|
||||
@Import({ MeterBindersConfiguration.class, WebMvcMetricsConfiguration.class,
|
||||
WebFluxMetricsConfiguration.class, RestTemplateMetricsConfiguration.class,
|
||||
CacheMetricsConfiguration.class, DataSourcePoolMetricsConfiguration.class,
|
||||
RabbitMetricsConfiguration.class, AtlasExportConfiguration.class,
|
||||
DatadogExportConfiguration.class, GangliaExportConfiguration.class,
|
||||
GraphiteExportConfiguration.class, InfluxExportConfiguration.class,
|
||||
JmxExportConfiguration.class, PrometheusExportConfiguration.class,
|
||||
SimpleExportConfiguration.class, StatsdExportConfiguration.class })
|
||||
RabbitMetricsConfiguration.class, MeterRegistriesConfiguration.class,
|
||||
CompositeMeterRegistryConfiguration.class })
|
||||
@AutoConfigureAfter({ CacheAutoConfiguration.class, DataSourceAutoConfiguration.class,
|
||||
RabbitAutoConfiguration.class, RestTemplateAutoConfiguration.class })
|
||||
public class MetricsAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(MeterRegistry.class)
|
||||
public CompositeMeterRegistry compositeMeterRegistry(
|
||||
MetricsProperties metricsProperties,
|
||||
ObjectProvider<Collection<MetricsExporter>> exporters,
|
||||
ObjectProvider<Collection<MeterRegistryConfigurer>> configurers) {
|
||||
CompositeMeterRegistry composite = metricsProperties.isUseGlobalRegistry()
|
||||
? Metrics.globalRegistry : new CompositeMeterRegistry();
|
||||
configurers.getIfAvailable(Collections::emptyList)
|
||||
.forEach((configurer) -> configurer.configureRegistry(composite));
|
||||
exporters.getIfAvailable(Collections::emptyList).forEach((exporter) -> {
|
||||
MeterRegistry childRegistry = exporter.registry();
|
||||
Assert.state(composite != childRegistry,
|
||||
"cannot add a CompositeMeterRegistry to itself");
|
||||
composite.add(childRegistry);
|
||||
});
|
||||
return composite;
|
||||
public static MeterRegistryPostProcessor meterRegistryPostProcessor(
|
||||
ObjectProvider<Collection<MeterBinder>> binders,
|
||||
ObjectProvider<Collection<MeterRegistryCustomizer<?>>> customizers,
|
||||
MetricsProperties properties) {
|
||||
return new MeterRegistryPostProcessor(binders, customizers,
|
||||
properties.isUseGlobalRegistry());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -112,6 +87,15 @@ public class MetricsAutoConfiguration {
|
||||
return new MetricsEndpoint(registry);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Clock micrometerClock() {
|
||||
return Clock.SYSTEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds metrics from Spring Integration.
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(EnableIntegrationManagement.class)
|
||||
static class MetricsIntegrationConfiguration {
|
||||
@@ -133,19 +117,4 @@ public class MetricsAutoConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MeterRegistryConfigurationSupport {
|
||||
|
||||
MeterRegistryConfigurationSupport(MeterRegistry registry,
|
||||
MetricsProperties config,
|
||||
ObjectProvider<Collection<MeterBinder>> binders) {
|
||||
binders.getIfAvailable(Collections::emptyList)
|
||||
.forEach((binder) -> binder.bindTo(registry));
|
||||
if (config.isUseGlobalRegistry() && registry != Metrics.globalRegistry) {
|
||||
Metrics.addRegistry(registry);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,23 +16,21 @@
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.metrics.export;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* A {@code MetricsExporter} can be used to export metrics, typically to an external
|
||||
* server running as a separate process.
|
||||
* Conditionally build a composite registry when more than one registry present.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface MetricsExporter {
|
||||
@Configuration
|
||||
public class CompositeMeterRegistryConfiguration {
|
||||
|
||||
/**
|
||||
* Returns the {@link MeterRegistry} used to register metrics with the exporter.
|
||||
* @return the meter registry
|
||||
*/
|
||||
MeterRegistry registry();
|
||||
@Bean
|
||||
public static CompositeMeterRegistryPostProcessor compositeMeterRegistryPostProcessor() {
|
||||
return new CompositeMeterRegistryPostProcessor();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.metrics.export;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import io.micrometer.core.instrument.Clock;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* {@link BeanFactoryPostProcessor} to register a {@link CompositeMeterRegistry} when
|
||||
* necessary.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Order(Ordered.LOWEST_PRECEDENCE - 1)
|
||||
class CompositeMeterRegistryPostProcessor
|
||||
implements BeanDefinitionRegistryPostProcessor, BeanFactoryAware {
|
||||
|
||||
private static final String COMPOSITE_BEAN_NAME = "compositeMeterRegistry";
|
||||
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
if (beanFactory instanceof ConfigurableListableBeanFactory) {
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
|
||||
throws BeansException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
|
||||
throws BeansException {
|
||||
if (this.beanFactory == null) {
|
||||
return;
|
||||
}
|
||||
String[] registryBeans = this.beanFactory.getBeanNamesForType(MeterRegistry.class,
|
||||
true, false);
|
||||
registerCompositeIfNecessary(registry, registryBeans);
|
||||
}
|
||||
|
||||
private void registerCompositeIfNecessary(BeanDefinitionRegistry registry,
|
||||
String[] registryBeans) {
|
||||
if (ObjectUtils.isEmpty(registryBeans)) {
|
||||
registerNoOpMeterRegistry(registry);
|
||||
}
|
||||
if (registryBeans.length > 1 && !hasPrimaryDefinition(registryBeans)) {
|
||||
registerPrimaryCompositeMeterRegistry(registry, registryBeans);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasPrimaryDefinition(String[] registryBeans) {
|
||||
return Arrays.stream(registryBeans).map(this.beanFactory::getBeanDefinition)
|
||||
.anyMatch(BeanDefinition::isPrimary);
|
||||
}
|
||||
|
||||
private void registerNoOpMeterRegistry(BeanDefinitionRegistry registry) {
|
||||
// If there are no meter registries configured, we register an empty composite
|
||||
// that effectively no-ops metrics instrumentation throughout the app.
|
||||
GenericBeanDefinition definition = new GenericBeanDefinition();
|
||||
definition.setBeanClass(CompositeMeterRegistry.class);
|
||||
registry.registerBeanDefinition(COMPOSITE_BEAN_NAME, definition);
|
||||
}
|
||||
|
||||
private void registerPrimaryCompositeMeterRegistry(BeanDefinitionRegistry registry,
|
||||
String[] registryBeans) {
|
||||
GenericBeanDefinition definition = new GenericBeanDefinition();
|
||||
definition.setBeanClass(CompositeMeterRegistry.class);
|
||||
definition.setPrimary(true);
|
||||
ConstructorArgumentValues arguments = new ConstructorArgumentValues();
|
||||
arguments.addIndexedArgumentValue(0,
|
||||
new ValueHolder(null, Clock.class.getName()));
|
||||
arguments.addIndexedArgumentValue(1, getBeanReferences(registryBeans));
|
||||
definition.setConstructorArgumentValues(arguments);
|
||||
registry.registerBeanDefinition(COMPOSITE_BEAN_NAME, definition);
|
||||
}
|
||||
|
||||
private ManagedList<RuntimeBeanReference> getBeanReferences(String[] names) {
|
||||
ManagedList<RuntimeBeanReference> references = new ManagedList<>(names.length);
|
||||
Arrays.stream(names).map(RuntimeBeanReference::new).forEach(references::add);
|
||||
return references;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 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.
|
||||
@@ -20,7 +20,6 @@ import com.netflix.spectator.atlas.AtlasConfig;
|
||||
import io.micrometer.atlas.AtlasMeterRegistry;
|
||||
import io.micrometer.core.instrument.Clock;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@@ -48,14 +47,8 @@ public class AtlasExportConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "management.metrics.export.atlas.enabled", matchIfMissing = true)
|
||||
public MetricsExporter atlasExporter(AtlasConfig atlasConfig, Clock clock) {
|
||||
return () -> new AtlasMeterRegistry(atlasConfig, clock);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Clock micrometerClock() {
|
||||
return Clock.SYSTEM;
|
||||
public AtlasMeterRegistry atlasMeterRegistry(AtlasConfig atlasConfig, Clock clock) {
|
||||
return new AtlasMeterRegistry(atlasConfig, clock);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 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.
|
||||
@@ -20,7 +20,6 @@ import io.micrometer.core.instrument.Clock;
|
||||
import io.micrometer.datadog.DatadogConfig;
|
||||
import io.micrometer.datadog.DatadogMeterRegistry;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@@ -48,14 +47,9 @@ public class DatadogExportConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "management.metrics.export.datadog.enabled", matchIfMissing = true)
|
||||
public MetricsExporter datadogExporter(DatadogConfig datadogConfig, Clock clock) {
|
||||
return () -> new DatadogMeterRegistry(datadogConfig, clock);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Clock micrometerClock() {
|
||||
return Clock.SYSTEM;
|
||||
public DatadogMeterRegistry datadogMeterRegistry(DatadogConfig datadogConfig,
|
||||
Clock clock) {
|
||||
return new DatadogMeterRegistry(datadogConfig, clock);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import io.micrometer.core.instrument.util.HierarchicalNameMapper;
|
||||
import io.micrometer.ganglia.GangliaConfig;
|
||||
import io.micrometer.ganglia.GangliaMeterRegistry;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@@ -48,15 +47,9 @@ public class GangliaExportConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "management.metrics.export.ganglia.enabled", matchIfMissing = true)
|
||||
public MetricsExporter gangliaExporter(GangliaConfig gangliaConfig,
|
||||
public GangliaMeterRegistry gangliaMeterRegistry(GangliaConfig gangliaConfig,
|
||||
HierarchicalNameMapper nameMapper, Clock clock) {
|
||||
return () -> new GangliaMeterRegistry(gangliaConfig, clock, nameMapper);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Clock micrometerClock() {
|
||||
return Clock.SYSTEM;
|
||||
return new GangliaMeterRegistry(gangliaConfig, clock, nameMapper);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -21,7 +21,6 @@ import io.micrometer.core.instrument.util.HierarchicalNameMapper;
|
||||
import io.micrometer.graphite.GraphiteConfig;
|
||||
import io.micrometer.graphite.GraphiteMeterRegistry;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@@ -48,15 +47,9 @@ public class GraphiteExportConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "management.metrics.export.graphite.enabled", matchIfMissing = true)
|
||||
public MetricsExporter graphiteExporter(GraphiteConfig graphiteConfig,
|
||||
public GraphiteMeterRegistry graphiteMeterRegistry(GraphiteConfig graphiteConfig,
|
||||
HierarchicalNameMapper nameMapper, Clock clock) {
|
||||
return () -> new GraphiteMeterRegistry(graphiteConfig, clock, nameMapper);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Clock micrometerClock() {
|
||||
return Clock.SYSTEM;
|
||||
return new GraphiteMeterRegistry(graphiteConfig, clock, nameMapper);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 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.
|
||||
@@ -20,7 +20,6 @@ import io.micrometer.core.instrument.Clock;
|
||||
import io.micrometer.influx.InfluxConfig;
|
||||
import io.micrometer.influx.InfluxMeterRegistry;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@@ -47,14 +46,9 @@ public class InfluxExportConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "management.metrics.export.influx.enabled", matchIfMissing = true)
|
||||
public MetricsExporter influxExporter(InfluxConfig influxConfig, Clock clock) {
|
||||
return () -> new InfluxMeterRegistry(influxConfig, clock);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Clock micrometerClock() {
|
||||
return Clock.SYSTEM;
|
||||
public InfluxMeterRegistry influxMeterRegistry(InfluxConfig influxConfig,
|
||||
Clock clock) {
|
||||
return new InfluxMeterRegistry(influxConfig, clock);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import io.micrometer.core.instrument.util.HierarchicalNameMapper;
|
||||
import io.micrometer.jmx.JmxConfig;
|
||||
import io.micrometer.jmx.JmxMeterRegistry;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@@ -48,15 +47,9 @@ public class JmxExportConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "management.metrics.export.jmx.enabled", matchIfMissing = true)
|
||||
public MetricsExporter jmxExporter(JmxConfig config,
|
||||
public JmxMeterRegistry jmxMeterRegistry(JmxConfig config,
|
||||
HierarchicalNameMapper nameMapper, Clock clock) {
|
||||
return () -> new JmxMeterRegistry(config, clock, nameMapper);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Clock micrometerClock() {
|
||||
return Clock.SYSTEM;
|
||||
return new JmxMeterRegistry(config, clock, nameMapper);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 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.
|
||||
@@ -21,7 +21,6 @@ import io.micrometer.prometheus.PrometheusConfig;
|
||||
import io.micrometer.prometheus.PrometheusMeterRegistry;
|
||||
import io.prometheus.client.CollectorRegistry;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
|
||||
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusScrapeEndpoint;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
@@ -50,10 +49,10 @@ public class PrometheusExportConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "management.metrics.export.prometheus.enabled", matchIfMissing = true)
|
||||
public MetricsExporter prometheusExporter(PrometheusConfig prometheusConfig,
|
||||
CollectorRegistry collectorRegistry, Clock clock) {
|
||||
return () -> new PrometheusMeterRegistry(prometheusConfig, collectorRegistry,
|
||||
clock);
|
||||
public PrometheusMeterRegistry prometheusMeterRegistry(
|
||||
PrometheusConfig prometheusConfig, CollectorRegistry collectorRegistry,
|
||||
Clock clock) {
|
||||
return new PrometheusMeterRegistry(prometheusConfig, collectorRegistry, clock);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -62,12 +61,6 @@ public class PrometheusExportConfiguration {
|
||||
return new CollectorRegistry(true);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Clock micrometerClock() {
|
||||
return Clock.SYSTEM;
|
||||
}
|
||||
|
||||
@ManagementContextConfiguration
|
||||
public static class PrometheusScrapeEndpointConfiguration {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 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.
|
||||
@@ -17,10 +17,10 @@
|
||||
package org.springframework.boot.actuate.autoconfigure.metrics.export.simple;
|
||||
|
||||
import io.micrometer.core.instrument.Clock;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.simple.SimpleConfig;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
@@ -39,15 +39,9 @@ public class SimpleExportConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "management.metrics.export.simple.enabled", matchIfMissing = true)
|
||||
@ConditionalOnMissingBean(MetricsExporter.class)
|
||||
public MetricsExporter simpleExporter(SimpleConfig config, Clock clock) {
|
||||
return () -> new SimpleMeterRegistry(config, clock);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Clock micrometerClock() {
|
||||
return Clock.SYSTEM;
|
||||
@ConditionalOnMissingBean(MeterRegistry.class)
|
||||
public SimpleMeterRegistry simpleMeterRegistry(SimpleConfig config, Clock clock) {
|
||||
return new SimpleMeterRegistry(config, clock);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 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.
|
||||
@@ -21,7 +21,6 @@ import io.micrometer.core.instrument.util.HierarchicalNameMapper;
|
||||
import io.micrometer.statsd.StatsdConfig;
|
||||
import io.micrometer.statsd.StatsdMeterRegistry;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.export.MetricsExporter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@@ -48,15 +47,9 @@ public class StatsdExportConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "management.metrics.export.statsd.enabled", matchIfMissing = true)
|
||||
public MetricsExporter statsdExporter(StatsdConfig statsdConfig,
|
||||
public StatsdMeterRegistry statsdMeterRegistry(StatsdConfig statsdConfig,
|
||||
HierarchicalNameMapper hierarchicalNameMapper, Clock clock) {
|
||||
return () -> new StatsdMeterRegistry(statsdConfig, hierarchicalNameMapper, clock);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Clock micrometerClock() {
|
||||
return Clock.SYSTEM;
|
||||
return new StatsdMeterRegistry(statsdConfig, hierarchicalNameMapper, clock);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2018 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.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.boot.actuate.autoconfigure;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration;
|
||||
@@ -67,8 +68,8 @@ public class SpringApplicationHierarchyTests {
|
||||
CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class,
|
||||
MongoDataAutoConfiguration.class, Neo4jDataAutoConfiguration.class,
|
||||
Neo4jRepositoriesAutoConfiguration.class, RedisAutoConfiguration.class,
|
||||
RedisRepositoriesAutoConfiguration.class,
|
||||
FlywayAutoConfiguration.class }, excludeName = {
|
||||
RedisRepositoriesAutoConfiguration.class, FlywayAutoConfiguration.class,
|
||||
MetricsAutoConfiguration.class }, excludeName = {
|
||||
"org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration" })
|
||||
public static class Child {
|
||||
|
||||
@@ -79,8 +80,8 @@ public class SpringApplicationHierarchyTests {
|
||||
CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class,
|
||||
MongoDataAutoConfiguration.class, Neo4jDataAutoConfiguration.class,
|
||||
Neo4jRepositoriesAutoConfiguration.class, RedisAutoConfiguration.class,
|
||||
RedisRepositoriesAutoConfiguration.class,
|
||||
FlywayAutoConfiguration.class }, excludeName = {
|
||||
RedisRepositoriesAutoConfiguration.class, FlywayAutoConfiguration.class,
|
||||
MetricsAutoConfiguration.class }, excludeName = {
|
||||
"org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration" })
|
||||
public static class Parent {
|
||||
|
||||
|
||||
@@ -17,20 +17,22 @@
|
||||
package org.springframework.boot.actuate.autoconfigure.metrics;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.MeterRegistry.Config;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for applying {@link MeterRegistryConfigurer MeterRegistryConfigurers}.
|
||||
* Tests for applying {@link MeterRegistryCustomizer} beans.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class MeterRegistryConfigurerTests {
|
||||
public class MeterRegistryCustomizerTests {
|
||||
|
||||
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.with(MetricsRun.simple());
|
||||
@@ -38,26 +40,35 @@ public class MeterRegistryConfigurerTests {
|
||||
@Test
|
||||
public void commonTagsAreAppliedToAutoConfiguredBinders() {
|
||||
this.contextRunner
|
||||
.withUserConfiguration(MeterRegistryConfigurerConfiguration.class)
|
||||
.run((context) -> assertThat(context.getBean(MeterRegistry.class)
|
||||
.get("jvm.memory.used").tags("region", "us-east-1").gauge())
|
||||
.isNotNull());
|
||||
.withUserConfiguration(MeterRegistryCustomizerConfiguration.class)
|
||||
.run((context) -> {
|
||||
MeterRegistry registry = context.getBean(MeterRegistry.class);
|
||||
assertThat(registry.get("jvm.memory.used").tags("region", "us-east-1")
|
||||
.gauge()).isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void commonTagsAreAppliedBeforeRegistryIsInjectableElsewhere() {
|
||||
this.contextRunner
|
||||
.withUserConfiguration(MeterRegistryConfigurerConfiguration.class)
|
||||
.run((context) -> assertThat(context.getBean(MeterRegistry.class)
|
||||
.get("my.thing").tags("region", "us-east-1").gauge())
|
||||
.isNotNull());
|
||||
.withUserConfiguration(MeterRegistryCustomizerConfiguration.class)
|
||||
.run((context) -> {
|
||||
MeterRegistry registry = context.getBean(MeterRegistry.class);
|
||||
assertThat(
|
||||
registry.get("my.thing").tags("region", "us-east-1").gauge())
|
||||
.isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
static class MeterRegistryConfigurerConfiguration {
|
||||
@Configuration
|
||||
static class MeterRegistryCustomizerConfiguration {
|
||||
|
||||
@Bean
|
||||
public MeterRegistryConfigurer registryConfigurer() {
|
||||
return (registry) -> registry.config().commonTags("region", "us-east-1");
|
||||
public MeterRegistryCustomizer<MeterRegistry> commonTags() {
|
||||
return (registry) -> {
|
||||
Config config = registry.config();
|
||||
config.commonTags("region", "us-east-1");
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.metrics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Metrics;
|
||||
import io.micrometer.core.instrument.binder.MeterBinder;
|
||||
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
|
||||
/**
|
||||
* Tests for {@link MeterRegistryPostProcessor}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class MeterRegistryPostProcessorTests {
|
||||
|
||||
private List<MeterBinder> binderBeans = new ArrayList<>();
|
||||
|
||||
private List<MeterRegistryCustomizer<?>> customizerBeans = new ArrayList<>();
|
||||
|
||||
private ObjectProvider<Collection<MeterBinder>> binders = TestObjectProvider
|
||||
.of(this.binderBeans);
|
||||
|
||||
private ObjectProvider<Collection<MeterRegistryCustomizer<?>>> customizers = TestObjectProvider
|
||||
.of(this.customizerBeans);
|
||||
|
||||
@Mock
|
||||
private MeterBinder mockBinder;
|
||||
|
||||
@Mock
|
||||
private MeterRegistryCustomizer<MeterRegistry> mockCustomizer;
|
||||
|
||||
@Mock
|
||||
private MeterRegistry mockRegistry;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessWhenNotRegistryShouldReturnBean() {
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
|
||||
this.binders, this.customizers, false);
|
||||
Object bean = new Object();
|
||||
String beanName = "name";
|
||||
assertThat(processor.postProcessBeforeInitialization(bean, beanName))
|
||||
.isEqualTo(bean);
|
||||
assertThat(processor.postProcessAfterInitialization(bean, beanName))
|
||||
.isEqualTo(bean);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessorWhenCompositeShouldSkip() {
|
||||
this.binderBeans.add(this.mockBinder);
|
||||
this.customizerBeans.add(this.mockCustomizer);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
|
||||
this.binders, this.customizers, false);
|
||||
assertThat(processor.postProcessAfterInitialization(new CompositeMeterRegistry(),
|
||||
"name"));
|
||||
verifyZeroInteractions(this.mockBinder, this.mockCustomizer);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessShouldApplyCustomizer() {
|
||||
this.customizerBeans.add(this.mockCustomizer);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
|
||||
this.binders, this.customizers, false);
|
||||
assertThat(processor.postProcessAfterInitialization(this.mockRegistry, "name"));
|
||||
verify(this.mockCustomizer).customize(this.mockRegistry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessShouldApplyBinder() {
|
||||
this.binderBeans.add(this.mockBinder);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
|
||||
this.binders, this.customizers, false);
|
||||
assertThat(processor.postProcessAfterInitialization(this.mockRegistry, "name"));
|
||||
verify(this.mockBinder).bindTo(this.mockRegistry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessShouldCustomizeBeforeApplyingBinder() {
|
||||
this.binderBeans.add(this.mockBinder);
|
||||
this.customizerBeans.add(this.mockCustomizer);
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
|
||||
this.binders, this.customizers, false);
|
||||
processor.postProcessAfterInitialization(this.mockRegistry, "name");
|
||||
InOrder ordered = inOrder(this.mockCustomizer, this.mockBinder);
|
||||
ordered.verify(this.mockCustomizer).customize(this.mockRegistry);
|
||||
ordered.verify(this.mockBinder).bindTo(this.mockRegistry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessWhenAddToGlobalRegistryShouldAddToGlobalRegistry() {
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
|
||||
this.binders, this.customizers, true);
|
||||
try {
|
||||
processor.postProcessAfterInitialization(this.mockRegistry, "name");
|
||||
assertThat(Metrics.globalRegistry.getRegistries())
|
||||
.contains(this.mockRegistry);
|
||||
}
|
||||
finally {
|
||||
Metrics.removeRegistry(this.mockRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postProcessWhenNotAddToGlobalRegistryShouldAddToGlobalRegistry() {
|
||||
MeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(
|
||||
this.binders, this.customizers, false);
|
||||
processor.postProcessAfterInitialization(this.mockRegistry, "name");
|
||||
assertThat(Metrics.globalRegistry.getRegistries())
|
||||
.doesNotContain(this.mockRegistry);
|
||||
}
|
||||
|
||||
private static class TestObjectProvider<T> implements ObjectProvider<T> {
|
||||
|
||||
private final T value;
|
||||
|
||||
TestObjectProvider(T value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getObject() throws BeansException {
|
||||
Assert.state(this.value != null, "No value");
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getObject(Object... args) throws BeansException {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getIfAvailable() throws BeansException {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getIfUnique() throws BeansException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static <T> TestObjectProvider<T> of(T value) {
|
||||
return new TestObjectProvider<>(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -51,6 +51,7 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
@@ -140,6 +141,7 @@ public class MetricsAutoConfigurationIntegrationTests {
|
||||
@Import(PersonController.class)
|
||||
static class MetricsApp {
|
||||
|
||||
@Primary
|
||||
@Bean
|
||||
public MeterRegistry registry() {
|
||||
return new SimpleMeterRegistry(SimpleConfig.DEFAULT, new MockClock());
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.metrics;
|
||||
|
||||
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
|
||||
import io.micrometer.graphite.GraphiteMeterRegistry;
|
||||
import io.micrometer.prometheus.PrometheusMeterRegistry;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link MetricsAutoConfiguration} creating a {@link CompositeMeterRegistry}.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
*/
|
||||
public class MetricsConfigurationCompositeTests {
|
||||
|
||||
@Test
|
||||
public void compositeContainsImplementationsOnClasspath() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class))
|
||||
.withPropertyValues("management.metrics.use-global-registry=false")
|
||||
.run((context) -> assertThat(
|
||||
context.getBean(CompositeMeterRegistry.class).getRegistries())
|
||||
.hasAtLeastOneElementOfType(PrometheusMeterRegistry.class)
|
||||
.hasAtLeastOneElementOfType(GraphiteMeterRegistry.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.metrics.export;
|
||||
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.MockClock;
|
||||
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
|
||||
import io.micrometer.core.instrument.simple.SimpleConfig;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
import io.micrometer.graphite.GraphiteMeterRegistry;
|
||||
import io.micrometer.jmx.JmxMeterRegistry;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsRun;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link CompositeMeterRegistryConfiguration}.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
public class CompositeMeterRegistryConfigurationTests {
|
||||
|
||||
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.with(MetricsRun.simple());
|
||||
|
||||
/**
|
||||
* The simple registry is off by default UNLESS there is no other registry
|
||||
* implementation on the classpath, in which case it is on.
|
||||
*/
|
||||
@Test
|
||||
public void simpleWithNoCompositeCreated() {
|
||||
this.contextRunner
|
||||
.run((context) -> assertThat(context.getBean(MeterRegistry.class))
|
||||
.isInstanceOf(SimpleMeterRegistry.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* An empty composite is created in the absence of any other registry implementation.
|
||||
* This effectively no-ops instrumentation code throughout the application.
|
||||
*/
|
||||
@Test
|
||||
public void emptyCompositeCreated() {
|
||||
new ApplicationContextRunner().with(MetricsRun.limitedTo()).run((context) -> {
|
||||
MeterRegistry registry = context.getBean(MeterRegistry.class);
|
||||
assertThat(registry).isInstanceOf(CompositeMeterRegistry.class);
|
||||
assertThat(((CompositeMeterRegistry) registry).getRegistries()).isEmpty();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noCompositeCreatedWhenSingleImplementationIsEnabled() {
|
||||
new ApplicationContextRunner().with(MetricsRun.limitedTo("graphite"))
|
||||
.run((context) -> assertThat(context.getBean(MeterRegistry.class))
|
||||
.isInstanceOf(GraphiteMeterRegistry.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noCompositeCreatedWhenMultipleRegistriesButOneMarkedAsPrimary() {
|
||||
new ApplicationContextRunner().with(MetricsRun.limitedTo("graphite", "jmx"))
|
||||
.withUserConfiguration(PrimarySimpleMeterRegistryConfiguration.class)
|
||||
.run((context) -> assertThat(context.getBean(MeterRegistry.class))
|
||||
.isInstanceOf(SimpleMeterRegistry.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compositeCreatedWhenMultipleImplementationsAreEnabled() {
|
||||
new ApplicationContextRunner().with(MetricsRun.limitedTo("graphite", "jmx"))
|
||||
.run((context) -> {
|
||||
MeterRegistry registry = context.getBean(MeterRegistry.class);
|
||||
assertThat(registry).isInstanceOf(CompositeMeterRegistry.class);
|
||||
assertThat(((CompositeMeterRegistry) registry).getRegistries())
|
||||
.hasAtLeastOneElementOfType(GraphiteMeterRegistry.class)
|
||||
.hasAtLeastOneElementOfType(JmxMeterRegistry.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class PrimarySimpleMeterRegistryConfiguration {
|
||||
|
||||
@Primary
|
||||
@Bean
|
||||
public MeterRegistry simpleMeterRegistry() {
|
||||
return new SimpleMeterRegistry(SimpleConfig.DEFAULT, new MockClock());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.metrics.export;
|
||||
|
||||
import io.micrometer.core.instrument.Clock;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link CompositeMeterRegistryPostProcessor}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class CompositeMeterRegistryPostProcessorTests {
|
||||
|
||||
private static final String COMPOSITE_NAME = "compositeMeterRegistry";
|
||||
|
||||
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withUserConfiguration(BaseConfig.class);
|
||||
|
||||
@Test
|
||||
public void registerWhenHasNoMeterRegistryShouldRegisterEmptyComposite() {
|
||||
this.contextRunner.withUserConfiguration(NoMeterRegistryConfig.class)
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(MeterRegistry.class);
|
||||
CompositeMeterRegistry registry = context.getBean(COMPOSITE_NAME,
|
||||
CompositeMeterRegistry.class);
|
||||
assertThat(registry.getRegistries()).isEmpty();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerWhenHasSingleMeterRegistryShouldDoNothing() {
|
||||
this.contextRunner.withUserConfiguration(SingleMeterRegistryConfig.class)
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(MeterRegistry.class);
|
||||
MeterRegistry registry = context.getBean(MeterRegistry.class);
|
||||
assertThat(registry).isInstanceOf(TestMeterRegistry.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerWhenHasMultipleMeterRegistriesShouldAddPrimaryComposite() {
|
||||
this.contextRunner.withUserConfiguration(MultipleMeterRegistriesConfig.class)
|
||||
.run((context) -> {
|
||||
assertThat(context.getBeansOfType(MeterRegistry.class)).hasSize(3)
|
||||
.containsKeys("meterRegistryOne", "meterRegistryTwo",
|
||||
COMPOSITE_NAME);
|
||||
MeterRegistry primary = context.getBean(MeterRegistry.class);
|
||||
assertThat(primary).isInstanceOf(CompositeMeterRegistry.class);
|
||||
assertThat(((CompositeMeterRegistry) primary).getRegistries())
|
||||
.hasSize(2);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerWhenHasMultipleRegistriesAndOneIsPrimaryShouldDoNothing() {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class BaseConfig {
|
||||
|
||||
@Bean
|
||||
public CompositeMeterRegistryPostProcessor compositeMeterRegistryPostProcessor() {
|
||||
return new CompositeMeterRegistryPostProcessor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Clock micrometerClock() {
|
||||
return Clock.SYSTEM;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class NoMeterRegistryConfig {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class SingleMeterRegistryConfig {
|
||||
|
||||
@Bean
|
||||
public MeterRegistry meterRegistry() {
|
||||
return new TestMeterRegistry();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MultipleMeterRegistriesConfig {
|
||||
|
||||
@Bean
|
||||
public MeterRegistry meterRegistryOne() {
|
||||
return new TestMeterRegistry();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MeterRegistry meterRegistryTwo() {
|
||||
return new SimpleMeterRegistry();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestMeterRegistry extends SimpleMeterRegistry {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2018 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.metrics.export.simple;
|
||||
|
||||
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link SimpleExportConfiguration}.
|
||||
*
|
||||
* @author Jon Schneider
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
public class SimpleExportConfigurationTests {
|
||||
|
||||
@Test
|
||||
public void simpleMeterRegistryIsInTheCompositeWhenNoOtherRegistryIs() {
|
||||
new ApplicationContextRunner()
|
||||
.withPropertyValues("management.metrics.export.atlas.enabled=false",
|
||||
"management.metrics.export.datadog.enabled=false",
|
||||
"management.metrics.export.ganglia.enabled=false",
|
||||
"management.metrics.export.graphite.enabled=false",
|
||||
"management.metrics.export.influx.enabled=false",
|
||||
"management.metrics.export.jmx.enabled=false",
|
||||
"management.metrics.export.prometheus.enabled=false",
|
||||
"management.metrics.export.statsd.enabled=false",
|
||||
"management.metrics.use-global-registry=false")
|
||||
.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
CompositeMeterRegistry meterRegistry = context
|
||||
.getBean(CompositeMeterRegistry.class);
|
||||
assertThat(meterRegistry.getRegistries()).hasSize(1);
|
||||
assertThat(meterRegistry.getRegistries())
|
||||
.hasOnlyElementsOfType(SimpleMeterRegistry.class);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user