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 e0e69fa7f9b..79c9eed75f6 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 @@ -25,6 +25,7 @@ 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.PushGateway; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -49,6 +50,7 @@ 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 org.springframework.util.StringUtils; /** * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Prometheus. @@ -124,11 +126,16 @@ public class PrometheusMetricsExportAutoConfiguration { 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) { + private PushGateway initializePushGateway(String url) { try { return new PushGateway(new URL(url)); } 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 74023c8f0d1..3d301366507 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 @@ -101,6 +101,16 @@ public class PrometheusProperties { */ private String baseUrl = "http://localhost:9091"; + /** + * Login user of the Prometheus Pushgateway. + */ + private String username; + + /** + * Login password of the Prometheus Pushgateway. + */ + private String password; + /** * Frequency with which to push metrics. */ @@ -137,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; } 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 b4813b3d8d1..51a2c9b0bbf 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)