diff options
author | Ola Aunrønning <olaa@yahooinc.com> | 2022-09-12 11:36:23 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-12 11:36:23 +0200 |
commit | 3f22e0be7c4b730172d19b0f575baa461877958f (patch) | |
tree | 0469fe8e4bd83cdc546d93e36cb9a298214eec0e /container-core/src/main | |
parent | 767abbde9867afc94f6932a8ed3d314c5cec1a1e (diff) | |
parent | 0969fb2082dd6f9ac054a20c5166e80be5ccf045 (diff) |
Merge pull request #24013 from vespa-engine/olaa/prometheus-metric-packet-handler
MetricsPacketsHandler supports Prometheus format
Diffstat (limited to 'container-core/src/main')
-rw-r--r-- | container-core/src/main/java/com/yahoo/container/jdisc/state/MetricsPacketsHandler.java | 14 | ||||
-rw-r--r-- | container-core/src/main/java/com/yahoo/container/jdisc/state/PrometheusHelper.java | 73 |
2 files changed, 87 insertions, 0 deletions
diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricsPacketsHandler.java b/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricsPacketsHandler.java index 8fa658bf7fc..480ee96393a 100644 --- a/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricsPacketsHandler.java +++ b/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricsPacketsHandler.java @@ -18,6 +18,7 @@ import com.yahoo.jdisc.handler.ResponseDispatch; import com.yahoo.jdisc.handler.ResponseHandler; import com.yahoo.jdisc.http.HttpHeaders; +import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -100,10 +101,16 @@ public class MetricsPacketsHandler extends AbstractRequestHandler { if (query != null && query.equals("array-formatted")) { return getMetricsArray(); } + if ("format=prometheus".equals(query)) { + return buildPrometheusOutput(); + } + String output = jsonToString(getStatusPacket()) + getAllMetricsPackets() + "\n"; return output.getBytes(StandardCharsets.UTF_8); } catch (JsonProcessingException e) { throw new RuntimeException("Bad JSON construction.", e); + } catch (IOException e) { + throw new RuntimeException("Unexcpected IOException.", e); } } @@ -120,6 +127,13 @@ public class MetricsPacketsHandler extends AbstractRequestHandler { } /** + * Returns metrics in Prometheus format + */ + private byte[] buildPrometheusOutput() throws IOException { + return PrometheusHelper.buildPrometheusOutput(getSnapshot(), applicationName, timer.currentTimeMillis()); + } + + /** * Exactly one status packet is added to the response. */ private JsonNode getStatusPacket() { diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/state/PrometheusHelper.java b/container-core/src/main/java/com/yahoo/container/jdisc/state/PrometheusHelper.java new file mode 100644 index 00000000000..ca12e8161a9 --- /dev/null +++ b/container-core/src/main/java/com/yahoo/container/jdisc/state/PrometheusHelper.java @@ -0,0 +1,73 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.container.jdisc.state; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Map; + +import static com.yahoo.container.jdisc.state.JsonUtil.sanitizeDouble; + +/** + * @author olaa + */ +public class PrometheusHelper { + + private static final String HELP_LINE = "# HELP %s\n# TYPE %s untyped\n"; + private static final String METRIC_LINE = "%s{%s} %s %d\n"; + + protected static byte[] buildPrometheusOutput(MetricSnapshot metricSnapshot, String application, long timestamp) throws IOException { + var outputStream = new ByteArrayOutputStream(); + + for (Map.Entry<MetricDimensions, MetricSet> snapshotEntry : metricSnapshot) { + var metricDimensions = snapshotEntry.getKey(); + var metricSet = snapshotEntry.getValue(); + + var dimensionBuilder = new StringBuilder(); + for (var dimension : metricDimensions) { + dimensionBuilder.append(dimension.getKey()).append("=\"").append(dimension.getValue()).append("\","); + } + dimensionBuilder.append("vespa_service=\"").append(application).append("\","); + var dimensions = dimensionBuilder.toString(); + + for (var metric : metricSet) { + var metricName = metric.getKey(); + var metricValue = metric.getValue(); + + if (metricValue instanceof CountMetric) { + var sanitizedMetricName = getSanitizedMetricName(metricName, "count"); + var value = ((CountMetric) metricValue).getCount(); + outputStream.write(getMetricLines(sanitizedMetricName, dimensions, value, timestamp)); + } else if (metricValue instanceof GaugeMetric) { + var gauge = (GaugeMetric) metricValue; + writeGaugeMetrics(outputStream, metricName, gauge, dimensions, timestamp); + } + } + } + return outputStream.toByteArray(); + } + + private static void writeGaugeMetrics(OutputStream outputStream, String metricName, GaugeMetric gaugeMetric, String dimensions, long timestamp) throws IOException { + var sanitizedMetricName = getSanitizedMetricName(metricName, "last"); + var value = sanitizeDouble(gaugeMetric.getLast()); + outputStream.write(getMetricLines(sanitizedMetricName, dimensions, value, timestamp)); + + sanitizedMetricName = getSanitizedMetricName(metricName, "average"); + value = sanitizeDouble(gaugeMetric.getAverage()); + outputStream.write(getMetricLines(sanitizedMetricName, dimensions, value, timestamp)); + + sanitizedMetricName = getSanitizedMetricName(metricName, "max"); + value = sanitizeDouble(gaugeMetric.getMax()); + outputStream.write(getMetricLines(sanitizedMetricName, dimensions, value, timestamp)); + } + + private static byte[] getMetricLines(String metricName, String dimensions, Number value, long timestamp) { + return (String.format(HELP_LINE, metricName, metricName) + + String.format(METRIC_LINE, metricName, dimensions, value, timestamp)).getBytes(); + } + + private static String getSanitizedMetricName(String metricName, String suffix) { + return metricName.replaceAll("([-.])", "_") + "_" + suffix; + } + +} |