Skip to content

Commit 14eb041

Browse files
committed
Polish "Add basic auth support for Prometheus pushgateway"
See gh-22548
1 parent 9ddc97f commit 14eb041

File tree

3 files changed

+96
-66
lines changed

3 files changed

+96
-66
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfiguration.java

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus;
1818

19+
import java.net.MalformedURLException;
20+
import java.net.URL;
21+
import java.time.Duration;
22+
import java.util.Map;
23+
1924
import io.micrometer.core.instrument.Clock;
2025
import io.micrometer.prometheus.PrometheusConfig;
2126
import io.micrometer.prometheus.PrometheusMeterRegistry;
@@ -24,6 +29,7 @@
2429
import io.prometheus.client.exporter.PushGateway;
2530
import org.apache.commons.logging.Log;
2631
import org.apache.commons.logging.LogFactory;
32+
2733
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
2834
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
2935
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
@@ -44,21 +50,17 @@
4450
import org.springframework.context.annotation.Configuration;
4551
import org.springframework.core.env.Environment;
4652
import org.springframework.core.log.LogMessage;
47-
48-
import java.net.MalformedURLException;
49-
import java.net.URL;
50-
import java.time.Duration;
51-
import java.util.Map;
53+
import org.springframework.util.StringUtils;
5254

5355
/**
5456
* {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Prometheus.
5557
*
58+
* @since 2.0.0
5659
* @author Jon Schneider
5760
* @author David J. M. Karlsen
58-
* @since 2.0.0
5961
*/
6062
@Configuration(proxyBeanMethods = false)
61-
@AutoConfigureBefore({CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class})
63+
@AutoConfigureBefore({ CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class })
6264
@AutoConfigureAfter(MetricsAutoConfiguration.class)
6365
@ConditionalOnBean(Clock.class)
6466
@ConditionalOnClass(PrometheusMeterRegistry.class)
@@ -75,7 +77,7 @@ public PrometheusConfig prometheusConfig(PrometheusProperties prometheusProperti
7577
@Bean
7678
@ConditionalOnMissingBean
7779
public PrometheusMeterRegistry prometheusMeterRegistry(PrometheusConfig prometheusConfig,
78-
CollectorRegistry collectorRegistry, Clock clock) {
80+
CollectorRegistry collectorRegistry, Clock clock) {
7981
return new PrometheusMeterRegistry(prometheusConfig, collectorRegistry, clock);
8082
}
8183

@@ -118,30 +120,30 @@ public static class PrometheusPushGatewayConfiguration {
118120
@Bean
119121
@ConditionalOnMissingBean
120122
public PrometheusPushGatewayManager prometheusPushGatewayManager(CollectorRegistry collectorRegistry,
121-
PrometheusProperties prometheusProperties, Environment environment) {
123+
PrometheusProperties prometheusProperties, Environment environment) {
122124
PrometheusProperties.Pushgateway properties = prometheusProperties.getPushgateway();
123125
Duration pushRate = properties.getPushRate();
124126
String job = getJob(properties, environment);
125127
Map<String, String> groupingKey = properties.getGroupingKey();
126128
ShutdownOperation shutdownOperation = properties.getShutdownOperation();
127-
return new PrometheusPushGatewayManager(getPushGateway(properties.getBaseUrl()), collectorRegistry,
128-
pushRate, job, groupingKey, shutdownOperation);
129+
PushGateway pushGateway = initializePushGateway(properties.getBaseUrl());
130+
if (StringUtils.hasText(properties.getUsername())) {
131+
pushGateway.setConnectionFactory(
132+
new BasicAuthHttpConnectionFactory(properties.getUsername(), properties.getPassword()));
133+
}
134+
return new PrometheusPushGatewayManager(pushGateway, collectorRegistry, pushRate, job, groupingKey,
135+
shutdownOperation);
129136
}
130137

131-
private PushGateway getPushGateway(String url) {
132-
PushGateway pushGateway = null;
138+
private PushGateway initializePushGateway(String url) {
133139
try {
134-
pushGateway = new PushGateway(new URL(url));
135-
} catch (MalformedURLException ex) {
140+
return new PushGateway(new URL(url));
141+
}
142+
catch (MalformedURLException ex) {
136143
logger.warn(LogMessage
137144
.format("Invalid PushGateway base url '%s': update your configuration to a valid URL", url));
138-
pushGateway = new PushGateway(url);
139-
}
140-
PrometheusProperties.Pushgateway properties = prometheusProperties.getPushgateway();
141-
if (properties.getAuthEnabled()) {
142-
pushgateway.setConnectionFactory(new BasicAuthHttpConnectionFactory(properties.getAuthusername(), properties.getAuthpassword()));
145+
return new PushGateway(url);
143146
}
144-
return pushGateway;
145147
}
146148

147149
private String getJob(PrometheusProperties.Pushgateway properties, Environment environment) {

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusProperties.java

Lines changed: 31 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus;
1818

19-
import io.micrometer.prometheus.HistogramFlavor;
20-
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusPushGatewayManager.ShutdownOperation;
21-
import org.springframework.boot.context.properties.ConfigurationProperties;
22-
2319
import java.time.Duration;
2420
import java.util.HashMap;
2521
import java.util.Map;
2622

23+
import io.micrometer.prometheus.HistogramFlavor;
24+
25+
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusPushGatewayManager.ShutdownOperation;
26+
import org.springframework.boot.context.properties.ConfigurationProperties;
27+
2728
/**
2829
* {@link ConfigurationProperties @ConfigurationProperties} for configuring metrics export
2930
* to Prometheus.
@@ -85,7 +86,6 @@ public Pushgateway getPushgateway() {
8586
return this.pushgateway;
8687
}
8788

88-
8989
/**
9090
* Configuration options for push-based interaction with Prometheus.
9191
*/
@@ -102,34 +102,29 @@ public static class Pushgateway {
102102
private String baseUrl = "http://localhost:9091";
103103

104104
/**
105-
* Frequency with which to push metrics.
106-
*/
107-
private Duration pushRate = Duration.ofMinutes(1);
108-
109-
/**
110-
* Job identifier for this application instance.
105+
* Login user of the Prometheus Pushgateway.
111106
*/
112-
private String job;
107+
private String username;
113108

114109
/**
115-
* Grouping key for the pushed metrics.
110+
* Login password of the Prometheus Pushgateway.
116111
*/
117-
private Map<String, String> groupingKey = new HashMap<>();
112+
private String password;
118113

119114
/**
120-
* Enable publishing via a Prometheus Pushgateway with Basic Auth.
115+
* Frequency with which to push metrics.
121116
*/
122-
private Boolean authEnabled = false;
117+
private Duration pushRate = Duration.ofMinutes(1);
123118

124119
/**
125-
* Prometheus Pushgateway basic-auth username.
120+
* Job identifier for this application instance.
126121
*/
127-
private String authusername;
122+
private String job;
128123

129124
/**
130-
* Prometheus Pushgateway basic-auth password.
125+
* Grouping key for the pushed metrics.
131126
*/
132-
private String authpassword;
127+
private Map<String, String> groupingKey = new HashMap<>();
133128

134129
/**
135130
* Operation that should be performed on shutdown.
@@ -152,6 +147,22 @@ public void setBaseUrl(String baseUrl) {
152147
this.baseUrl = baseUrl;
153148
}
154149

150+
public String getUsername() {
151+
return this.username;
152+
}
153+
154+
public void setUsername(String username) {
155+
this.username = username;
156+
}
157+
158+
public String getPassword() {
159+
return this.password;
160+
}
161+
162+
public void setPassword(String password) {
163+
this.password = password;
164+
}
165+
155166
public Duration getPushRate() {
156167
return this.pushRate;
157168
}
@@ -184,29 +195,6 @@ public void setShutdownOperation(ShutdownOperation shutdownOperation) {
184195
this.shutdownOperation = shutdownOperation;
185196
}
186197

187-
public Boolean getAuthEnabled() {
188-
return this.authEnabled;
189-
}
190-
191-
public void setAuthEnabled(Boolean authEnabled) {
192-
this.authEnabled = authEnabled;
193-
}
194-
195-
public String getAuthusername() {
196-
return authusername;
197-
}
198-
199-
public void setAuthusername(String authusername) {
200-
this.authusername = authusername;
201-
}
202-
203-
public String getAuthpassword() {
204-
return authpassword;
205-
}
206-
207-
public void setAuthpassword(String authpassword) {
208-
this.authpassword = authpassword;
209-
}
210198
}
211199

212200
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfigurationTests.java

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,16 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus;
1818

19+
import java.util.function.Consumer;
20+
1921
import io.micrometer.core.instrument.Clock;
2022
import io.micrometer.prometheus.PrometheusConfig;
2123
import io.micrometer.prometheus.PrometheusMeterRegistry;
2224
import io.prometheus.client.CollectorRegistry;
25+
import io.prometheus.client.exporter.BasicAuthHttpConnectionFactory;
26+
import io.prometheus.client.exporter.DefaultHttpConnectionFactory;
27+
import io.prometheus.client.exporter.HttpConnectionFactory;
28+
import io.prometheus.client.exporter.PushGateway;
2329
import org.junit.jupiter.api.Test;
2430
import org.junit.jupiter.api.extension.ExtendWith;
2531

@@ -29,6 +35,7 @@
2935
import org.springframework.boot.autoconfigure.AutoConfigurations;
3036
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
3137
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
38+
import org.springframework.boot.test.context.runner.ContextConsumer;
3239
import org.springframework.boot.test.system.CapturedOutput;
3340
import org.springframework.boot.test.system.OutputCaptureExtension;
3441
import org.springframework.context.annotation.Bean;
@@ -42,6 +49,7 @@
4249
* Tests for {@link PrometheusMetricsExportAutoConfiguration}.
4350
*
4451
* @author Andy Wilkinson
52+
* @author Stephane Nicoll
4553
*/
4654
@ExtendWith(OutputCaptureExtension.class)
4755
class PrometheusMetricsExportAutoConfigurationTests {
@@ -142,6 +150,15 @@ void withPushGatewayEnabled(CapturedOutput output) {
142150
});
143151
}
144152

153+
@Test
154+
void withPushGatewayNoBasicAuth() {
155+
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
156+
.withPropertyValues("management.metrics.export.prometheus.pushgateway.enabled=true")
157+
.withUserConfiguration(BaseConfiguration.class)
158+
.run(hasHttpConnectionFactory((httpConnectionFactory) -> assertThat(httpConnectionFactory)
159+
.isInstanceOf(DefaultHttpConnectionFactory.class)));
160+
}
161+
145162
@Test
146163
@Deprecated
147164
void withCustomLegacyPushGatewayURL(CapturedOutput output) {
@@ -163,11 +180,34 @@ void withCustomPushGatewayURL() {
163180
.run((context) -> hasGatewayURL(context, "https://example.com:8080/metrics/"));
164181
}
165182

183+
@Test
184+
void withPushGatewayBasicAuth() {
185+
this.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))
186+
.withPropertyValues("management.metrics.export.prometheus.pushgateway.enabled=true",
187+
"management.metrics.export.prometheus.pushgateway.username=admin",
188+
"management.metrics.export.prometheus.pushgateway.password=secret")
189+
.withUserConfiguration(BaseConfiguration.class)
190+
.run(hasHttpConnectionFactory((httpConnectionFactory) -> assertThat(httpConnectionFactory)
191+
.isInstanceOf(BasicAuthHttpConnectionFactory.class)));
192+
}
193+
166194
private void hasGatewayURL(AssertableApplicationContext context, String url) {
195+
assertThat(getPushGateway(context)).hasFieldOrPropertyWithValue("gatewayBaseURL", url);
196+
}
197+
198+
private ContextConsumer<AssertableApplicationContext> hasHttpConnectionFactory(
199+
Consumer<HttpConnectionFactory> httpConnectionFactory) {
200+
return (context) -> {
201+
PushGateway pushGateway = getPushGateway(context);
202+
httpConnectionFactory
203+
.accept((HttpConnectionFactory) ReflectionTestUtils.getField(pushGateway, "connectionFactory"));
204+
};
205+
}
206+
207+
private PushGateway getPushGateway(AssertableApplicationContext context) {
167208
assertThat(context).hasSingleBean(PrometheusPushGatewayManager.class);
168209
PrometheusPushGatewayManager gatewayManager = context.getBean(PrometheusPushGatewayManager.class);
169-
Object pushGateway = ReflectionTestUtils.getField(gatewayManager, "pushGateway");
170-
assertThat(pushGateway).hasFieldOrPropertyWithValue("gatewayBaseURL", url);
210+
return (PushGateway) ReflectionTestUtils.getField(gatewayManager, "pushGateway");
171211
}
172212

173213
@Configuration(proxyBeanMethods = false)

0 commit comments

Comments
 (0)