-
Notifications
You must be signed in to change notification settings - Fork 828
feat: compositeValues and exemplarCompliance flags for OM2 writer #1991
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
2128d87
6e683d3
f1eba6f
ff7b3bc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -14,9 +14,7 @@ | |||||||
| import io.prometheus.metrics.model.snapshots.ClassicHistogramBuckets; | ||||||||
| import io.prometheus.metrics.model.snapshots.CounterSnapshot; | ||||||||
| import io.prometheus.metrics.model.snapshots.DataPointSnapshot; | ||||||||
| import io.prometheus.metrics.model.snapshots.DistributionDataPointSnapshot; | ||||||||
| 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; | ||||||||
|
|
@@ -36,7 +34,6 @@ | |||||||
| import java.io.OutputStreamWriter; | ||||||||
| import java.io.Writer; | ||||||||
| import java.nio.charset.StandardCharsets; | ||||||||
| import java.util.List; | ||||||||
| import javax.annotation.Nullable; | ||||||||
|
|
||||||||
| /** | ||||||||
|
|
@@ -92,6 +89,7 @@ public OpenMetrics2TextFormatWriter build() { | |||||||
| private final OpenMetrics2Properties openMetrics2Properties; | ||||||||
| private final boolean createdTimestampsEnabled; | ||||||||
| private final boolean exemplarsOnAllMetricTypesEnabled; | ||||||||
| private final OpenMetricsTextFormatWriter om1Writer; | ||||||||
|
|
||||||||
| /** | ||||||||
| * @param openMetrics2Properties OpenMetrics 2.0 feature flags | ||||||||
|
|
@@ -106,6 +104,8 @@ public OpenMetrics2TextFormatWriter( | |||||||
| this.openMetrics2Properties = openMetrics2Properties; | ||||||||
| this.createdTimestampsEnabled = createdTimestampsEnabled; | ||||||||
| this.exemplarsOnAllMetricTypesEnabled = exemplarsOnAllMetricTypesEnabled; | ||||||||
| this.om1Writer = | ||||||||
| new OpenMetricsTextFormatWriter(createdTimestampsEnabled, exemplarsOnAllMetricTypesEnabled); | ||||||||
| } | ||||||||
|
|
||||||||
| public static Builder builder() { | ||||||||
|
|
@@ -200,50 +200,65 @@ private void writeGauge(Writer writer, GaugeSnapshot snapshot, EscapingScheme sc | |||||||
|
|
||||||||
| private void writeHistogram(Writer writer, HistogramSnapshot snapshot, EscapingScheme scheme) | ||||||||
| throws IOException { | ||||||||
| if (!openMetrics2Properties.getCompositeValues()) { | ||||||||
| om1Writer.writeHistogram(writer, snapshot, scheme); | ||||||||
| return; | ||||||||
| } | ||||||||
| MetricMetadata metadata = snapshot.getMetadata(); | ||||||||
| String name = getExpositionBaseMetadataName(metadata, scheme); | ||||||||
| if (snapshot.isGaugeHistogram()) { | ||||||||
| writeMetadataWithName(writer, name, "gaugehistogram", metadata); | ||||||||
| writeClassicHistogramBuckets( | ||||||||
| writer, name, "_gcount", "_gsum", snapshot.getDataPoints(), scheme); | ||||||||
| for (HistogramSnapshot.HistogramDataPointSnapshot data : snapshot.getDataPoints()) { | ||||||||
| writeCompositeHistogramDataPoint(writer, name, "gcount", "gsum", data, scheme); | ||||||||
| } | ||||||||
| } else { | ||||||||
| writeMetadataWithName(writer, name, "histogram", metadata); | ||||||||
| writeClassicHistogramBuckets( | ||||||||
| writer, name, "_count", "_sum", snapshot.getDataPoints(), scheme); | ||||||||
| for (HistogramSnapshot.HistogramDataPointSnapshot data : snapshot.getDataPoints()) { | ||||||||
| writeCompositeHistogramDataPoint(writer, name, "count", "sum", data, scheme); | ||||||||
| } | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| private void writeClassicHistogramBuckets( | ||||||||
| private void writeCompositeHistogramDataPoint( | ||||||||
| Writer writer, | ||||||||
| String name, | ||||||||
| String countSuffix, | ||||||||
| String sumSuffix, | ||||||||
| List<HistogramSnapshot.HistogramDataPointSnapshot> dataList, | ||||||||
| String countKey, | ||||||||
| String sumKey, | ||||||||
| HistogramSnapshot.HistogramDataPointSnapshot data, | ||||||||
| EscapingScheme scheme) | ||||||||
| throws IOException { | ||||||||
| for (HistogramSnapshot.HistogramDataPointSnapshot data : dataList) { | ||||||||
| ClassicHistogramBuckets buckets = getClassicBuckets(data); | ||||||||
| Exemplars exemplars = data.getExemplars(); | ||||||||
| long cumulativeCount = 0; | ||||||||
| for (int i = 0; i < buckets.size(); i++) { | ||||||||
| cumulativeCount += buckets.getCount(i); | ||||||||
| writeNameAndLabels( | ||||||||
| writer, name, "_bucket", data.getLabels(), scheme, "le", buckets.getUpperBound(i)); | ||||||||
| writeLong(writer, cumulativeCount); | ||||||||
| Exemplar exemplar; | ||||||||
| if (i == 0) { | ||||||||
| exemplar = exemplars.get(Double.NEGATIVE_INFINITY, buckets.getUpperBound(i)); | ||||||||
| } else { | ||||||||
| exemplar = exemplars.get(buckets.getUpperBound(i - 1), buckets.getUpperBound(i)); | ||||||||
| } | ||||||||
| writeScrapeTimestampAndExemplar(writer, data, exemplar, scheme); | ||||||||
| writeNameAndLabels(writer, name, null, data.getLabels(), scheme); | ||||||||
| writer.write('{'); | ||||||||
| writer.write(countKey); | ||||||||
| writer.write(':'); | ||||||||
| writeLong(writer, data.getCount()); | ||||||||
| writer.write(','); | ||||||||
| writer.write(sumKey); | ||||||||
| writer.write(':'); | ||||||||
| writeDouble(writer, data.getSum()); | ||||||||
| writer.write(",bucket:["); | ||||||||
| ClassicHistogramBuckets buckets = getClassicBuckets(data); | ||||||||
| long cumulativeCount = 0; | ||||||||
| for (int i = 0; i < buckets.size(); i++) { | ||||||||
| if (i > 0) { | ||||||||
| writer.write(','); | ||||||||
| } | ||||||||
| // In OpenMetrics format, histogram _count and _sum are either both present or both absent. | ||||||||
| if (data.hasCount() && data.hasSum()) { | ||||||||
| writeCountAndSum(writer, name, data, countSuffix, sumSuffix, exemplars, scheme); | ||||||||
| } | ||||||||
| writeCreated(writer, name, data, scheme); | ||||||||
| cumulativeCount += buckets.getCount(i); | ||||||||
| writeDouble(writer, buckets.getUpperBound(i)); | ||||||||
| writer.write(':'); | ||||||||
| writeLong(writer, cumulativeCount); | ||||||||
| } | ||||||||
| writer.write("]}"); | ||||||||
| if (data.hasScrapeTimestamp()) { | ||||||||
| writer.write(' '); | ||||||||
| writeOpenMetricsTimestamp(writer, data.getScrapeTimestampMillis()); | ||||||||
| } | ||||||||
| if (data.hasCreatedTimestamp()) { | ||||||||
| writer.write(" st@"); | ||||||||
| writeOpenMetricsTimestamp(writer, data.getCreatedTimestampMillis()); | ||||||||
| } | ||||||||
| writeExemplar(writer, data.getExemplars().getLatest(), scheme); | ||||||||
| writer.write('\n'); | ||||||||
| } | ||||||||
|
|
||||||||
| private ClassicHistogramBuckets getClassicBuckets( | ||||||||
|
|
@@ -258,6 +273,10 @@ private ClassicHistogramBuckets getClassicBuckets( | |||||||
|
|
||||||||
| private void writeSummary(Writer writer, SummarySnapshot snapshot, EscapingScheme scheme) | ||||||||
| throws IOException { | ||||||||
| if (!openMetrics2Properties.getCompositeValues()) { | ||||||||
|
||||||||
| if (!openMetrics2Properties.getCompositeValues()) { | |
| if (!openMetrics2Properties.getCompositeValues() | |
| && !openMetrics2Properties.getExemplarCompliance()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When
compositeValuesis disabled, this delegates histogram rendering toom1Writer. That bypassesexemplarCompliancehandling inOpenMetrics2TextFormatWriter, soexemplarCompliance=truewill still emit histogram exemplars that lack timestamps (the OM1 writer prints exemplars even whenhasTimestamp()is false). To keep compliance mode effective, avoid delegating toom1WriterwhenexemplarComplianceis enabled, or update the delegated path to drop timestamp-less exemplars as well (and add a regression test for histogram exemplars without timestamps).