diff --git a/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/OpenMetrics2TextFormatWriter.java b/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/OpenMetrics2TextFormatWriter.java index 3ccdc80d8..95c3e7285 100644 --- a/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/OpenMetrics2TextFormatWriter.java +++ b/prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/OpenMetrics2TextFormatWriter.java @@ -15,6 +15,7 @@ import io.prometheus.metrics.model.snapshots.CounterSnapshot; import io.prometheus.metrics.model.snapshots.DataPointSnapshot; import io.prometheus.metrics.model.snapshots.Exemplar; +import io.prometheus.metrics.model.snapshots.Exemplars; import io.prometheus.metrics.model.snapshots.GaugeSnapshot; import io.prometheus.metrics.model.snapshots.HistogramSnapshot; import io.prometheus.metrics.model.snapshots.InfoSnapshot; @@ -62,7 +63,7 @@ public Builder setOpenMetrics2Properties(OpenMetrics2Properties openMetrics2Prop } /** - * @param createdTimestampsEnabled whether to include the _created timestamp in the output + * @param createdTimestampsEnabled whether to include the start timestamp in the output */ public Builder setCreatedTimestampsEnabled(boolean createdTimestampsEnabled) { this.createdTimestampsEnabled = createdTimestampsEnabled; @@ -93,8 +94,7 @@ public OpenMetrics2TextFormatWriter build() { /** * @param openMetrics2Properties OpenMetrics 2.0 feature flags - * @param createdTimestampsEnabled whether to include the _created timestamp in the output - This - * will produce an invalid OpenMetrics output, but is kept for backwards compatibility. + * @param createdTimestampsEnabled whether to include the start timestamp in the output. * @param exemplarsOnAllMetricTypesEnabled whether to include exemplars on all metric types */ public OpenMetrics2TextFormatWriter( @@ -177,8 +177,16 @@ private void writeCounter(Writer writer, CounterSnapshot snapshot, EscapingSchem for (CounterSnapshot.CounterDataPointSnapshot data : snapshot.getDataPoints()) { writeNameAndLabels(writer, counterName, null, data.getLabels(), scheme); writeDouble(writer, data.getValue()); - writeScrapeTimestampAndExemplar(writer, data, data.getExemplar(), scheme); - writeCreated(writer, counterName, data, scheme); + if (data.hasScrapeTimestamp()) { + writer.write(' '); + writeOpenMetricsTimestamp(writer, data.getScrapeTimestampMillis()); + } + if (createdTimestampsEnabled && data.hasCreatedTimestamp()) { + writer.write(" st@"); + writeOpenMetricsTimestamp(writer, data.getCreatedTimestampMillis()); + } + writeExemplar(writer, data.getExemplar(), scheme); + writer.write('\n'); } } @@ -316,22 +324,20 @@ private void writeCompositeSummaryDataPoint( writeDouble(writer, data.getSum()); first = false; } - if (data.getQuantiles().size() > 0) { - if (!first) { + if (!first) { + writer.write(','); + } + writer.write("quantile:["); + for (int i = 0; i < data.getQuantiles().size(); i++) { + if (i > 0) { writer.write(','); } - writer.write("quantile:["); - for (int i = 0; i < data.getQuantiles().size(); i++) { - if (i > 0) { - writer.write(','); - } - Quantile q = data.getQuantiles().get(i); - writeDouble(writer, q.getQuantile()); - writer.write(':'); - writeDouble(writer, q.getValue()); - } - writer.write(']'); + Quantile q = data.getQuantiles().get(i); + writeDouble(writer, q.getQuantile()); + writer.write(':'); + writeDouble(writer, q.getValue()); } + writer.write(']'); writer.write('}'); if (data.hasScrapeTimestamp()) { writer.write(' '); @@ -341,7 +347,7 @@ private void writeCompositeSummaryDataPoint( writer.write(" st@"); writeOpenMetricsTimestamp(writer, data.getCreatedTimestampMillis()); } - writeExemplar(writer, data.getExemplars().getLatest(), scheme); + writeExemplars(writer, data.getExemplars(), scheme); writer.write('\n'); } @@ -411,20 +417,6 @@ private void writeUnknown(Writer writer, UnknownSnapshot snapshot, EscapingSchem } } - private void writeCreated( - Writer writer, String name, DataPointSnapshot data, EscapingScheme scheme) - throws IOException { - if (createdTimestampsEnabled && data.hasCreatedTimestamp()) { - writeNameAndLabels(writer, name, "_created", data.getLabels(), scheme); - writeOpenMetricsTimestamp(writer, data.getCreatedTimestampMillis()); - if (data.hasScrapeTimestamp()) { - writer.write(' '); - writeOpenMetricsTimestamp(writer, data.getScrapeTimestampMillis()); - } - writer.write('\n'); - } - } - private void writeNameAndLabels( Writer writer, String name, @@ -496,6 +488,13 @@ private void writeExemplar(Writer writer, @Nullable Exemplar exemplar, EscapingS } } + private void writeExemplars(Writer writer, Exemplars exemplars, EscapingScheme scheme) + throws IOException { + for (Exemplar exemplar : exemplars) { + writeExemplar(writer, exemplar, scheme); + } + } + private void writeMetadataWithName( Writer writer, String name, String typeName, MetricMetadata metadata) throws IOException { writer.write("# TYPE "); diff --git a/prometheus-metrics-exposition-textformats/src/test/java/io/prometheus/metrics/expositionformats/OpenMetrics2TextFormatWriterTest.java b/prometheus-metrics-exposition-textformats/src/test/java/io/prometheus/metrics/expositionformats/OpenMetrics2TextFormatWriterTest.java index 483bf1339..4dc730d27 100644 --- a/prometheus-metrics-exposition-textformats/src/test/java/io/prometheus/metrics/expositionformats/OpenMetrics2TextFormatWriterTest.java +++ b/prometheus-metrics-exposition-textformats/src/test/java/io/prometheus/metrics/expositionformats/OpenMetrics2TextFormatWriterTest.java @@ -307,13 +307,12 @@ void testCounterWithCreatedTimestamps() throws IOException { String om2Output = write(snapshots, om2Writer); - // OM2: no _total, _created uses the counter name directly + // OM2: no _total, start timestamp uses st@ inline. assertThat(om2Output) .isEqualTo( "# TYPE my_counter counter\n" + "# HELP my_counter Test counter\n" - + "my_counter 42.0\n" - + "my_counter_created 1672850385.800\n" + + "my_counter 42.0 st@1672850385.800\n" + "# EOF\n"); } @@ -479,8 +478,10 @@ void testCompositeSummary() throws IOException { @Test void testCompositeSummaryWithCreatedAndExemplar() throws IOException { - Exemplar exemplar = + Exemplar exemplar1 = Exemplar.builder().value(0.5).traceId("abc123").timestampMillis(1520879607000L).build(); + Exemplar exemplar2 = + Exemplar.builder().value(1.5).traceId("def456").timestampMillis(1520879608000L).build(); MetricSnapshots snapshots = MetricSnapshots.of( @@ -491,7 +492,7 @@ void testCompositeSummaryWithCreatedAndExemplar() throws IOException { .count(10) .sum(100.0) .createdTimestampMillis(1520430000000L) - .exemplars(Exemplars.of(exemplar)) + .exemplars(Exemplars.of(exemplar1, exemplar2)) .build()) .build()); @@ -500,8 +501,9 @@ void testCompositeSummaryWithCreatedAndExemplar() throws IOException { assertThat(output) .isEqualTo( "# TYPE rpc_duration_seconds summary\n" - + "rpc_duration_seconds {count:10,sum:100.0} st@1520430000.000" - + " # {trace_id=\"abc123\"} 0.5 1520879607.000\n" + + "rpc_duration_seconds {count:10,sum:100.0,quantile:[]} st@1520430000.000" + + " # {trace_id=\"abc123\"} 0.5 1520879607.000" + + " # {trace_id=\"def456\"} 1.5 1520879608.000\n" + "# EOF\n"); }