Skip to content
Closed
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
@@ -0,0 +1,257 @@
package io.prometheus.metrics.model.snapshots;

import io.prometheus.metrics.model.registry.MetricType;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.annotation.Nullable;

/** Registration-time descriptor for a metric family. */
public final class MetricFamilyDescriptor {

private final MetricType type;
private final MetricMetadata metadata;
private final Set<String> labelNames;

private MetricFamilyDescriptor(
MetricType type, MetricMetadata metadata, Collection<String> labelNames) {
this.type = type;
this.metadata = metadata;
this.labelNames = Collections.unmodifiableSet(new LinkedHashSet<>(labelNames));
}

public static Builder<?> of(MetricType type, String name) {
switch (type) {
case COUNTER:
return counter(name);
case GAUGE:
return gauge(name);
case HISTOGRAM:
return histogram(name);
case SUMMARY:
return summary(name);
case INFO:
return info(name);
case STATESET:
return stateSet(name);
case UNKNOWN:
default:
return unknown(name);
}
}

public static CounterBuilder counter(String name) {
return new CounterBuilder().name(name);
}

public static GaugeBuilder gauge(String name) {
return new GaugeBuilder().name(name);
}

public static HistogramBuilder histogram(String name) {
return new HistogramBuilder().name(name);
}

public static SummaryBuilder summary(String name) {
return new SummaryBuilder().name(name);
}

public static InfoBuilder info(String name) {
return new InfoBuilder().name(name);
}

public static StateSetBuilder stateSet(String name) {
return new StateSetBuilder().name(name);
}

public static UnknownBuilder unknown(String name) {
return new UnknownBuilder().name(name);
}

public MetricType getType() {
return type;
}

public MetricMetadata getMetadata() {
return metadata;
}

public Set<String> getLabelNames() {
return labelNames;
}

public String getPrometheusName() {
return metadata.getPrometheusName();
}

public abstract static class Builder<T extends Builder<T>> {

@Nullable protected String name;
@Nullable protected String help;
@Nullable protected Unit unit;
protected final Set<String> labelNames = new LinkedHashSet<>();

public T name(String name) {
this.name = name;
return self();
}

public T help(@Nullable String help) {
this.help = help;
return self();
}

public T unit(@Nullable Unit unit) {
this.unit = unit;
return self();
}

public T labelName(String labelName) {
this.labelNames.add(labelName);
return self();
}

public T labelNames(String... labelNames) {
Collections.addAll(this.labelNames, labelNames);
return self();
}

public T labelNames(Collection<String> labelNames) {
this.labelNames.addAll(labelNames);
return self();
}

public MetricFamilyDescriptor build() {
return new MetricFamilyDescriptor(getType(), buildMetadata(), labelNames);
}

protected MetricMetadata buildMetadata() {
if (name == null) {
throw new IllegalArgumentException("Missing required field: name is null");
}
return MetricMetadataSupport.metricMetadata(name, help, unit);
}

protected abstract MetricType getType();

protected abstract T self();
}

public static final class CounterBuilder extends Builder<CounterBuilder> {

@Override
protected MetricMetadata buildMetadata() {
if (name == null) {
throw new IllegalArgumentException("Missing required field: name is null");
}
return MetricMetadataSupport.counterMetadata(name, help, unit);
}

@Override
protected MetricType getType() {
return MetricType.COUNTER;
}

@Override
protected CounterBuilder self() {
return this;
}
}

public static final class GaugeBuilder extends Builder<GaugeBuilder> {

@Override
protected MetricType getType() {
return MetricType.GAUGE;
}

@Override
protected GaugeBuilder self() {
return this;
}
}

public static final class HistogramBuilder extends Builder<HistogramBuilder> {

@Override
protected MetricType getType() {
return MetricType.HISTOGRAM;
}

@Override
protected HistogramBuilder self() {
return this;
}
}

public static final class SummaryBuilder extends Builder<SummaryBuilder> {

@Override
protected MetricType getType() {
return MetricType.SUMMARY;
}

@Override
protected SummaryBuilder self() {
return this;
}
}

public static final class InfoBuilder extends Builder<InfoBuilder> {

@Override
public InfoBuilder unit(@Nullable Unit unit) {
throw new IllegalArgumentException("Info metric cannot have a unit.");
}

@Override
protected MetricMetadata buildMetadata() {
if (name == null) {
throw new IllegalArgumentException("Missing required field: name is null");
}
return MetricMetadataSupport.infoMetadata(name, help);
}

@Override
protected MetricType getType() {
return MetricType.INFO;
}

@Override
protected InfoBuilder self() {
return this;
}
}

public static final class StateSetBuilder extends Builder<StateSetBuilder> {

@Override
public StateSetBuilder unit(@Nullable Unit unit) {
throw new IllegalArgumentException("State set metric cannot have a unit.");
}

@Override
protected MetricType getType() {
return MetricType.STATESET;
}

@Override
protected StateSetBuilder self() {
return this;
}
}

public static final class UnknownBuilder extends Builder<UnknownBuilder> {

@Override
protected MetricType getType() {
return MetricType.UNKNOWN;
}

@Override
protected UnknownBuilder self() {
return this;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package io.prometheus.metrics.model.snapshots;

import javax.annotation.Nullable;

final class MetricMetadataSupport {

private MetricMetadataSupport() {}

static MetricMetadata metricMetadata(String name, @Nullable String help, @Nullable Unit unit) {
return new MetricMetadata(name, help, unit);
}

static MetricMetadata counterMetadata(String name, @Nullable String help, @Nullable Unit unit) {
return typedMetadata(name, help, unit, "_total", ".total");
}

static MetricMetadata infoMetadata(String name, @Nullable String help) {
return typedMetadata(name, help, null, "_info", ".info");
}

private static MetricMetadata typedMetadata(
String originalName,
@Nullable String help,
@Nullable Unit unit,
String suffix,
String dotSuffix) {
String baseName = stripSuffix(originalName, suffix, dotSuffix);
return new MetricMetadata(
appendUnitIfMissing(baseName, unit),
appendUnitIfMissing(originalName, unit),
originalName,
help,
unit);
}

private static String appendUnitIfMissing(String name, @Nullable Unit unit) {
if (unit != null && !name.endsWith("_" + unit) && !name.endsWith("." + unit)) {
return name + "_" + unit;
}
return name;
}

private static String stripSuffix(String name, String suffix, String dotSuffix) {
if (name.endsWith(suffix)) {
return name.substring(0, name.length() - suffix.length());
}
if (name.endsWith(dotSuffix)) {
return name.substring(0, name.length() - dotSuffix.length());
}
return name;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ void testMinimalGoodCase() {
.dataPoint(CounterDataPointSnapshot.builder().value(1.0).build())
.build();
SnapshotTestUtil.assertMetadata(snapshot, "events", null, null);
SnapshotTestUtil.assertDerivedMetadata(snapshot, "events", "events", "events");
assertThat(snapshot.getDataPoints()).hasSize(1);
CounterDataPointSnapshot data = snapshot.getDataPoints().get(0);
assertThat((Iterable<? extends Label>) data.getLabels()).isEmpty();
Expand All @@ -94,6 +95,13 @@ void testEmptyCounter() {
void testTotalSuffixPresent() {
CounterSnapshot snapshot = CounterSnapshot.builder().name("test_total").build();
assertThat(snapshot.getMetadata().getPrometheusName()).isEqualTo("test_total");
SnapshotTestUtil.assertDerivedMetadata(snapshot, "test_total", "test_total", "test_total");
}

@Test
void testCounterBuilderKeepsLegacyUnitValidation() {
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> CounterSnapshot.builder().name("test_total").unit(Unit.SECONDS).build());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,16 @@ void testEmptyGauge() {

@Test
void testTotalSuffixPresent() {
CounterSnapshot snapshot = CounterSnapshot.builder().name("test_total").build();
GaugeSnapshot snapshot = GaugeSnapshot.builder().name("test_total").build();
assertThat(snapshot.getMetadata().getPrometheusName()).isEqualTo("test_total");
SnapshotTestUtil.assertDerivedMetadata(snapshot, "test_total", "test_total", "test_total");
}

@Test
void testTotalSuffixPresentDot() {
CounterSnapshot snapshot = CounterSnapshot.builder().name("test.total").build();
GaugeSnapshot snapshot = GaugeSnapshot.builder().name("test.total").build();
assertThat(snapshot.getMetadata().getPrometheusName()).isEqualTo("test_total");
SnapshotTestUtil.assertDerivedMetadata(snapshot, "test.total", "test.total", "test.total");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ void testCompleteGoodCase() {
.labels(Labels.of("instance_id", "127.0.0.1:9100", "service_name", "gateway"))
.build())
.build();
assertThat(snapshot.getMetadata().getName()).isEqualTo("target");
SnapshotTestUtil.assertDerivedMetadata(snapshot, "target", "target", "target");
assertThat(snapshot.getMetadata().getHelp()).isEqualTo("Target info");
assertThat(snapshot.getMetadata().hasUnit()).isFalse();
assertThat(snapshot.getDataPoints().size()).isOne();
Expand Down Expand Up @@ -63,11 +63,13 @@ void testDataImmutable() {
void testNameMayIncludeSuffix() {
InfoSnapshot snapshot = InfoSnapshot.builder().name("jvm_info").build();
assertThat(snapshot.getMetadata().getPrometheusName()).isEqualTo("jvm_info");
SnapshotTestUtil.assertDerivedMetadata(snapshot, "jvm_info", "jvm_info", "jvm_info");
}

@Test
void testNameMayIncludeSuffixDot() {
InfoSnapshot snapshot = InfoSnapshot.builder().name("jvm.info").build();
assertThat(snapshot.getMetadata().getPrometheusName()).isEqualTo("jvm_info");
SnapshotTestUtil.assertDerivedMetadata(snapshot, "jvm.info", "jvm.info", "jvm.info");
}
}
Loading