From f7a7e8cb8966acdb42b9681beffcf95144f5de9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Thu, 28 Apr 2022 02:31:48 -0500 Subject: [PATCH] Add auto-configuration for OtlpMeterRegistry See gh-30825 --- .../build.gradle | 1 + .../OtlpMetricsExportAutoConfiguration.java | 68 +++++++++++ .../metrics/export/otlp/OtlpProperties.java | 45 +++++++ .../otlp/OtlpPropertiesConfigAdapter.java | 44 +++++++ .../metrics/export/otlp/package-info.java | 20 ++++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + ...lpMetricsExportAutoConfigurationTests.java | 112 ++++++++++++++++++ .../export/otlp/OtlpPropertiesTests.java | 41 +++++++ .../metrics/test/MetricsRun.java | 2 + .../src/docs/asciidoc/actuator/metrics.adoc | 17 +++ 10 files changed, 351 insertions(+) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsExportAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpProperties.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesConfigAdapter.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/package-info.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsExportAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle b/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle index f8e30f8a1af..1a77ab50c6e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle @@ -67,6 +67,7 @@ dependencies { optional("io.micrometer:micrometer-registry-jmx") optional("io.micrometer:micrometer-registry-kairos") optional("io.micrometer:micrometer-registry-new-relic") + optional("io.micrometer:micrometer-registry-otlp") optional("io.micrometer:micrometer-registry-prometheus") optional("io.micrometer:micrometer-registry-stackdriver") { exclude group: "commons-logging", module: "commons-logging" diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsExportAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsExportAutoConfiguration.java new file mode 100644 index 00000000000..29e89c29e50 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsExportAutoConfiguration.java @@ -0,0 +1,68 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure.metrics.export.otlp; + +import io.micrometer.core.instrument.Clock; +import io.micrometer.registry.otlp.OtlpConfig; +import io.micrometer.registry.otlp.OtlpMeterRegistry; + +import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.export.ConditionalOnEnabledMetricsExport; +import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to OTLP. + * + * @author Eddú Meléndez + * @since 3.0.0 + */ +@AutoConfiguration( + before = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class }, + after = MetricsAutoConfiguration.class) +@ConditionalOnBean(Clock.class) +@ConditionalOnClass(OtlpMeterRegistry.class) +@ConditionalOnEnabledMetricsExport("otlp") +@EnableConfigurationProperties(OtlpProperties.class) +public class OtlpMetricsExportAutoConfiguration { + + private final OtlpProperties properties; + + public OtlpMetricsExportAutoConfiguration(OtlpProperties properties) { + this.properties = properties; + } + + @Bean + @ConditionalOnMissingBean + public OtlpConfig otlpConfig() { + return new OtlpPropertiesConfigAdapter(this.properties); + } + + @Bean + @ConditionalOnMissingBean + public OtlpMeterRegistry otlpMeterRegistry(OtlpConfig otlpConfig, Clock clock) { + return new OtlpMeterRegistry(otlpConfig, clock); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpProperties.java new file mode 100644 index 00000000000..d461b5a2c2b --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpProperties.java @@ -0,0 +1,45 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure.metrics.export.otlp; + +import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * {@link ConfigurationProperties @ConfigurationProperties} for configuring OTLP metrics + * export. + * + * @author Eddú Meléndez + * @since 3.0.0 + */ +@ConfigurationProperties(prefix = "management.otlp.metrics.export") +public class OtlpProperties extends StepRegistryProperties { + + /** + * URI of the OLTP server. + */ + private String url = "http://localhost:4318/v1/metrics"; + + public String getUrl() { + return this.url; + } + + public void setUrl(String url) { + this.url = url; + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesConfigAdapter.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesConfigAdapter.java new file mode 100644 index 00000000000..7300b42a285 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesConfigAdapter.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure.metrics.export.otlp; + +import io.micrometer.registry.otlp.OtlpConfig; + +import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapter; + +/** + * Adapter to convert {@link OtlpProperties} to an {@link OtlpConfig}. + * + * @author Eddú Meléndez + */ +class OtlpPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter implements OtlpConfig { + + OtlpPropertiesConfigAdapter(OtlpProperties properties) { + super(properties); + } + + @Override + public String prefix() { + return "management.otlp.metrics.export"; + } + + @Override + public String url() { + return get(OtlpProperties::getUrl, OtlpConfig.super::url); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/package-info.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/package-info.java new file mode 100644 index 00000000000..22ea3c4c0e7 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Support for exporting actuator metrics to OTLP. + */ +package org.springframework.boot.actuate.autoconfigure.metrics.export.otlp; diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index cb999708e2c..048d12820b6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -59,6 +59,7 @@ org.springframework.boot.actuate.autoconfigure.metrics.export.humio.HumioMetrics org.springframework.boot.actuate.autoconfigure.metrics.export.influx.InfluxMetricsExportAutoConfiguration org.springframework.boot.actuate.autoconfigure.metrics.export.jmx.JmxMetricsExportAutoConfiguration org.springframework.boot.actuate.autoconfigure.metrics.export.kairos.KairosMetricsExportAutoConfiguration +org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsExportAutoConfiguration org.springframework.boot.actuate.autoconfigure.metrics.export.newrelic.NewRelicMetricsExportAutoConfiguration org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusMetricsExportAutoConfiguration org.springframework.boot.actuate.autoconfigure.metrics.export.signalfx.SignalFxMetricsExportAutoConfiguration diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsExportAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsExportAutoConfigurationTests.java new file mode 100644 index 00000000000..2cbb87dd0cf --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpMetricsExportAutoConfigurationTests.java @@ -0,0 +1,112 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure.metrics.export.otlp; + +import io.micrometer.core.instrument.Clock; +import io.micrometer.registry.otlp.OtlpConfig; +import io.micrometer.registry.otlp.OtlpMeterRegistry; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +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.Import; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link OtlpMetricsExportAutoConfiguration}. + * + * @author Eddú Meléndez + */ +class OtlpMetricsExportAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(OtlpMetricsExportAutoConfiguration.class)); + + @Test + void backsOffWithoutAClock() { + this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(OtlpMeterRegistry.class)); + } + + @Test + void autoConfiguresConfigAndMeterRegistry() { + this.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> assertThat(context) + .hasSingleBean(OtlpMeterRegistry.class).hasSingleBean(OtlpConfig.class)); + } + + @Test + void autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() { + this.contextRunner.withUserConfiguration(BaseConfiguration.class) + .withPropertyValues("management.defaults.metrics.export.enabled=false") + .run((context) -> assertThat(context).doesNotHaveBean(OtlpMeterRegistry.class) + .doesNotHaveBean(OtlpConfig.class)); + } + + @Test + void autoConfigurationCanBeDisabledWithSpecificEnabledProperty() { + this.contextRunner.withUserConfiguration(BaseConfiguration.class) + .withPropertyValues("management.otlp.metrics.export.enabled=false").run((context) -> assertThat(context) + .doesNotHaveBean(OtlpMeterRegistry.class).doesNotHaveBean(OtlpConfig.class)); + } + + @Test + void allowsCustomConfigToBeUsed() { + this.contextRunner.withUserConfiguration(CustomConfigConfiguration.class).run((context) -> assertThat(context) + .hasSingleBean(OtlpMeterRegistry.class).hasSingleBean(OtlpConfig.class).hasBean("customConfig")); + } + + @Test + void allowsRegistryToBeCustomized() { + this.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class).run((context) -> assertThat(context) + .hasSingleBean(OtlpMeterRegistry.class).hasSingleBean(OtlpConfig.class).hasBean("customRegistry")); + } + + @Configuration(proxyBeanMethods = false) + static class BaseConfiguration { + + @Bean + Clock customClock() { + return Clock.SYSTEM; + } + + } + + @Configuration(proxyBeanMethods = false) + @Import(BaseConfiguration.class) + static class CustomConfigConfiguration { + + @Bean + OtlpConfig customConfig() { + return (key) -> null; + } + + } + + @Configuration(proxyBeanMethods = false) + @Import(BaseConfiguration.class) + static class CustomRegistryConfiguration { + + @Bean + OtlpMeterRegistry customRegistry(OtlpConfig config, Clock clock) { + return new OtlpMeterRegistry(config, clock); + } + + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesTests.java new file mode 100644 index 00000000000..534d8f946e4 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesTests.java @@ -0,0 +1,41 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.autoconfigure.metrics.export.otlp; + +import io.micrometer.registry.otlp.OtlpConfig; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesTests; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link OtlpProperties}. + * + * @author Eddú Meléndez + */ +class OtlpPropertiesTests extends StepRegistryPropertiesTests { + + @Test + void defaultValuesAreConsistent() { + OtlpProperties properties = new OtlpProperties(); + OtlpConfig config = OtlpConfig.DEFAULT; + assertStepRegistryDefaultValues(properties, config); + assertThat(properties.getUrl()).isEqualTo(config.url()); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java index 8df509ddb34..b2dbcc76489 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsRun.java @@ -30,6 +30,7 @@ import org.springframework.boot.actuate.autoconfigure.metrics.export.graphite.Gr import org.springframework.boot.actuate.autoconfigure.metrics.export.influx.InfluxMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.jmx.JmxMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.newrelic.NewRelicMetricsExportAutoConfiguration; +import org.springframework.boot.actuate.autoconfigure.metrics.export.otlp.OtlpMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.signalfx.SignalFxMetricsExportAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration; @@ -59,6 +60,7 @@ public final class MetricsRun { implementations.add(InfluxMetricsExportAutoConfiguration.class); implementations.add(JmxMetricsExportAutoConfiguration.class); implementations.add(NewRelicMetricsExportAutoConfiguration.class); + implementations.add(OtlpMetricsExportAutoConfiguration.class); implementations.add(PrometheusMetricsExportAutoConfiguration.class); implementations.add(SimpleMetricsExportAutoConfiguration.class); implementations.add(SignalFxMetricsExportAutoConfiguration.class); diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/metrics.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/metrics.adoc index 6445ddd6515..a43cd3d0bdb 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/metrics.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/metrics.adoc @@ -14,6 +14,7 @@ Spring Boot Actuator provides dependency management and auto-configuration for h - <> - <> - <> +- <> - <> - <> - <> @@ -437,6 +438,22 @@ Finally, you can take full control by defining your own `NewRelicClientProvider` +[[actuator.metrics.export.otlp]] +==== OpenTelemetry +By default, metrics are exported to {micrometer-registry-docs}/otlp[OpenTelemetry] running on your local machine. +You can provide the location of the https://opentelemetry.io/[OpenTelemtry metric endpoint] to use by using: + +[source,yaml,indent=0,subs="verbatim",configprops,configblocks] +---- + management: + otlp: + metrics: + export: + url: "https://otlp.example.com:4318/v1/metrics" +---- + + + [[actuator.metrics.export.prometheus]] ==== Prometheus {micrometer-registry-docs}/prometheus[Prometheus] expects to scrape or poll individual application instances for metrics.