diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfiguration.java index 99e6985b1f..79c9eed75f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfiguration.java @@ -16,6 +16,11 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus; +import java.net.MalformedURLException; +import java.net.URL; +import java.time.Duration; +import java.util.Map; + import io.micrometer.core.instrument.Clock; import io.micrometer.prometheus.PrometheusConfig; import io.micrometer.prometheus.PrometheusMeterRegistry; @@ -24,6 +29,7 @@ import io.prometheus.client.exporter.BasicAuthHttpConnectionFactory; import io.prometheus.client.exporter.PushGateway; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint; import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration; @@ -44,21 +50,17 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.core.log.LogMessage; - -import java.net.MalformedURLException; -import java.net.URL; -import java.time.Duration; -import java.util.Map; +import org.springframework.util.StringUtils; /** * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Prometheus. * + * @since 2.0.0 * @author Jon Schneider * @author David J. M. Karlsen - * @since 2.0.0 */ @Configuration(proxyBeanMethods = false) -@AutoConfigureBefore({CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class}) +@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class }) @AutoConfigureAfter(MetricsAutoConfiguration.class) @ConditionalOnBean(Clock.class) @ConditionalOnClass(PrometheusMeterRegistry.class) @@ -75,7 +77,7 @@ public class PrometheusMetricsExportAutoConfiguration { @Bean @ConditionalOnMissingBean public PrometheusMeterRegistry prometheusMeterRegistry(PrometheusConfig prometheusConfig, - CollectorRegistry collectorRegistry, Clock clock) { + CollectorRegistry collectorRegistry, Clock clock) { return new PrometheusMeterRegistry(prometheusConfig, collectorRegistry, clock); } @@ -118,30 +120,30 @@ public class PrometheusMetricsExportAutoConfiguration { @Bean @ConditionalOnMissingBean public PrometheusPushGatewayManager prometheusPushGatewayManager(CollectorRegistry collectorRegistry, - PrometheusProperties prometheusProperties, Environment environment) { + PrometheusProperties prometheusProperties, Environment environment) { PrometheusProperties.Pushgateway properties = prometheusProperties.getPushgateway(); Duration pushRate = properties.getPushRate(); String job = getJob(properties, environment); Map groupingKey = properties.getGroupingKey(); ShutdownOperation shutdownOperation = properties.getShutdownOperation(); - return new PrometheusPushGatewayManager(getPushGateway(properties.getBaseUrl()), collectorRegistry, - pushRate, job, groupingKey, shutdownOperation); + PushGateway pushGateway = initializePushGateway(properties.getBaseUrl()); + if (StringUtils.hasText(properties.getUsername())) { + pushGateway.setConnectionFactory( + new BasicAuthHttpConnectionFactory(properties.getUsername(), properties.getPassword())); + } + return new PrometheusPushGatewayManager(pushGateway, collectorRegistry, pushRate, job, groupingKey, + shutdownOperation); } - private PushGateway getPushGateway(String url) { - PushGateway pushGateway = null; + private PushGateway initializePushGateway(String url) { try { - pushGateway = new PushGateway(new URL(url)); - } catch (MalformedURLException ex) { + return new PushGateway(new URL(url)); + } + catch (MalformedURLException ex) { logger.warn(LogMessage .format("Invalid PushGateway base url '%s': update your configuration to a valid URL", url)); - pushGateway = new PushGateway(url); - } - PrometheusProperties.Pushgateway properties = prometheusProperties.getPushgateway(); - if (properties.getAuthEnabled()) { - pushgateway.setConnectionFactory(new BasicAuthHttpConnectionFactory(properties.getAuthusername(), properties.getAuthpassword())); + return new PushGateway(url); } - return pushGateway; } private String getJob(PrometheusProperties.Pushgateway properties, Environment environment) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusProperties.java index 2da509b323..3d30136650 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusProperties.java @@ -16,14 +16,15 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus; -import io.micrometer.prometheus.HistogramFlavor; -import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusPushGatewayManager.ShutdownOperation; -import org.springframework.boot.context.properties.ConfigurationProperties; - import java.time.Duration; import java.util.HashMap; import java.util.Map; +import io.micrometer.prometheus.HistogramFlavor; + +import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusPushGatewayManager.ShutdownOperation; +import org.springframework.boot.context.properties.ConfigurationProperties; + /** * {@link ConfigurationProperties @ConfigurationProperties} for configuring metrics export * to Prometheus. @@ -85,7 +86,6 @@ public class PrometheusProperties { return this.pushgateway; } - /** * Configuration options for push-based interaction with Prometheus. */ @@ -102,34 +102,29 @@ public class PrometheusProperties { private String baseUrl = "http://localhost:9091"; /** - * Frequency with which to push metrics. - */ - private Duration pushRate = Duration.ofMinutes(1); - - /** - * Job identifier for this application instance. + * Login user of the Prometheus Pushgateway. */ - private String job; + private String username; /** - * Grouping key for the pushed metrics. + * Login password of the Prometheus Pushgateway. */ - private Map groupingKey = new HashMap<>(); + private String password; /** - * Enable publishing via a Prometheus Pushgateway with Basic Auth. + * Frequency with which to push metrics. */ - private Boolean authEnabled = false; + private Duration pushRate = Duration.ofMinutes(1); /** - * Prometheus Pushgateway basic-auth username. + * Job identifier for this application instance. */ - private String authusername; + private String job; /** - * Prometheus Pushgateway basic-auth password. + * Grouping key for the pushed metrics. */ - private String authpassword; + private Map groupingKey = new HashMap<>(); /** * Operation that should be performed on shutdown. @@ -152,6 +147,22 @@ public class PrometheusProperties { this.baseUrl = baseUrl; } + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } + public Duration getPushRate() { return this.pushRate; } @@ -184,29 +195,6 @@ public class PrometheusProperties { this.shutdownOperation = shutdownOperation; } - public Boolean getAuthEnabled() { - return this.authEnabled; - } - - public void setAuthEnabled(Boolean authEnabled) { - this.authEnabled = authEnabled; - } - - public String getAuthusername() { - return authusername; - } - - public void setAuthusername(String authusername) { - this.authusername = authusername; - } - - public String getAuthpassword() { - return authpassword; - } - - public void setAuthpassword(String authpassword) { - this.authpassword = authpassword; - } } } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfigurationTests.java index b4813b3d8d..51a2c9b0bb 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfigurationTests.java @@ -16,10 +16,16 @@ package org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus; +import java.util.function.Consumer; + import io.micrometer.core.instrument.Clock; import io.micrometer.prometheus.PrometheusConfig; import io.micrometer.prometheus.PrometheusMeterRegistry; import io.prometheus.client.CollectorRegistry; +import io.prometheus.client.exporter.BasicAuthHttpConnectionFactory; +import io.prometheus.client.exporter.DefaultHttpConnectionFactory; +import io.prometheus.client.exporter.HttpConnectionFactory; +import io.prometheus.client.exporter.PushGateway; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -29,6 +35,7 @@ import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusScra import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.context.annotation.Bean; @@ -42,6 +49,7 @@ import static org.assertj.core.api.Assertions.assertThat; * Tests for {@link PrometheusMetricsExportAutoConfiguration}. * * @author Andy Wilkinson + * @author Stephane Nicoll */ @ExtendWith(OutputCaptureExtension.class) class PrometheusMetricsExportAutoConfigurationTests { @@ -142,6 +150,15 @@ class PrometheusMetricsExportAutoConfigurationTests { }); } + @Test + void withPushGatewayNoBasicAuth() { + this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class)) + .withPropertyValues("management.metrics.export.prometheus.pushgateway.enabled=true") + .withUserConfiguration(BaseConfiguration.class) + .run(hasHttpConnectionFactory((httpConnectionFactory) -> assertThat(httpConnectionFactory) + .isInstanceOf(DefaultHttpConnectionFactory.class))); + } + @Test @Deprecated void withCustomLegacyPushGatewayURL(CapturedOutput output) { @@ -163,11 +180,34 @@ class PrometheusMetricsExportAutoConfigurationTests { .run((context) -> hasGatewayURL(context, "https://example.com:8080/metrics/")); } + @Test + void withPushGatewayBasicAuth() { + this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class)) + .withPropertyValues("management.metrics.export.prometheus.pushgateway.enabled=true", + "management.metrics.export.prometheus.pushgateway.username=admin", + "management.metrics.export.prometheus.pushgateway.password=secret") + .withUserConfiguration(BaseConfiguration.class) + .run(hasHttpConnectionFactory((httpConnectionFactory) -> assertThat(httpConnectionFactory) + .isInstanceOf(BasicAuthHttpConnectionFactory.class))); + } + private void hasGatewayURL(AssertableApplicationContext context, String url) { + assertThat(getPushGateway(context)).hasFieldOrPropertyWithValue("gatewayBaseURL", url); + } + + private ContextConsumer hasHttpConnectionFactory( + Consumer httpConnectionFactory) { + return (context) -> { + PushGateway pushGateway = getPushGateway(context); + httpConnectionFactory + .accept((HttpConnectionFactory) ReflectionTestUtils.getField(pushGateway, "connectionFactory")); + }; + } + + private PushGateway getPushGateway(AssertableApplicationContext context) { assertThat(context).hasSingleBean(PrometheusPushGatewayManager.class); PrometheusPushGatewayManager gatewayManager = context.getBean(PrometheusPushGatewayManager.class); - Object pushGateway = ReflectionTestUtils.getField(gatewayManager, "pushGateway"); - assertThat(pushGateway).hasFieldOrPropertyWithValue("gatewayBaseURL", url); + return (PushGateway) ReflectionTestUtils.getField(gatewayManager, "pushGateway"); } @Configuration(proxyBeanMethods = false)