Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ private Builder(PrometheusProperties properties) {
*/
@Override
public Builder name(String name) {
return super.name(stripTotalSuffix(name));
return super.nameWithOriginal(stripTotalSuffix(name), name);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ private Builder(PrometheusProperties config) {
*/
@Override
public Builder name(String name) {
return super.name(stripInfoSuffix(name));
return super.nameWithOriginal(stripInfoSuffix(name), name);
}

/** Throws an {@link UnsupportedOperationException} because Info metrics cannot have a unit. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,14 @@ public abstract class MetricWithFixedMetadata extends Metric {

protected MetricWithFixedMetadata(Builder<?, ?> builder) {
super(builder);
String name = makeName(builder.name, builder.unit);
if (builder.originalName == null) {
throw new IllegalArgumentException("Missing required field: name is null");
}
String originalName = builder.originalName;
String expositionBaseName = makeExpositionBaseName(originalName, builder.unit);
this.metadata =
new MetricMetadata(makeName(builder.name, builder.unit), builder.help, builder.unit);
new MetricMetadata(name, expositionBaseName, originalName, builder.help, builder.unit);
this.labelNames = Arrays.copyOf(builder.labelNames, builder.labelNames.length);
}

Expand All @@ -47,6 +53,18 @@ private String makeName(@Nullable String name, @Nullable Unit unit) {
return name;
}

private String makeExpositionBaseName(@Nullable String expositionBaseName, @Nullable Unit unit) {
if (expositionBaseName == null) {
throw new IllegalArgumentException("Missing required field: name is null");
}
if (unit != null) {
if (!expositionBaseName.endsWith("_" + unit) && !expositionBaseName.endsWith("." + unit)) {
expositionBaseName += "_" + unit;
}
}
return expositionBaseName;
}

@Override
public String getPrometheusName() {
return metadata.getPrometheusName();
Expand All @@ -68,6 +86,7 @@ public abstract static class Builder<B extends Builder<B, M>, M extends MetricWi
extends Metric.Builder<B, M> {

@Nullable private String name;
@Nullable private String originalName;
@Nullable private Unit unit;
@Nullable private String help;
private String[] labelNames = new String[0];
Expand All @@ -82,6 +101,25 @@ public B name(String name) {
throw new IllegalArgumentException("'" + name + "': Illegal metric name: " + error);
}
this.name = name;
this.originalName = name;
return self();
}

/**
* Set the metric name and original name separately. Used by Counter and Info builders which
* strip type suffixes from the name but preserve the original for exposition.
*/
protected B nameWithOriginal(String name, String originalName) {
String error = PrometheusNaming.validateMetricName(name);
if (error != null) {
throw new IllegalArgumentException("'" + name + "': Illegal metric name: " + error);
}
error = PrometheusNaming.validateMetricName(originalName);
if (error != null) {
throw new IllegalArgumentException("'" + originalName + "': Illegal metric name: " + error);
}
this.name = name;
this.originalName = originalName;
return self();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,12 @@ private void setMetadataUnlessEmpty(
if (nameSuffix == null) {
builder.setName(SnapshotEscaper.getMetadataName(metadata, scheme));
} else {
builder.setName(SnapshotEscaper.getMetadataName(metadata, scheme) + nameSuffix);
String expositionBaseName = SnapshotEscaper.getExpositionBaseMetadataName(metadata, scheme);
if (expositionBaseName.endsWith(nameSuffix)) {
builder.setName(expositionBaseName);
} else {
builder.setName(SnapshotEscaper.getMetadataName(metadata, scheme) + nameSuffix);
}
}
if (metadata.getHelp() != null) {
builder.setHelp(metadata.getHelp());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
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.getExpositionBaseMetadataName;
import static io.prometheus.metrics.model.snapshots.SnapshotEscaper.getSnapshotLabelName;

import io.prometheus.metrics.config.EscapingScheme;
Expand Down Expand Up @@ -40,9 +40,9 @@
import javax.annotation.Nullable;

/**
* Write the OpenMetrics 2.0 text format. This is currently a skeleton implementation that produces
* identical output to OpenMetrics 1.0, with infrastructure for future OM2 features. This is
* experimental and subject to change as the <a
* Write the OpenMetrics 2.0 text format. Unlike the OM1 writer, this writer outputs metric names as
* provided by the user — no {@code _total} or unit suffix appending. The {@code _info} suffix is
* enforced per the OM2 spec (MUST). This is experimental and subject to change as the <a
* href="https://github.com/prometheus/docs/blob/main/docs/specs/om/open_metrics_spec_2_0.md">OpenMetrics
* 2.0 specification</a> evolves.
*/
Expand Down Expand Up @@ -171,22 +171,24 @@ public void write(OutputStream out, MetricSnapshots metricSnapshots, EscapingSch
private void writeCounter(Writer writer, CounterSnapshot snapshot, EscapingScheme scheme)
throws IOException {
MetricMetadata metadata = snapshot.getMetadata();
writeMetadata(writer, "counter", metadata, scheme);
// OM2: use the name as provided by the user, no _total appending
String counterName = getExpositionBaseMetadataName(metadata, scheme);
writeMetadataWithName(writer, counterName, "counter", metadata);
for (CounterSnapshot.CounterDataPointSnapshot data : snapshot.getDataPoints()) {
writeNameAndLabels(
writer, getMetadataName(metadata, scheme), "_total", data.getLabels(), scheme);
writeNameAndLabels(writer, counterName, null, data.getLabels(), scheme);
writeDouble(writer, data.getValue());
writeScrapeTimestampAndExemplar(writer, data, data.getExemplar(), scheme);
writeCreated(writer, metadata, data, scheme);
writeCreated(writer, counterName, data, scheme);
}
}

private void writeGauge(Writer writer, GaugeSnapshot snapshot, EscapingScheme scheme)
throws IOException {
MetricMetadata metadata = snapshot.getMetadata();
writeMetadata(writer, "gauge", metadata, scheme);
String name = getExpositionBaseMetadataName(metadata, scheme);
writeMetadataWithName(writer, name, "gauge", metadata);
for (GaugeSnapshot.GaugeDataPointSnapshot data : snapshot.getDataPoints()) {
writeNameAndLabels(writer, getMetadataName(metadata, scheme), null, data.getLabels(), scheme);
writeNameAndLabels(writer, name, null, data.getLabels(), scheme);
writeDouble(writer, data.getValue());
if (exemplarsOnAllMetricTypesEnabled) {
writeScrapeTimestampAndExemplar(writer, data, data.getExemplar(), scheme);
Expand All @@ -199,20 +201,21 @@ private void writeGauge(Writer writer, GaugeSnapshot snapshot, EscapingScheme sc
private void writeHistogram(Writer writer, HistogramSnapshot snapshot, EscapingScheme scheme)
throws IOException {
MetricMetadata metadata = snapshot.getMetadata();
String name = getExpositionBaseMetadataName(metadata, scheme);
if (snapshot.isGaugeHistogram()) {
writeMetadata(writer, "gaugehistogram", metadata, scheme);
writeMetadataWithName(writer, name, "gaugehistogram", metadata);
writeClassicHistogramBuckets(
writer, metadata, "_gcount", "_gsum", snapshot.getDataPoints(), scheme);
writer, name, "_gcount", "_gsum", snapshot.getDataPoints(), scheme);
} else {
writeMetadata(writer, "histogram", metadata, scheme);
writeMetadataWithName(writer, name, "histogram", metadata);
writeClassicHistogramBuckets(
writer, metadata, "_count", "_sum", snapshot.getDataPoints(), scheme);
writer, name, "_count", "_sum", snapshot.getDataPoints(), scheme);
}
}

private void writeClassicHistogramBuckets(
Writer writer,
MetricMetadata metadata,
String name,
String countSuffix,
String sumSuffix,
List<HistogramSnapshot.HistogramDataPointSnapshot> dataList,
Expand All @@ -225,13 +228,7 @@ private void writeClassicHistogramBuckets(
for (int i = 0; i < buckets.size(); i++) {
cumulativeCount += buckets.getCount(i);
writeNameAndLabels(
writer,
getMetadataName(metadata, scheme),
"_bucket",
data.getLabels(),
scheme,
"le",
buckets.getUpperBound(i));
writer, name, "_bucket", data.getLabels(), scheme, "le", buckets.getUpperBound(i));
writeLong(writer, cumulativeCount);
Exemplar exemplar;
if (i == 0) {
Expand All @@ -243,9 +240,9 @@ private void writeClassicHistogramBuckets(
}
// In OpenMetrics format, histogram _count and _sum are either both present or both absent.
if (data.hasCount() && data.hasSum()) {
writeCountAndSum(writer, metadata, data, countSuffix, sumSuffix, exemplars, scheme);
writeCountAndSum(writer, name, data, countSuffix, sumSuffix, exemplars, scheme);
}
writeCreated(writer, metadata, data, scheme);
writeCreated(writer, name, data, scheme);
}
}

Expand All @@ -263,12 +260,13 @@ private void writeSummary(Writer writer, SummarySnapshot snapshot, EscapingSchem
throws IOException {
boolean metadataWritten = false;
MetricMetadata metadata = snapshot.getMetadata();
String name = getExpositionBaseMetadataName(metadata, scheme);
for (SummarySnapshot.SummaryDataPointSnapshot data : snapshot.getDataPoints()) {
if (data.getQuantiles().size() == 0 && !data.hasCount() && !data.hasSum()) {
continue;
}
if (!metadataWritten) {
writeMetadata(writer, "summary", metadata, scheme);
writeMetadataWithName(writer, name, "summary", metadata);
metadataWritten = true;
}
Exemplars exemplars = data.getExemplars();
Expand All @@ -280,13 +278,7 @@ private void writeSummary(Writer writer, SummarySnapshot snapshot, EscapingSchem
int exemplarIndex = 1;
for (Quantile quantile : data.getQuantiles()) {
writeNameAndLabels(
writer,
getMetadataName(metadata, scheme),
null,
data.getLabels(),
scheme,
"quantile",
quantile.getQuantile());
writer, name, null, data.getLabels(), scheme, "quantile", quantile.getQuantile());
writeDouble(writer, quantile.getValue());
if (exemplars.size() > 0 && exemplarsOnAllMetricTypesEnabled) {
exemplarIndex = (exemplarIndex + 1) % exemplars.size();
Expand All @@ -296,18 +288,20 @@ private void writeSummary(Writer writer, SummarySnapshot snapshot, EscapingSchem
}
}
// Unlike histograms, summaries can have only a count or only a sum according to OpenMetrics.
writeCountAndSum(writer, metadata, data, "_count", "_sum", exemplars, scheme);
writeCreated(writer, metadata, data, scheme);
writeCountAndSum(writer, name, data, "_count", "_sum", exemplars, scheme);
writeCreated(writer, name, data, scheme);
}
}

private void writeInfo(Writer writer, InfoSnapshot snapshot, EscapingScheme scheme)
throws IOException {
MetricMetadata metadata = snapshot.getMetadata();
writeMetadata(writer, "info", metadata, scheme);
// OM2 spec: Info MetricFamily name MUST end in _info
String infoName = ensureSuffix(getExpositionBaseMetadataName(metadata, scheme), "_info");
String baseName = removeSuffix(infoName, "_info");
writeMetadataWithName(writer, baseName, "info", metadata);
for (InfoSnapshot.InfoDataPointSnapshot data : snapshot.getDataPoints()) {
writeNameAndLabels(
writer, getMetadataName(metadata, scheme), "_info", data.getLabels(), scheme);
writeNameAndLabels(writer, infoName, null, data.getLabels(), scheme);
writer.write("1");
writeScrapeTimestampAndExemplar(writer, data, null, scheme);
}
Expand All @@ -316,10 +310,11 @@ private void writeInfo(Writer writer, InfoSnapshot snapshot, EscapingScheme sche
private void writeStateSet(Writer writer, StateSetSnapshot snapshot, EscapingScheme scheme)
throws IOException {
MetricMetadata metadata = snapshot.getMetadata();
writeMetadata(writer, "stateset", metadata, scheme);
String name = getExpositionBaseMetadataName(metadata, scheme);
writeMetadataWithName(writer, name, "stateset", metadata);
for (StateSetSnapshot.StateSetDataPointSnapshot data : snapshot.getDataPoints()) {
for (int i = 0; i < data.size(); i++) {
writer.write(getMetadataName(metadata, scheme));
writer.write(name);
writer.write('{');
Labels labels = data.getLabels();
for (int j = 0; j < labels.size(); j++) {
Expand All @@ -334,7 +329,7 @@ private void writeStateSet(Writer writer, StateSetSnapshot snapshot, EscapingSch
if (!labels.isEmpty()) {
writer.write(",");
}
writer.write(getMetadataName(metadata, scheme));
writer.write(name);
writer.write("=\"");
writeEscapedString(writer, data.getName(i));
writer.write("\"} ");
Expand All @@ -351,9 +346,10 @@ private void writeStateSet(Writer writer, StateSetSnapshot snapshot, EscapingSch
private void writeUnknown(Writer writer, UnknownSnapshot snapshot, EscapingScheme scheme)
throws IOException {
MetricMetadata metadata = snapshot.getMetadata();
writeMetadata(writer, "unknown", metadata, scheme);
String name = getExpositionBaseMetadataName(metadata, scheme);
writeMetadataWithName(writer, name, "unknown", metadata);
for (UnknownSnapshot.UnknownDataPointSnapshot data : snapshot.getDataPoints()) {
writeNameAndLabels(writer, getMetadataName(metadata, scheme), null, data.getLabels(), scheme);
writeNameAndLabels(writer, name, null, data.getLabels(), scheme);
writeDouble(writer, data.getValue());
if (exemplarsOnAllMetricTypesEnabled) {
writeScrapeTimestampAndExemplar(writer, data, data.getExemplar(), scheme);
Expand All @@ -365,16 +361,15 @@ private void writeUnknown(Writer writer, UnknownSnapshot snapshot, EscapingSchem

private void writeCountAndSum(
Writer writer,
MetricMetadata metadata,
String name,
DistributionDataPointSnapshot data,
String countSuffix,
String sumSuffix,
Exemplars exemplars,
EscapingScheme scheme)
throws IOException {
if (data.hasCount()) {
writeNameAndLabels(
writer, getMetadataName(metadata, scheme), countSuffix, data.getLabels(), scheme);
writeNameAndLabels(writer, name, countSuffix, data.getLabels(), scheme);
writeLong(writer, data.getCount());
if (exemplarsOnAllMetricTypesEnabled) {
writeScrapeTimestampAndExemplar(writer, data, exemplars.getLatest(), scheme);
Expand All @@ -383,19 +378,17 @@ private void writeCountAndSum(
}
}
if (data.hasSum()) {
writeNameAndLabels(
writer, getMetadataName(metadata, scheme), sumSuffix, data.getLabels(), scheme);
writeNameAndLabels(writer, name, sumSuffix, data.getLabels(), scheme);
writeDouble(writer, data.getSum());
writeScrapeTimestampAndExemplar(writer, data, null, scheme);
}
}

private void writeCreated(
Writer writer, MetricMetadata metadata, DataPointSnapshot data, EscapingScheme scheme)
Writer writer, String name, DataPointSnapshot data, EscapingScheme scheme)
throws IOException {
if (createdTimestampsEnabled && data.hasCreatedTimestamp()) {
writeNameAndLabels(
writer, getMetadataName(metadata, scheme), "_created", data.getLabels(), scheme);
writeNameAndLabels(writer, name, "_created", data.getLabels(), scheme);
writeOpenMetricsTimestamp(writer, data.getCreatedTimestampMillis());
if (data.hasScrapeTimestamp()) {
writer.write(' ');
Expand Down Expand Up @@ -466,27 +459,40 @@ private void writeScrapeTimestampAndExemplar(
writer.write('\n');
}

private void writeMetadata(
Writer writer, String typeName, MetricMetadata metadata, EscapingScheme scheme)
throws IOException {
private void writeMetadataWithName(
Writer writer, String name, String typeName, MetricMetadata metadata) throws IOException {
writer.write("# TYPE ");
writeName(writer, getMetadataName(metadata, scheme), NameType.Metric);
writeName(writer, name, NameType.Metric);
writer.write(' ');
writer.write(typeName);
writer.write('\n');
if (metadata.getUnit() != null) {
writer.write("# UNIT ");
writeName(writer, getMetadataName(metadata, scheme), NameType.Metric);
writeName(writer, name, NameType.Metric);
writer.write(' ');
writeEscapedString(writer, metadata.getUnit().toString());
writer.write('\n');
}
if (metadata.getHelp() != null && !metadata.getHelp().isEmpty()) {
writer.write("# HELP ");
writeName(writer, getMetadataName(metadata, scheme), NameType.Metric);
writeName(writer, name, NameType.Metric);
writer.write(' ');
writeEscapedString(writer, metadata.getHelp());
writer.write('\n');
}
}

private static String ensureSuffix(String name, String suffix) {
if (name.endsWith(suffix)) {
return name;
}
return name + suffix;
}

private static String removeSuffix(String name, String suffix) {
if (name.endsWith(suffix)) {
return name.substring(0, name.length() - suffix.length());
}
return name;
}
}
Loading
Loading