001package io.prometheus.metrics.model.snapshots; 002 003import java.util.ArrayList; 004import java.util.Collection; 005import java.util.Collections; 006import java.util.Comparator; 007import java.util.List; 008 009/** Base class for metric snapshots. */ 010public abstract class MetricSnapshot { 011 012 private final MetricMetadata metadata; 013 protected final List<? extends DataPointSnapshot> dataPoints; 014 015 protected MetricSnapshot( 016 MetricMetadata metadata, Collection<? extends DataPointSnapshot> dataPoints) { 017 if (metadata == null) { 018 throw new NullPointerException("metadata"); 019 } 020 if (dataPoints == null) { 021 throw new NullPointerException("dataPoints"); 022 } 023 this.metadata = metadata; 024 List<? extends DataPointSnapshot> dataCopy = new ArrayList<>(dataPoints); 025 dataCopy.sort(Comparator.comparing(DataPointSnapshot::getLabels)); 026 this.dataPoints = Collections.unmodifiableList(dataCopy); 027 validateLabels(this.dataPoints, metadata); 028 } 029 030 public MetricMetadata getMetadata() { 031 return metadata; 032 } 033 034 public abstract List<? extends DataPointSnapshot> getDataPoints(); 035 036 private static <T extends DataPointSnapshot> void validateLabels( 037 List<T> dataPoints, MetricMetadata metadata) { 038 // Verify that labels are unique (the same set of names/values must not be used multiple times 039 // for the same metric). 040 for (int i = 0; i < dataPoints.size() - 1; i++) { 041 if (dataPoints.get(i).getLabels().equals(dataPoints.get(i + 1).getLabels())) { 042 throw new DuplicateLabelsException(metadata, dataPoints.get(i).getLabels()); 043 } 044 } 045 // Should we verify that all entries in data have the same label names? 046 // No. They should have the same label names, but according to OpenMetrics this is not a MUST. 047 } 048 049 public abstract static class Builder<T extends Builder<T>> { 050 051 private String name; 052 private String help; 053 private Unit unit; 054 055 /** 056 * The name is required. If the name is missing or invalid, {@code build()} will throw an {@link 057 * IllegalArgumentException}. See {@link PrometheusNaming#isValidMetricName(String)} for info on 058 * valid metric names. 059 */ 060 public T name(String name) { 061 this.name = name; 062 return self(); 063 } 064 065 public T help(String help) { 066 this.help = help; 067 return self(); 068 } 069 070 public T unit(Unit unit) { 071 this.unit = unit; 072 return self(); 073 } 074 075 public abstract MetricSnapshot build(); 076 077 protected MetricMetadata buildMetadata() { 078 return new MetricMetadata(name, help, unit); 079 } 080 081 protected abstract T self(); 082 } 083}