From 26ee3465102eea11643998e977870f188cb27d6e Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 18 Mar 2021 19:12:03 -0700 Subject: [PATCH] Polish 'Support OpenMetrics text format with Prometheus' Closes gh-25564 --- .../prometheus/PrometheusScrapeEndpoint.java | 25 ++++--------- ...eTextFormat.java => TextOutputFormat.java} | 35 +++++++++++++++---- 2 files changed, 34 insertions(+), 26 deletions(-) rename spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/{ProducibleTextFormat.java => TextOutputFormat.java} (56%) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/PrometheusScrapeEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/PrometheusScrapeEndpoint.java index 1cc2236334..eb179c5438 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/PrometheusScrapeEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/PrometheusScrapeEndpoint.java @@ -24,14 +24,12 @@ import java.util.Set; import io.prometheus.client.Collector.MetricFamilySamples; import io.prometheus.client.CollectorRegistry; -import io.prometheus.client.exporter.common.TextFormat; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint; import org.springframework.lang.Nullable; -import org.springframework.util.MimeType; /** * {@link Endpoint @Endpoint} that outputs metrics in a format that can be scraped by the @@ -50,30 +48,19 @@ public class PrometheusScrapeEndpoint { this.collectorRegistry = collectorRegistry; } - @ReadOperation(produces = { TextFormat.CONTENT_TYPE_004, TextFormat.CONTENT_TYPE_OPENMETRICS_100 }) - public WebEndpointResponse scrape(ProducibleTextFormat producibleTextFormat, - @Nullable Set includedNames) { + @ReadOperation(producesFrom = TextOutputFormat.class) + public WebEndpointResponse scrape(TextOutputFormat format, @Nullable Set includedNames) { try { Writer writer = new StringWriter(); Enumeration samples = (includedNames != null) ? this.collectorRegistry.filteredMetricFamilySamples(includedNames) : this.collectorRegistry.metricFamilySamples(); - MimeType contentType = producibleTextFormat.getMimeType(); - if (producibleTextFormat == ProducibleTextFormat.CONTENT_TYPE_004) { - TextFormat.write004(writer, samples); - } - else if (producibleTextFormat == ProducibleTextFormat.CONTENT_TYPE_OPENMETRICS_100) { - TextFormat.writeOpenMetrics100(writer, samples); - } - else { - throw new RuntimeException("Unsupported text format '" + producibleTextFormat.getMimeType() + "'"); - } - return new WebEndpointResponse<>(writer.toString(), contentType); + format.write(writer, samples); + return new WebEndpointResponse<>(writer.toString(), format); } catch (IOException ex) { - // This actually never happens since StringWriter::write() doesn't throw any - // IOException - throw new RuntimeException("Writing metrics failed", ex); + // This actually never happens since StringWriter doesn't throw an IOException + throw new IllegalStateException("Writing metrics failed", ex); } } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/ProducibleTextFormat.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/TextOutputFormat.java similarity index 56% rename from spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/ProducibleTextFormat.java rename to spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/TextOutputFormat.java index 31142f3563..ef2812bb87 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/ProducibleTextFormat.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/export/prometheus/TextOutputFormat.java @@ -16,39 +16,60 @@ package org.springframework.boot.actuate.metrics.export.prometheus; +import java.io.IOException; +import java.io.Writer; +import java.util.Enumeration; + +import io.prometheus.client.Collector.MetricFamilySamples; import io.prometheus.client.exporter.common.TextFormat; -import org.springframework.boot.actuate.endpoint.http.Producible; +import org.springframework.boot.actuate.endpoint.annotation.Producible; import org.springframework.util.MimeType; import org.springframework.util.MimeTypeUtils; /** - * A {@link Producible} for Prometheus's {@link TextFormat}. + * A {@link Producible} enum for supported Prometheus {@link TextFormat}. * * @author Andy Wilkinson * @since 2.5.0 */ -public enum ProducibleTextFormat implements Producible { +public enum TextOutputFormat implements Producible { /** * Openmetrics text version 1.0.0. */ - CONTENT_TYPE_OPENMETRICS_100(TextFormat.CONTENT_TYPE_OPENMETRICS_100), + CONTENT_TYPE_OPENMETRICS_100(TextFormat.CONTENT_TYPE_OPENMETRICS_100) { + + @Override + void write(Writer writer, Enumeration samples) throws IOException { + TextFormat.writeOpenMetrics100(writer, samples); + } + + }, /** * Prometheus text version 0.0.4. */ - CONTENT_TYPE_004(TextFormat.CONTENT_TYPE_004); + CONTENT_TYPE_004(TextFormat.CONTENT_TYPE_004) { + + @Override + void write(Writer writer, Enumeration samples) throws IOException { + TextFormat.write004(writer, samples); + } + + }; private final MimeType mimeType; - ProducibleTextFormat(String mimeType) { + TextOutputFormat(String mimeType) { this.mimeType = MimeTypeUtils.parseMimeType(mimeType); } @Override - public MimeType getMimeType() { + public MimeType getProducedMimeType() { return this.mimeType; } + abstract void write(Writer writer, Enumeration samples) throws IOException; + }