diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java index 1e686b165a..486191de2e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfiguration.java @@ -52,6 +52,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.SearchStrategy; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -64,6 +65,7 @@ import org.springframework.integration.support.management.IntegrationManagementC * * @since 2.0.0 * @author Jon Schneider + * @author Stephane Nicoll */ @Configuration @ConditionalOnClass(Timed.class) @@ -76,19 +78,28 @@ import org.springframework.integration.support.management.IntegrationManagementC InfluxExportConfiguration.class, JmxExportConfiguration.class, PrometheusExportConfiguration.class, SimpleExportConfiguration.class, StatsdExportConfiguration.class }) -@AutoConfigureAfter({ CacheAutoConfiguration.class, DataSourceAutoConfiguration.class }) +@AutoConfigureAfter({ CacheAutoConfiguration.class, DataSourceAutoConfiguration.class, + RestTemplateAutoConfiguration.class }) public class MetricsAutoConfiguration { @Bean @ConditionalOnMissingBean(MeterRegistry.class) public CompositeMeterRegistry compositeMeterRegistry( + MetricsProperties metricsProperties, ObjectProvider> exporters, ObjectProvider> configurers) { - CompositeMeterRegistry composite = new CompositeMeterRegistry(); + CompositeMeterRegistry composite = metricsProperties.isUseGlobalRegistry() ? + Metrics.globalRegistry : new CompositeMeterRegistry(); configurers.getIfAvailable(Collections::emptyList) .forEach((configurer) -> configurer.configureRegistry(composite)); - exporters.getIfAvailable(Collections::emptyList).stream() - .map(MetricsExporter::registry).forEach(composite::add); + exporters.getIfAvailable(Collections::emptyList).forEach(exporter -> { + MeterRegistry childRegistry = exporter.registry(); + if (composite == childRegistry) { + throw new IllegalStateException( + "cannot add a CompositeMeterRegistry to itself"); + } + composite.add(childRegistry); + }); return composite; } @@ -129,7 +140,7 @@ public class MetricsAutoConfiguration { ObjectProvider> binders) { binders.getIfAvailable(Collections::emptyList) .forEach((binder) -> binder.bindTo(registry)); - if (config.isUseGlobalRegistry()) { + if (config.isUseGlobalRegistry() && registry != Metrics.globalRegistry) { Metrics.addRegistry(registry); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogProperties.java index d4c80b068c..f8b3c74a98 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogProperties.java @@ -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. @@ -33,6 +33,18 @@ public class DatadogProperties extends StepRegistryProperties { */ private String apiKey; + /** + * Datadog application key. Not strictly required, but improves the Datadog + * experience by sending meter descriptions, types, and base units to Datadog. + */ + private String applicationKey; + + /** + * Whether to publish descriptions metadata to Datadog. Turn this off to minimize the + * amount of metadata sent. + */ + private Boolean descriptions; + /** * Tag that will be mapped to "host" when shipping metrics to Datadog. Can be * omitted if host should be omitted on publishing. @@ -53,6 +65,22 @@ public class DatadogProperties extends StepRegistryProperties { this.apiKey = apiKey; } + public String getApplicationKey() { + return this.applicationKey; + } + + public void setApplicationKey(String applicationKey) { + this.applicationKey = applicationKey; + } + + public Boolean getDescriptions() { + return this.descriptions; + } + + public void setDescriptions(Boolean descriptions) { + this.descriptions = descriptions; + } + public String getHostTag() { return this.hostTag; } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogPropertiesConfigAdapter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogPropertiesConfigAdapter.java index 725ed3580b..3e5b03c052 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogPropertiesConfigAdapter.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogPropertiesConfigAdapter.java @@ -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. @@ -39,6 +39,11 @@ class DatadogPropertiesConfigAdapter return get(DatadogProperties::getApiKey, DatadogConfig.super::apiKey); } + @Override + public String applicationKey() { + return get(DatadogProperties::getApplicationKey, DatadogConfig.super::applicationKey); + } + @Override public String hostTag() { return get(DatadogProperties::getHostTag, DatadogConfig.super::hostTag); @@ -49,4 +54,9 @@ class DatadogPropertiesConfigAdapter return get(DatadogProperties::getUri, DatadogConfig.super::uri); } + @Override + public boolean descriptions() { + return get(DatadogProperties::getDescriptions, DatadogConfig.super::descriptions); + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxExportConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxExportConfiguration.java index 14a10c7b15..de71666e55 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxExportConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxExportConfiguration.java @@ -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. @@ -18,12 +18,14 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.jmx; import io.micrometer.core.instrument.Clock; 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; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -35,12 +37,20 @@ import org.springframework.context.annotation.Configuration; */ @Configuration @ConditionalOnClass(JmxMeterRegistry.class) +@EnableConfigurationProperties(JmxProperties.class) public class JmxExportConfiguration { + @Bean + @ConditionalOnMissingBean + public JmxConfig jmxConfig(JmxProperties jmxProperties) { + return new JmxPropertiesConfigAdapter(jmxProperties); + } + @Bean @ConditionalOnProperty(value = "management.metrics.export.jmx.enabled", matchIfMissing = true) - public MetricsExporter jmxExporter(HierarchicalNameMapper nameMapper, Clock clock) { - return () -> new JmxMeterRegistry(nameMapper, clock); + public MetricsExporter jmxExporter(JmxConfig config, + HierarchicalNameMapper nameMapper, Clock clock) { + return () -> new JmxMeterRegistry(config, nameMapper, clock); } @Bean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxProperties.java new file mode 100644 index 0000000000..ae73fb4bc7 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxProperties.java @@ -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.export.jmx; + +import java.time.Duration; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * {@link ConfigurationProperties} for configuring JMX metrics export. + * + * @author Jon Schneider + * @since 2.0.0 + */ +@ConfigurationProperties(prefix = "management.metrics.export.jmx") +public class JmxProperties { + + /** + * Step size (i.e. reporting frequency) to use. + */ + private Duration step; + + public Duration getStep() { + return this.step; + } + + public void setStep(Duration step) { + this.step = step; + } +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxPropertiesConfigAdapter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxPropertiesConfigAdapter.java new file mode 100644 index 0000000000..1741a6496f --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxPropertiesConfigAdapter.java @@ -0,0 +1,47 @@ +/* + * 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.jmx; + +import java.time.Duration; + +import io.micrometer.jmx.JmxConfig; + +import org.springframework.boot.actuate.autoconfigure.metrics.export.PropertiesConfigAdapter; + +/** + * Adapter to convert {@link JmxProperties} to a {@link JmxConfig}. + * + * @author Jon Schneider + */ +class JmxPropertiesConfigAdapter extends PropertiesConfigAdapter + implements JmxConfig { + + JmxPropertiesConfigAdapter(JmxProperties properties) { + super(properties); + } + + @Override + public String get(String k) { + return null; + } + + @Override + public Duration step() { + return get(JmxProperties::getStep, JmxConfig.super::step); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfiguration.java index 14a7f59a1a..0e54df99c4 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfiguration.java @@ -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. @@ -18,14 +18,12 @@ package org.springframework.boot.actuate.autoconfigure.metrics.web.client; import io.micrometer.core.instrument.MeterRegistry; -import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties; import org.springframework.boot.actuate.metrics.web.client.DefaultRestTemplateExchangeTagsProvider; import org.springframework.boot.actuate.metrics.web.client.MetricsRestTemplateCustomizer; import org.springframework.boot.actuate.metrics.web.client.RestTemplateExchangeTagsProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @@ -57,47 +55,4 @@ public class RestTemplateMetricsConfiguration { properties.getWeb().getClient().isRecordRequestPercentiles()); } - @Bean - public static BeanPostProcessor restTemplateInterceptorPostProcessor( - ApplicationContext applicationContext) { - return new MetricsInterceptorPostProcessor(applicationContext); - } - - /** - * {@link BeanPostProcessor} to apply {@link MetricsRestTemplateCustomizer} to any - * directly registered {@link RestTemplate} beans. - */ - private static class MetricsInterceptorPostProcessor implements BeanPostProcessor { - - private final ApplicationContext applicationContext; - - private MetricsRestTemplateCustomizer customizer; - - MetricsInterceptorPostProcessor(ApplicationContext applicationContext) { - this.applicationContext = applicationContext; - } - - @Override - public Object postProcessBeforeInitialization(Object bean, String beanName) { - return bean; - } - - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) { - if (bean instanceof RestTemplate) { - getCustomizer().customize((RestTemplate) bean); - } - return bean; - } - - private MetricsRestTemplateCustomizer getCustomizer() { - if (this.customizer == null) { - this.customizer = this.applicationContext - .getBean(MetricsRestTemplateCustomizer.class); - } - return this.customizer; - } - - } - } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryConfigurerTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryConfigurerTests.java index f00eb836f4..2b3d4e98c7 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryConfigurerTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MeterRegistryConfigurerTests.java @@ -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. @@ -40,7 +40,7 @@ public class MeterRegistryConfigurerTests { .withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class)) .withConfiguration( UserConfigurations.of(MeterRegistryConfigurerConfiguration.class)) - .withPropertyValues("metrics.use-global-registry=false") + .withPropertyValues("management.metrics.use-global-registry=false") .run((context) -> assertThat(context.getBean(MeterRegistry.class) .find("jvm.memory.used").tags("region", "us-east-1").gauge()) .isPresent()); @@ -52,7 +52,7 @@ public class MeterRegistryConfigurerTests { .withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class)) .withConfiguration( UserConfigurations.of(MeterRegistryConfigurerConfiguration.class)) - .withPropertyValues("metrics.use-global-registry=false") + .withPropertyValues("management.metrics.use-global-registry=false") .run((context) -> assertThat(context.getBean(MeterRegistry.class) .find("my.thing").tags("region", "us-east-1").gauge()) .isPresent()); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationIntegrationTests.java index 7633b504bb..bc57384bad 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationIntegrationTests.java @@ -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. @@ -35,12 +35,14 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; +import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -92,7 +94,6 @@ public class MetricsAutoConfigurationIntegrationTests { "{\"message\": \"hello\"}", MediaType.APPLICATION_JSON)); assertThat(this.external.getForObject("/api/external", Map.class)) .containsKey("message"); - MockClock.clock(this.registry).add(SimpleConfig.DEFAULT_STEP); assertThat(this.registry.find("http.client.requests").value(Statistic.Count, 1.0) .timer()).isPresent(); } @@ -100,7 +101,6 @@ public class MetricsAutoConfigurationIntegrationTests { @Test public void requestMappingIsInstrumented() { this.loopback.getForObject("/api/people", Set.class); - MockClock.clock(this.registry).add(SimpleConfig.DEFAULT_STEP); assertThat(this.registry.find("http.server.requests").value(Statistic.Count, 1.0) .timer()).isPresent(); } @@ -115,7 +115,8 @@ public class MetricsAutoConfigurationIntegrationTests { @Configuration @ImportAutoConfiguration({ MetricsAutoConfiguration.class, JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, - WebMvcAutoConfiguration.class, DispatcherServletAutoConfiguration.class, + RestTemplateAutoConfiguration.class, WebMvcAutoConfiguration.class, + DispatcherServletAutoConfiguration.class, ServletWebServerFactoryAutoConfiguration.class }) @Import(PersonController.class) static class MetricsApp { @@ -126,8 +127,8 @@ public class MetricsAutoConfigurationIntegrationTests { } @Bean - public RestTemplate restTemplate() { - return new RestTemplate(); + public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) { + return restTemplateBuilder.build(); } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationTests.java index 624b58cb65..4478bb7cb0 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsAutoConfigurationTests.java @@ -41,6 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat; public class MetricsAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withPropertyValues("management.metrics.use-global-registry=false") .withUserConfiguration(RegistryConfiguration.class) .withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class)); @@ -49,8 +50,7 @@ public class MetricsAutoConfigurationTests { this.contextRunner .withConfiguration( AutoConfigurations.of(DataSourceAutoConfiguration.class)) - .withPropertyValues("spring.datasource.generate-unique-name=true", - "management.metrics.use-global-registry=false") + .withPropertyValues("spring.datasource.generate-unique-name=true") .run((context) -> { context.getBean(DataSource.class).getConnection().getMetaData(); MeterRegistry registry = context.getBean(MeterRegistry.class); @@ -65,8 +65,7 @@ public class MetricsAutoConfigurationTests { .withConfiguration( AutoConfigurations.of(DataSourceAutoConfiguration.class)) .withPropertyValues("spring.datasource.generate-unique-name=true", - "management.metrics.jdbc.datasource-metric-name=custom.name", - "management.metrics.use-global-registry=false") + "management.metrics.jdbc.datasource-metric-name=custom.name") .run((context) -> { context.getBean(DataSource.class).getConnection().getMetaData(); MeterRegistry registry = context.getBean(MeterRegistry.class); @@ -81,8 +80,7 @@ public class MetricsAutoConfigurationTests { .withConfiguration( AutoConfigurations.of(DataSourceAutoConfiguration.class)) .withPropertyValues("spring.datasource.generate-unique-name=true", - "management.metrics.jdbc.instrument-datasource=false", - "management.metrics.use-global-registry=false") + "management.metrics.jdbc.instrument-datasource=false") .run((context) -> { context.getBean(DataSource.class).getConnection().getMetaData(); MeterRegistry registry = context.getBean(MeterRegistry.class); @@ -96,7 +94,6 @@ public class MetricsAutoConfigurationTests { this.contextRunner.withUserConfiguration(TwoDataSourcesConfiguration.class) .withConfiguration( AutoConfigurations.of(DataSourceAutoConfiguration.class)) - .withPropertyValues("metrics.use-global-registry=false") .run((context) -> { context.getBean("firstDataSource", DataSource.class).getConnection() .getMetaData(); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsConfigurationCompositeTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsConfigurationCompositeTests.java index 60c5d2ead8..353d6cd076 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsConfigurationCompositeTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/MetricsConfigurationCompositeTests.java @@ -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. @@ -37,7 +37,7 @@ public class MetricsConfigurationCompositeTests { public void compositeContainsImplementationsOnClasspath() { new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class)) - .withPropertyValues("metrics.use-global-registry=false") + .withPropertyValues("management.metrics.use-global-registry=false") .run((context) -> assertThat( context.getBean(CompositeMeterRegistry.class).getRegistries()) .hasAtLeastOneElementOfType(PrometheusMeterRegistry.class) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogPropertiesConfigAdapterTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogPropertiesConfigAdapterTests.java index 7ca2affe1b..f822103425 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogPropertiesConfigAdapterTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogPropertiesConfigAdapterTests.java @@ -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. @@ -27,14 +27,6 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class DatadogPropertiesConfigAdapterTests { - @Test - public void apiKeyInferUri() { - DatadogProperties properties = new DatadogProperties(); - properties.setApiKey("my-key"); - assertThat(new DatadogPropertiesConfigAdapter(properties).uri()) - .contains("?api_key=my-key"); - } - @Test public void uriCanBeSet() { DatadogProperties properties = new DatadogProperties(); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/simple/SimpleExportConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/simple/SimpleExportConfigurationTests.java index 01256cfe43..b9f622bcff 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/simple/SimpleExportConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/simple/SimpleExportConfigurationTests.java @@ -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. @@ -46,7 +46,8 @@ public class SimpleExportConfigurationTests { "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.export.statsd.enabled=false", + "management.metrics.use-global-registry=false") .withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class)) .run((context) -> { CompositeMeterRegistry meterRegistry = context diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfigurationTests.java new file mode 100644 index 0000000000..70cf20b930 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/web/client/RestTemplateMetricsConfigurationTests.java @@ -0,0 +1,93 @@ +/* + * 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.web.client; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import org.junit.Test; + +import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; +import org.springframework.boot.actuate.metrics.web.client.MetricsRestTemplateCustomizer; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpStatus; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.web.client.RestTemplate; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; + +/** + * Tests for {@link RestTemplateMetricsConfiguration}. + * + * @author Stephane Nicoll + */ +public class RestTemplateMetricsConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withPropertyValues("management.metrics.use-global-registry=false") + .withConfiguration(AutoConfigurations.of( + RestTemplateAutoConfiguration.class, MetricsAutoConfiguration.class)) + .withUserConfiguration(RegistryConfiguration.class); + + + @Test + public void restTemplateCreatedWithBuilderIsInstrumented() { + this.contextRunner.run((context) -> { + MeterRegistry registry = context.getBean(MeterRegistry.class); + RestTemplate restTemplate = context.getBean(RestTemplateBuilder.class) + .build(); + validateRestTemplate(restTemplate, registry); + }); + } + + @Test + public void restTemplateCanBeCustomizedManually() { + this.contextRunner.run((context) -> { + assertThat(context).hasSingleBean(MetricsRestTemplateCustomizer.class); + RestTemplate restTemplate = new RestTemplateBuilder().customizers( + context.getBean(MetricsRestTemplateCustomizer.class)).build(); + MeterRegistry registry = context.getBean(MeterRegistry.class); + validateRestTemplate(restTemplate, registry); + }); + } + + private void validateRestTemplate(RestTemplate restTemplate, MeterRegistry registry) { + MockRestServiceServer server = MockRestServiceServer.createServer(restTemplate); + server.expect(requestTo("/test")).andRespond(withStatus(HttpStatus.OK)); + assertThat(registry.find("http.client.requests").meter()).isNotPresent(); + assertThat(restTemplate.getForEntity("/test", Void.class).getStatusCode()) + .isEqualTo(HttpStatus.OK); + assertThat(registry.find("http.client.requests").meter()).isPresent(); + } + + @Configuration + static class RegistryConfiguration { + + @Bean + public MeterRegistry registry() { + return new SimpleMeterRegistry(); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/cache/CaffeineCacheMeterBinderProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/cache/CaffeineCacheMeterBinderProvider.java index 3450059c62..11a3968fd3 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/cache/CaffeineCacheMeterBinderProvider.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/cache/CaffeineCacheMeterBinderProvider.java @@ -34,7 +34,7 @@ public class CaffeineCacheMeterBinderProvider @Override public MeterBinder getMeterBinder(CaffeineCache cache, String name, Iterable tags) { - return new CaffeineCacheMetrics(cache.getNativeCache(), tags, name); + return new CaffeineCacheMetrics(cache.getNativeCache(), name, tags); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetrics.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetrics.java index b4723ddd26..11d0ee7cad 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetrics.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetrics.java @@ -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. @@ -93,7 +93,10 @@ public class WebMvcMetrics { } void preHandle(HttpServletRequest request, Object handler) { - request.setAttribute(TIMING_REQUEST_ATTRIBUTE, System.nanoTime()); + if (request.getAttribute(TIMING_REQUEST_ATTRIBUTE) == null) { + request.setAttribute(TIMING_REQUEST_ATTRIBUTE, + this.registry.config().clock().monotonicTime()); + } request.setAttribute(HANDLER_REQUEST_ATTRIBUTE, handler); longTaskTimed(handler).forEach((config) -> { if (config.getName() == null) { diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilter.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilter.java index c67a8d4a50..60598cf25d 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilter.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilter.java @@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; +import org.springframework.http.HttpStatus; import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.servlet.HandlerExecutionChain; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; @@ -102,6 +103,7 @@ public class WebMvcMetricsFilter extends OncePerRequestFilter { } } catch (NestedServletException ex) { + response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); metrics.record(request, response, ex.getCause()); throw ex; } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/MetricsEndpointWebIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/MetricsEndpointWebIntegrationTests.java index 5fe8c4fea7..3e79318f16 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/MetricsEndpointWebIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/MetricsEndpointWebIntegrationTests.java @@ -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. @@ -64,14 +64,12 @@ public class MetricsEndpointWebIntegrationTests { @Test public void selectByName() { - MockClock.clock(registry).add(SimpleConfig.DEFAULT_STEP); client.get().uri("/actuator/metrics/jvm.memory.used").exchange().expectStatus() .isOk().expectBody().jsonPath("$.name").isEqualTo("jvm.memory.used"); } @Test public void selectByTag() { - MockClock.clock(registry).add(SimpleConfig.DEFAULT_STEP); client.get() .uri("/actuator/metrics/jvm.memory.used?tag=id:Compressed%20Class%20Space") .exchange().expectStatus().isOk().expectBody().jsonPath("$.name") diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/client/MetricsRestTemplateCustomizerTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/client/MetricsRestTemplateCustomizerTests.java index 2f395a6012..ef392598de 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/client/MetricsRestTemplateCustomizerTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/client/MetricsRestTemplateCustomizerTests.java @@ -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. @@ -67,7 +67,6 @@ public class MetricsRestTemplateCustomizerTests { .andRespond(MockRestResponseCreators.withSuccess("OK", MediaType.APPLICATION_JSON)); String result = this.restTemplate.getForObject("/test/{id}", String.class, 123); - MockClock.clock(this.registry).add(SimpleConfig.DEFAULT_STEP); assertThat(this.registry.find("http.client.requests") .meters()).anySatisfy((m) -> assertThat( StreamSupport.stream(m.getId().getTags().spliterator(), false) diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilterAutoTimedTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilterAutoTimedTests.java index 107d775cb3..65248ca19c 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilterAutoTimedTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilterAutoTimedTests.java @@ -75,8 +75,6 @@ public class WebMvcMetricsFilterAutoTimedTests { @Test public void metricsCanBeAutoTimed() throws Exception { this.mvc.perform(get("/api/10")).andExpect(status().isOk()); - - this.clock.add(SimpleConfig.DEFAULT_STEP); assertThat( this.registry.find("http.server.requests").tags("status", "200").timer()) .hasValueSatisfying((t) -> assertThat(t.count()).isEqualTo(1)); diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilterTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilterTests.java index 146f090c64..9ec0d32285 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilterTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilterTests.java @@ -21,6 +21,7 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.Collection; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; @@ -30,10 +31,18 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import io.micrometer.core.annotation.Timed; +import io.micrometer.core.instrument.Clock; +import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Statistic; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.composite.CompositeMeterRegistry; +import io.micrometer.core.instrument.config.MeterFilter; +import io.micrometer.core.instrument.config.MeterFilterReply; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import io.micrometer.prometheus.PrometheusConfig; import io.micrometer.prometheus.PrometheusMeterRegistry; +import io.prometheus.client.CollectorRegistry; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -43,6 +52,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.HttpStatus; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.web.WebAppConfiguration; @@ -77,7 +87,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. public class WebMvcMetricsFilterTests { @Autowired - private PrometheusMeterRegistry registry; + private SimpleMeterRegistry registry; + + @Autowired + private PrometheusMeterRegistry prometheusRegistry; @Autowired private WebApplicationContext context; @@ -196,15 +209,15 @@ public class WebMvcMetricsFilterTests { @Test public void recordQuantiles() throws Exception { this.mvc.perform(get("/api/c1/percentiles/10")).andExpect(status().isOk()); - assertThat(this.registry.scrape()).contains("quantile=\"0.5\""); - assertThat(this.registry.scrape()).contains("quantile=\"0.95\""); + assertThat(this.prometheusRegistry.scrape()).contains("quantile=\"0.5\""); + assertThat(this.prometheusRegistry.scrape()).contains("quantile=\"0.95\""); } @Test public void recordHistogram() throws Exception { this.mvc.perform(get("/api/c1/histogram/10")).andExpect(status().isOk()); - assertThat(this.registry.scrape()).contains("le=\"0.001\""); - assertThat(this.registry.scrape()).contains("le=\"30.0\""); + assertThat(this.prometheusRegistry.scrape()).contains("le=\"0.001\""); + assertThat(this.prometheusRegistry.scrape()).contains("le=\"30.0\""); } @Target({ ElementType.METHOD }) @@ -219,10 +232,36 @@ public class WebMvcMetricsFilterTests { @Import({ Controller1.class, Controller2.class }) static class MetricsFilterApp { + @Primary @Bean - MeterRegistry meterRegistry() { - // one of the few registries that support aggregable percentiles - return new PrometheusMeterRegistry(PrometheusConfig.DEFAULT); + MeterRegistry meterRegistry(Collection registries) { + CompositeMeterRegistry composite = new CompositeMeterRegistry(); + registries.forEach(composite::add); + return composite; + } + + @Bean + SimpleMeterRegistry simple() { + return new SimpleMeterRegistry(); + } + + @Bean + PrometheusMeterRegistry prometheus() { + PrometheusMeterRegistry r = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT, new CollectorRegistry(), Clock.SYSTEM); + r.config().meterFilter(new MeterFilter() { + @Override + public MeterFilterReply accept(Meter.Id id) { + for (Tag tag : id.getTags()) { + if (tag.getKey().equals("uri") + && (tag.getValue().contains("histogram") + || tag.getValue().contains("percentiles"))) { + return MeterFilterReply.ACCEPT; + } + } + return MeterFilterReply.DENY; + } + }); + return r; } @Bean diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsIntegrationTests.java index 69be0df1c5..712091ab85 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsIntegrationTests.java @@ -82,20 +82,18 @@ public class WebMvcMetricsIntegrationTests { @Test public void handledExceptionIsRecordedInMetricTag() throws Exception { this.mvc.perform(get("/api/handledError")).andExpect(status().is5xxServerError()); - this.clock.add(SimpleConfig.DEFAULT_STEP); assertThat(this.registry.find("http.server.requests") - .tags("exception", "Exception1").value(Statistic.Count, 1.0).timer()) - .isPresent(); + .tags("exception", "Exception1", "status", "500") + .value(Statistic.Count, 1.0).timer()).isPresent(); } @Test public void rethrownExceptionIsRecordedInMetricTag() { assertThatCode(() -> this.mvc.perform(get("/api/rethrownError")) .andExpect(status().is5xxServerError())); - this.clock.add(SimpleConfig.DEFAULT_STEP); assertThat(this.registry.find("http.server.requests") - .tags("exception", "Exception2").value(Statistic.Count, 1.0).timer()) - .isPresent(); + .tags("exception", "Exception2", "status", "500") + .value(Statistic.Count, 1.0).timer()).isPresent(); } @Configuration diff --git a/spring-boot-project/spring-boot-dependencies/pom.xml b/spring-boot-project/spring-boot-dependencies/pom.xml index 3fabecd175..635026e650 100644 --- a/spring-boot-project/spring-boot-dependencies/pom.xml +++ b/spring-boot-project/spring-boot-dependencies/pom.xml @@ -113,7 +113,7 @@ 1.2.3 1.16.18 2.2.1 - 1.0.0-rc.5 + 1.0.0-rc.6 6.2.2.jre8 2.13.0 1.7.0 @@ -879,6 +879,11 @@ micrometer-registry-jmx ${micrometer.version} + + io.micrometer + micrometer-registry-new-relic + ${micrometer.version} + io.micrometer micrometer-registry-prometheus diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 9b087f6712..df3bd14415 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -1290,8 +1290,10 @@ content into your application. Rather, pick only the properties that you need. management.metrics.export.atlas.step=1m # Step size (i.e. reporting frequency) to use. management.metrics.export.atlas.uri= # URI of the Atlas server. management.metrics.export.datadog.api-key= # Datadog API key. + management.metrics.export.datadog.application-key= # Datadog application key. management.metrics.export.datadog.batch-size= # Number of measurements per request to use for the backend. If more measurements are found, then multiple requests will be made. management.metrics.export.datadog.connect-timeout= # Connection timeout for requests to the backend. + management.metrics.export.datadog.descriptions= # Whether to publish descriptions metadata to Datadog. Turn this off to minimize the amount of metadata sent. management.metrics.export.datadog.enabled=true # Whether exporting of metrics to this backend is enabled. management.metrics.export.datadog.host-tag= # Tag that will be mapped to "host" when shipping metrics to Datadog. Can be omitted if host should be omitted on publishing. management.metrics.export.datadog.num-threads= # Number of threads to use with the metrics publishing scheduler. @@ -1328,6 +1330,7 @@ content into your application. Rather, pick only the properties that you need. management.metrics.export.influx.uri= # URI of the Influx server. management.metrics.export.influx.user-name= # Login user of the Influx server. management.metrics.export.jmx.enabled=true # Whether exporting of metrics to JMX is enabled. + management.metrics.export.jmx.step= # Step size (i.e. reporting frequency) to use. management.metrics.export.prometheus.descriptions= # Enable publishing descriptions as part of the scrape payload to Prometheus. Turn this off to minimize the amount of data sent on each scrape. management.metrics.export.prometheus.enabled=true # Whether exporting of metrics to Prometheus is enabled. management.metrics.export.prometheus.step= # Step size (i.e. reporting frequency) to use. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index 76ecdab49a..dec92b799a 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -1010,9 +1010,9 @@ instance. [[production-ready-metrics-rest-template]] === RestTemplate Metrics -Auto-configuration customizes the auto-configured `RestTemplate` to enable the -instrumentation of its requests. `MetricsRestTemplateCustomizer` can be used to customize -your own `RestTemplate` instances. +The instrumentation of any `RestTemplate` created using the auto-configured +`RestTemplateBuilder` is enabled. It is also possible to apply +`MetricsRestTemplateCustomizer` manually. By default, metrics are generated with the name, `http.client.requests`. The name can be customized by setting the `management.metrics.web.client.requests-metric-name` property.