Commit 26ee3465 authored by Phillip Webb's avatar Phillip Webb

Polish 'Support OpenMetrics text format with Prometheus'

Closes gh-25564
parent 11b4a19d
...@@ -24,14 +24,12 @@ import java.util.Set; ...@@ -24,14 +24,12 @@ import java.util.Set;
import io.prometheus.client.Collector.MetricFamilySamples; import io.prometheus.client.Collector.MetricFamilySamples;
import io.prometheus.client.CollectorRegistry; 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.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse; import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint; import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;
import org.springframework.lang.Nullable; 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 * {@link Endpoint @Endpoint} that outputs metrics in a format that can be scraped by the
...@@ -50,30 +48,19 @@ public class PrometheusScrapeEndpoint { ...@@ -50,30 +48,19 @@ public class PrometheusScrapeEndpoint {
this.collectorRegistry = collectorRegistry; this.collectorRegistry = collectorRegistry;
} }
@ReadOperation(produces = { TextFormat.CONTENT_TYPE_004, TextFormat.CONTENT_TYPE_OPENMETRICS_100 }) @ReadOperation(producesFrom = TextOutputFormat.class)
public WebEndpointResponse<String> scrape(ProducibleTextFormat producibleTextFormat, public WebEndpointResponse<String> scrape(TextOutputFormat format, @Nullable Set<String> includedNames) {
@Nullable Set<String> includedNames) {
try { try {
Writer writer = new StringWriter(); Writer writer = new StringWriter();
Enumeration<MetricFamilySamples> samples = (includedNames != null) Enumeration<MetricFamilySamples> samples = (includedNames != null)
? this.collectorRegistry.filteredMetricFamilySamples(includedNames) ? this.collectorRegistry.filteredMetricFamilySamples(includedNames)
: this.collectorRegistry.metricFamilySamples(); : this.collectorRegistry.metricFamilySamples();
MimeType contentType = producibleTextFormat.getMimeType(); format.write(writer, samples);
if (producibleTextFormat == ProducibleTextFormat.CONTENT_TYPE_004) { return new WebEndpointResponse<>(writer.toString(), format);
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);
} }
catch (IOException ex) { catch (IOException ex) {
// This actually never happens since StringWriter::write() doesn't throw any // This actually never happens since StringWriter doesn't throw an IOException
// IOException throw new IllegalStateException("Writing metrics failed", ex);
throw new RuntimeException("Writing metrics failed", ex);
} }
} }
......
...@@ -16,39 +16,60 @@ ...@@ -16,39 +16,60 @@
package org.springframework.boot.actuate.metrics.export.prometheus; 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 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.MimeType;
import org.springframework.util.MimeTypeUtils; 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 * @author Andy Wilkinson
* @since 2.5.0 * @since 2.5.0
*/ */
public enum ProducibleTextFormat implements Producible<ProducibleTextFormat> { public enum TextOutputFormat implements Producible<TextOutputFormat> {
/** /**
* Openmetrics text version 1.0.0. * 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<MetricFamilySamples> samples) throws IOException {
TextFormat.writeOpenMetrics100(writer, samples);
}
},
/** /**
* Prometheus text version 0.0.4. * 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<MetricFamilySamples> samples) throws IOException {
TextFormat.write004(writer, samples);
}
};
private final MimeType mimeType; private final MimeType mimeType;
ProducibleTextFormat(String mimeType) { TextOutputFormat(String mimeType) {
this.mimeType = MimeTypeUtils.parseMimeType(mimeType); this.mimeType = MimeTypeUtils.parseMimeType(mimeType);
} }
@Override @Override
public MimeType getMimeType() { public MimeType getProducedMimeType() {
return this.mimeType; return this.mimeType;
} }
abstract void write(Writer writer, Enumeration<MetricFamilySamples> samples) throws IOException;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment