Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Prometheus Client 1.x and simpleclient #40023

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ dependencies {
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-prometheus-simpleclient")
optional("io.micrometer:micrometer-registry-stackdriver") {
exclude group: "commons-logging", module: "commons-logging"
Expand Down Expand Up @@ -144,6 +145,7 @@ dependencies {
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation("io.micrometer:micrometer-observation-test")
testImplementation("io.projectreactor:reactor-test")
testImplementation("io.prometheus:prometheus-metrics-exposition-formats")
testImplementation("io.r2dbc:r2dbc-h2")
testImplementation("com.squareup.okhttp3:mockwebserver")
testImplementation("com.jayway.jsonpath:json-path")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,39 +16,28 @@

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.prometheus.client.CollectorRegistry;
import io.prometheus.client.exemplars.DefaultExemplarSampler;
import io.prometheus.client.exemplars.ExemplarSampler;
import io.prometheus.client.exemplars.tracer.common.SpanContextSupplier;
import io.prometheus.client.exporter.BasicAuthHttpConnectionFactory;
import io.prometheus.client.exporter.PushGateway;
import io.micrometer.prometheusmetrics.PrometheusConfig;
import io.micrometer.prometheusmetrics.PrometheusMeterRegistry;
import io.prometheus.metrics.model.registry.PrometheusRegistry;
import io.prometheus.metrics.tracer.common.SpanContext;

import org.springframework.beans.factory.ObjectProvider;
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;
import org.springframework.boot.actuate.autoconfigure.metrics.export.ConditionalOnEnabledMetricsExport;
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusPushGatewayManager;
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusPushGatewayManager.ShutdownOperation;
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusScrapeEndpoint;
import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusSimpleclientScrapeEndpoint;
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.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;

/**
* {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Prometheus.
Expand All @@ -58,98 +47,43 @@
* @author Jonatan Ivanov
* @since 2.0.0
*/
@SuppressWarnings("deprecation")
@AutoConfiguration(
before = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },
after = MetricsAutoConfiguration.class)
@ConditionalOnBean(Clock.class)
@ConditionalOnClass(io.micrometer.prometheus.PrometheusMeterRegistry.class)
@ConditionalOnClass(PrometheusMeterRegistry.class)
@ConditionalOnEnabledMetricsExport("prometheus")
@EnableConfigurationProperties(PrometheusProperties.class)
public class PrometheusMetricsExportAutoConfiguration {

@Bean
@ConditionalOnMissingBean
public io.micrometer.prometheus.PrometheusConfig prometheusConfig(PrometheusProperties prometheusProperties) {
public PrometheusConfig prometheusConfig(PrometheusProperties prometheusProperties) {
return new PrometheusPropertiesConfigAdapter(prometheusProperties);
}

@Bean
@ConditionalOnMissingBean
public io.micrometer.prometheus.PrometheusMeterRegistry prometheusMeterRegistry(
io.micrometer.prometheus.PrometheusConfig prometheusConfig, CollectorRegistry collectorRegistry,
Clock clock, ObjectProvider<ExemplarSampler> exemplarSamplerProvider) {
return new io.micrometer.prometheus.PrometheusMeterRegistry(prometheusConfig, collectorRegistry, clock,
exemplarSamplerProvider.getIfAvailable());
public PrometheusMeterRegistry prometheusMeterRegistry(PrometheusConfig prometheusConfig,
PrometheusRegistry prometheusRegistry, Clock clock, ObjectProvider<SpanContext> spanContext) {
return new PrometheusMeterRegistry(prometheusConfig, prometheusRegistry, clock, spanContext.getIfAvailable());
}

@Bean
@ConditionalOnMissingBean
public CollectorRegistry collectorRegistry() {
return new CollectorRegistry(true);
}

@Bean
@ConditionalOnMissingBean(ExemplarSampler.class)
@ConditionalOnBean(SpanContextSupplier.class)
public DefaultExemplarSampler exemplarSampler(SpanContextSupplier spanContextSupplier) {
return new DefaultExemplarSampler(spanContextSupplier);
public PrometheusRegistry prometheusRegistry() {
return new PrometheusRegistry();
}

@Configuration(proxyBeanMethods = false)
@ConditionalOnAvailableEndpoint(endpoint = PrometheusScrapeEndpoint.class)
public static class PrometheusScrapeEndpointConfiguration {

@SuppressWarnings("removal")
@Bean
@ConditionalOnMissingBean
public PrometheusScrapeEndpoint prometheusEndpoint(CollectorRegistry collectorRegistry) {
return new PrometheusScrapeEndpoint(collectorRegistry);
}

}

/**
* Configuration for <a href="https://github.com/prometheus/pushgateway">Prometheus
* Pushgateway</a>.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(PushGateway.class)
@ConditionalOnProperty(prefix = "management.prometheus.metrics.export.pushgateway", name = "enabled")
public static class PrometheusPushGatewayConfiguration {

/**
* The fallback job name. We use 'spring' since there's a history of Prometheus
* spring integration defaulting to that name from when Prometheus integration
* didn't exist in Spring itself.
*/
private static final String FALLBACK_JOB = "spring";

@Bean
@ConditionalOnMissingBean
public PrometheusPushGatewayManager prometheusPushGatewayManager(CollectorRegistry collectorRegistry,
PrometheusProperties prometheusProperties, Environment environment) throws MalformedURLException {
PrometheusProperties.Pushgateway properties = prometheusProperties.getPushgateway();
Duration pushRate = properties.getPushRate();
String job = getJob(properties, environment);
Map<String, String> groupingKey = properties.getGroupingKey();
ShutdownOperation shutdownOperation = properties.getShutdownOperation();
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 initializePushGateway(String url) throws MalformedURLException {
return new PushGateway(new URL(url));
}

private String getJob(PrometheusProperties.Pushgateway properties, Environment environment) {
String job = properties.getJob();
job = (job != null) ? job : environment.getProperty("spring.application.name");
return (job != null) ? job : FALLBACK_JOB;
@ConditionalOnMissingBean({ PrometheusScrapeEndpoint.class, PrometheusSimpleclientScrapeEndpoint.class })
public PrometheusScrapeEndpoint prometheusEndpoint(PrometheusRegistry prometheusRegistry) {
return new PrometheusScrapeEndpoint(prometheusRegistry);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@
package org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

import org.springframework.boot.actuate.metrics.export.prometheus.PrometheusPushGatewayManager.ShutdownOperation;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
Expand All @@ -31,7 +28,6 @@
* @author Stephane Nicoll
* @since 2.0.0
*/
@SuppressWarnings("deprecation")
@ConfigurationProperties(prefix = "management.prometheus.metrics.export")
public class PrometheusProperties {

Expand All @@ -46,17 +42,6 @@ public class PrometheusProperties {
*/
private boolean descriptions = true;

/**
* Configuration options for using Prometheus Pushgateway, allowing metrics to be
* pushed when they cannot be scraped.
*/
private final Pushgateway pushgateway = new Pushgateway();

/**
* Histogram type for backing DistributionSummary and Timer.
*/
private io.micrometer.prometheus.HistogramFlavor histogramFlavor = io.micrometer.prometheus.HistogramFlavor.Prometheus;

/**
* Step size (i.e. reporting frequency) to use.
*/
Expand All @@ -70,14 +55,6 @@ public void setDescriptions(boolean descriptions) {
this.descriptions = descriptions;
}

public io.micrometer.prometheus.HistogramFlavor getHistogramFlavor() {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this from here to avoid the NoClassDefFoundError Moritz found before. I've duplicated the class similar to other classes so there is a simpleclient version now that is used by the corresponding autoconfig. I also removed the Pushgateway related properties until the latest versions of the Prometheus client support it and we can add back auto-configuration support for it here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reverted the change duplicating the ConfigurationProperties class and instead made a HistogramFlavor enum here to avoid requiring the micrometer-registry-prometheus-simpleclient module. The config adapter handles mapping to the Micrometer enum.

return this.histogramFlavor;
}

public void setHistogramFlavor(io.micrometer.prometheus.HistogramFlavor histogramFlavor) {
this.histogramFlavor = histogramFlavor;
}

public Duration getStep() {
return this.step;
}
Expand All @@ -94,119 +71,4 @@ public void setEnabled(boolean enabled) {
this.enabled = enabled;
}

public Pushgateway getPushgateway() {
return this.pushgateway;
}

/**
* Configuration options for push-based interaction with Prometheus.
*/
public static class Pushgateway {

/**
* Enable publishing over a Prometheus Pushgateway.
*/
private Boolean enabled = false;

/**
* Base URL for the Pushgateway.
*/
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.
*/
private Duration pushRate = Duration.ofMinutes(1);

/**
* Job identifier for this application instance.
*/
private String job;

/**
* Grouping key for the pushed metrics.
*/
private Map<String, String> groupingKey = new HashMap<>();

/**
* Operation that should be performed on shutdown.
*/
private ShutdownOperation shutdownOperation = ShutdownOperation.NONE;

public Boolean getEnabled() {
return this.enabled;
}

public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}

public String getBaseUrl() {
return this.baseUrl;
}

public void setBaseUrl(String baseUrl) {
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;
}

public void setPushRate(Duration pushRate) {
this.pushRate = pushRate;
}

public String getJob() {
return this.job;
}

public void setJob(String job) {
this.job = job;
}

public Map<String, String> getGroupingKey() {
return this.groupingKey;
}

public void setGroupingKey(Map<String, String> groupingKey) {
this.groupingKey = groupingKey;
}

public ShutdownOperation getShutdownOperation() {
return this.shutdownOperation;
}

public void setShutdownOperation(ShutdownOperation shutdownOperation) {
this.shutdownOperation = shutdownOperation;
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@

import java.time.Duration;

import io.micrometer.prometheusmetrics.PrometheusConfig;

import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.PropertiesConfigAdapter;

/**
* Adapter to convert {@link PrometheusProperties} to a
* {@link io.micrometer.prometheus.PrometheusConfig}.
* Adapter to convert {@link PrometheusProperties} to a {@link PrometheusConfig}.
*
* @author Jon Schneider
* @author Phillip Webb
*/
@SuppressWarnings("deprecation")
class PrometheusPropertiesConfigAdapter extends PropertiesConfigAdapter<PrometheusProperties>
implements io.micrometer.prometheus.PrometheusConfig {
implements PrometheusConfig {

PrometheusPropertiesConfigAdapter(PrometheusProperties properties) {
super(properties);
Expand All @@ -47,18 +47,12 @@ public String get(String key) {

@Override
public boolean descriptions() {
return get(PrometheusProperties::isDescriptions, io.micrometer.prometheus.PrometheusConfig.super::descriptions);
}

@Override
public io.micrometer.prometheus.HistogramFlavor histogramFlavor() {
return get(PrometheusProperties::getHistogramFlavor,
io.micrometer.prometheus.PrometheusConfig.super::histogramFlavor);
return get(PrometheusProperties::isDescriptions, PrometheusConfig.super::descriptions);
}

@Override
public Duration step() {
return get(PrometheusProperties::getStep, io.micrometer.prometheus.PrometheusConfig.super::step);
return get(PrometheusProperties::getStep, PrometheusConfig.super::step);
}

}
Loading
Loading