From c2656ce74e01c3462c020aefad811be634efa95e Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 8 Sep 2025 13:03:06 +0200 Subject: [PATCH 1/2] add option to disable metric suffixes Signed-off-by: Gregor Zeitlinger --- .../metrics/config/ExporterProperties.java | 31 ++++++++++-- .../metrics/core/metrics/HistogramTest.java | 2 +- .../metrics/core/metrics/InfoTest.java | 21 +++++--- .../expositionformats/ExpositionFormats.java | 2 + .../OpenMetricsTextFormatWriter.java | 49 ++++++++++++++----- .../PrometheusTextFormatWriter.java | 24 +++++++-- .../caffeine/CacheMetricsCollectorTest.java | 32 +++++++----- .../dropwizard/DropwizardExportsTest.java | 6 ++- .../dropwizard5/DropwizardExportsTest.java | 6 ++- .../labels/CustomLabelMapperTest.java | 6 ++- .../guava/CacheMetricsCollectorTest.java | 6 ++- .../metrics/instrumentation/jvm/TestUtil.java | 6 ++- .../bridge/SimpleclientCollectorTest.java | 3 +- 13 files changed, 148 insertions(+), 46 deletions(-) diff --git a/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/ExporterProperties.java b/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/ExporterProperties.java index 6b081816d..140d45c98 100644 --- a/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/ExporterProperties.java +++ b/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/ExporterProperties.java @@ -1,7 +1,7 @@ package io.prometheus.metrics.config; -import java.util.Map; import javax.annotation.Nullable; +import java.util.Map; /** Properties starting with io.prometheus.exporter */ public class ExporterProperties { @@ -10,19 +10,23 @@ public class ExporterProperties { // milliseconds is the default - we only provide a boolean flag to avoid a breaking change private static final String PROMETHEUS_TIMESTAMPS_IN_MS = "prometheusTimestampsInMs"; private static final String EXEMPLARS_ON_ALL_METRIC_TYPES = "exemplarsOnAllMetricTypes"; + private static final String ADD_SUFFIXES_TO_METRIC_NAMES = "addSuffixesToMetricNames"; private static final String PREFIX = "io.prometheus.exporter"; @Nullable private final Boolean includeCreatedTimestamps; @Nullable private final Boolean prometheusTimestampsInMs; @Nullable private final Boolean exemplarsOnAllMetricTypes; + @Nullable private final Boolean addSuffixesToMetricNames; private ExporterProperties( @Nullable Boolean includeCreatedTimestamps, @Nullable Boolean prometheusTimestampsInMs, - @Nullable Boolean exemplarsOnAllMetricTypes) { + @Nullable Boolean exemplarsOnAllMetricTypes, + @Nullable Boolean addSuffixesToMetricNames) { this.includeCreatedTimestamps = includeCreatedTimestamps; this.prometheusTimestampsInMs = prometheusTimestampsInMs; this.exemplarsOnAllMetricTypes = exemplarsOnAllMetricTypes; + this.addSuffixesToMetricNames = addSuffixesToMetricNames; } /** Include the {@code _created} timestamps in text format? Default is {@code false}. */ @@ -43,6 +47,10 @@ public boolean getExemplarsOnAllMetricTypes() { return exemplarsOnAllMetricTypes != null && exemplarsOnAllMetricTypes; } + public boolean isAddSuffixesToMetricNames() { + return addSuffixesToMetricNames == null || addSuffixesToMetricNames; + } + /** * Note that this will remove entries from {@code properties}. This is because we want to know if * there are unused properties remaining after all properties have been loaded. @@ -55,8 +63,13 @@ static ExporterProperties load(Map properties) Util.loadBoolean(PREFIX + "." + PROMETHEUS_TIMESTAMPS_IN_MS, properties); Boolean exemplarsOnAllMetricTypes = Util.loadBoolean(PREFIX + "." + EXEMPLARS_ON_ALL_METRIC_TYPES, properties); + Boolean addSuffixesToMetricNames = + Util.loadBoolean(PREFIX + "." + ADD_SUFFIXES_TO_METRIC_NAMES, properties); return new ExporterProperties( - includeCreatedTimestamps, timestampsInMs, exemplarsOnAllMetricTypes); + includeCreatedTimestamps, + timestampsInMs, + exemplarsOnAllMetricTypes, + addSuffixesToMetricNames); } public static Builder builder() { @@ -68,6 +81,7 @@ public static class Builder { @Nullable private Boolean includeCreatedTimestamps; @Nullable private Boolean exemplarsOnAllMetricTypes; boolean prometheusTimestampsInMs; + @Nullable private Boolean addSuffixesToMetricNames; private Builder() {} @@ -89,9 +103,18 @@ public Builder prometheusTimestampsInMs(boolean prometheusTimestampsInMs) { return this; } + /** See {@link #isAddSuffixesToMetricNames()}. */ + public Builder addSuffixesToMetricNames(boolean addSuffixesToMetricNames) { + this.addSuffixesToMetricNames = addSuffixesToMetricNames; + return this; + } + public ExporterProperties build() { return new ExporterProperties( - includeCreatedTimestamps, prometheusTimestampsInMs, exemplarsOnAllMetricTypes); + includeCreatedTimestamps, + prometheusTimestampsInMs, + exemplarsOnAllMetricTypes, + addSuffixesToMetricNames); } } } diff --git a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/HistogramTest.java b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/HistogramTest.java index 19e4cdc79..9fc3ad3c3 100644 --- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/HistogramTest.java +++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/HistogramTest.java @@ -949,7 +949,7 @@ public void testDefaults() throws IOException { // text ByteArrayOutputStream out = new ByteArrayOutputStream(); - OpenMetricsTextFormatWriter writer = new OpenMetricsTextFormatWriter(false, true); + OpenMetricsTextFormatWriter writer = OpenMetricsTextFormatWriter.create(); writer.write(out, MetricSnapshots.of(snapshot), EscapingScheme.ALLOW_UTF8); assertThat(out).hasToString(expectedTextFormat); } diff --git a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/InfoTest.java b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/InfoTest.java index fccc5d8d7..ec3a93fea 100644 --- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/InfoTest.java +++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/InfoTest.java @@ -1,8 +1,5 @@ package io.prometheus.metrics.core.metrics; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; - import io.prometheus.metrics.config.EscapingScheme; import io.prometheus.metrics.expositionformats.OpenMetricsTextFormatWriter; import io.prometheus.metrics.expositionformats.generated.com_google_protobuf_4_32_0.Metrics; @@ -11,13 +8,17 @@ import io.prometheus.metrics.model.snapshots.Labels; import io.prometheus.metrics.model.snapshots.MetricSnapshots; import io.prometheus.metrics.model.snapshots.Unit; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + class InfoTest { @ParameterizedTest @@ -120,11 +121,15 @@ public void testConstLabelsDuplicate2() { } private void assertTextFormat(String expected, Info info) throws IOException { - OpenMetricsTextFormatWriter writer = new OpenMetricsTextFormatWriter(true, true); + OpenMetricsTextFormatWriter writer = + OpenMetricsTextFormatWriter.builder() + .setCreatedTimestampsEnabled(true) + .setExemplarsOnAllMetricTypesEnabled(true) + .build(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); writer.write( outputStream, MetricSnapshots.of(info.collect()), EscapingScheme.UNDERSCORE_ESCAPING); - String result = outputStream.toString(StandardCharsets.UTF_8.name()); + String result = outputStream.toString(StandardCharsets.UTF_8); if (!result.contains(expected)) { throw new AssertionError(expected + " is not contained in the following output:\n" + result); } diff --git a/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/ExpositionFormats.java b/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/ExpositionFormats.java index 0ffa23a58..98f3c1427 100644 --- a/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/ExpositionFormats.java +++ b/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/ExpositionFormats.java @@ -30,10 +30,12 @@ public static ExpositionFormats init(ExporterProperties properties) { PrometheusTextFormatWriter.builder() .setIncludeCreatedTimestamps(properties.getIncludeCreatedTimestamps()) .setTimestampsInMs(properties.getPrometheusTimestampsInMs()) + .setAddSuffixesToMetricNames(properties.isAddSuffixesToMetricNames()) .build(), OpenMetricsTextFormatWriter.builder() .setCreatedTimestampsEnabled(properties.getIncludeCreatedTimestamps()) .setExemplarsOnAllMetricTypesEnabled(properties.getExemplarsOnAllMetricTypes()) + .setAddSuffixesToMetricNames(properties.isAddSuffixesToMetricNames()) .build()); } diff --git a/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/OpenMetricsTextFormatWriter.java b/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/OpenMetricsTextFormatWriter.java index 1ba1c627d..5193e4f5c 100644 --- a/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/OpenMetricsTextFormatWriter.java +++ b/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/OpenMetricsTextFormatWriter.java @@ -1,14 +1,5 @@ package io.prometheus.metrics.expositionformats; -import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeDouble; -import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeEscapedString; -import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeLabels; -import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeLong; -import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeName; -import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeOpenMetricsTimestamp; -import static io.prometheus.metrics.model.snapshots.SnapshotEscaper.getMetadataName; -import static io.prometheus.metrics.model.snapshots.SnapshotEscaper.getSnapshotLabelName; - import io.prometheus.metrics.config.EscapingScheme; import io.prometheus.metrics.model.snapshots.ClassicHistogramBuckets; import io.prometheus.metrics.model.snapshots.CounterSnapshot; @@ -29,6 +20,8 @@ import io.prometheus.metrics.model.snapshots.StateSetSnapshot; import io.prometheus.metrics.model.snapshots.SummarySnapshot; import io.prometheus.metrics.model.snapshots.UnknownSnapshot; + +import javax.annotation.Nullable; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStream; @@ -36,7 +29,15 @@ import java.io.Writer; import java.nio.charset.StandardCharsets; import java.util.List; -import javax.annotation.Nullable; + +import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeDouble; +import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeEscapedString; +import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeLabels; +import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeLong; +import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeName; +import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeOpenMetricsTimestamp; +import static io.prometheus.metrics.model.snapshots.SnapshotEscaper.getMetadataName; +import static io.prometheus.metrics.model.snapshots.SnapshotEscaper.getSnapshotLabelName; /** * Write the OpenMetrics text format as defined on Date: Mon, 8 Sep 2025 13:09:21 +0200 Subject: [PATCH 2/2] add option to disable metric suffixes Signed-off-by: Gregor Zeitlinger --- .../metrics/config/ExporterProperties.java | 2 +- .../metrics/core/metrics/InfoTest.java | 13 ++++++------ .../OpenMetricsTextFormatWriter.java | 21 +++++++++---------- .../caffeine/CacheMetricsCollectorTest.java | 17 +++++++-------- 4 files changed, 25 insertions(+), 28 deletions(-) diff --git a/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/ExporterProperties.java b/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/ExporterProperties.java index 140d45c98..ba24b0883 100644 --- a/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/ExporterProperties.java +++ b/prometheus-metrics-config/src/main/java/io/prometheus/metrics/config/ExporterProperties.java @@ -1,7 +1,7 @@ package io.prometheus.metrics.config; -import javax.annotation.Nullable; import java.util.Map; +import javax.annotation.Nullable; /** Properties starting with io.prometheus.exporter */ public class ExporterProperties { diff --git a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/InfoTest.java b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/InfoTest.java index ec3a93fea..9500c25ad 100644 --- a/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/InfoTest.java +++ b/prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/InfoTest.java @@ -1,5 +1,8 @@ package io.prometheus.metrics.core.metrics; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + import io.prometheus.metrics.config.EscapingScheme; import io.prometheus.metrics.expositionformats.OpenMetricsTextFormatWriter; import io.prometheus.metrics.expositionformats.generated.com_google_protobuf_4_32_0.Metrics; @@ -8,16 +11,12 @@ import io.prometheus.metrics.model.snapshots.Labels; import io.prometheus.metrics.model.snapshots.MetricSnapshots; import io.prometheus.metrics.model.snapshots.Unit; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; class InfoTest { diff --git a/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/OpenMetricsTextFormatWriter.java b/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/OpenMetricsTextFormatWriter.java index 5193e4f5c..aafc50eab 100644 --- a/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/OpenMetricsTextFormatWriter.java +++ b/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/OpenMetricsTextFormatWriter.java @@ -1,5 +1,14 @@ package io.prometheus.metrics.expositionformats; +import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeDouble; +import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeEscapedString; +import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeLabels; +import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeLong; +import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeName; +import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeOpenMetricsTimestamp; +import static io.prometheus.metrics.model.snapshots.SnapshotEscaper.getMetadataName; +import static io.prometheus.metrics.model.snapshots.SnapshotEscaper.getSnapshotLabelName; + import io.prometheus.metrics.config.EscapingScheme; import io.prometheus.metrics.model.snapshots.ClassicHistogramBuckets; import io.prometheus.metrics.model.snapshots.CounterSnapshot; @@ -20,8 +29,6 @@ import io.prometheus.metrics.model.snapshots.StateSetSnapshot; import io.prometheus.metrics.model.snapshots.SummarySnapshot; import io.prometheus.metrics.model.snapshots.UnknownSnapshot; - -import javax.annotation.Nullable; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStream; @@ -29,15 +36,7 @@ import java.io.Writer; import java.nio.charset.StandardCharsets; import java.util.List; - -import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeDouble; -import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeEscapedString; -import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeLabels; -import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeLong; -import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeName; -import static io.prometheus.metrics.expositionformats.TextFormatUtil.writeOpenMetricsTimestamp; -import static io.prometheus.metrics.model.snapshots.SnapshotEscaper.getMetadataName; -import static io.prometheus.metrics.model.snapshots.SnapshotEscaper.getSnapshotLabelName; +import javax.annotation.Nullable; /** * Write the OpenMetrics text format as defined on