001package io.prometheus.metrics.model.snapshots;
002
003import static io.prometheus.metrics.model.snapshots.PrometheusNaming.prometheusName;
004import static java.util.Collections.unmodifiableList;
005import static java.util.Comparator.comparing;
006
007import java.util.ArrayList;
008import java.util.Arrays;
009import java.util.Collection;
010import java.util.HashSet;
011import java.util.Iterator;
012import java.util.List;
013import java.util.Set;
014import java.util.stream.Stream;
015
016/** Immutable list of metric snapshots. */
017public class MetricSnapshots implements Iterable<MetricSnapshot> {
018
019  private final List<MetricSnapshot> snapshots;
020
021  /** See {@link #MetricSnapshots(Collection)} */
022  public MetricSnapshots(MetricSnapshot... snapshots) {
023    this(Arrays.asList(snapshots));
024  }
025
026  /**
027   * To create MetricSnapshots, you can either call the constructor directly or use {@link
028   * #builder()}.
029   *
030   * @param snapshots the constructor creates a sorted copy of snapshots.
031   * @throws IllegalArgumentException if snapshots contains duplicate metric names. To avoid
032   *     duplicate metric names use {@link #builder()} and check {@link
033   *     Builder#containsMetricName(String)} before calling {@link
034   *     Builder#metricSnapshot(MetricSnapshot)}.
035   */
036  public MetricSnapshots(Collection<MetricSnapshot> snapshots) {
037    List<MetricSnapshot> list = new ArrayList<>(snapshots);
038    list.sort(comparing(s -> s.getMetadata().getPrometheusName()));
039    for (int i = 0; i < snapshots.size() - 1; i++) {
040      if (list.get(i)
041          .getMetadata()
042          .getPrometheusName()
043          .equals(list.get(i + 1).getMetadata().getPrometheusName())) {
044        throw new IllegalArgumentException(
045            list.get(i).getMetadata().getPrometheusName() + ": duplicate metric name");
046      }
047    }
048    this.snapshots = unmodifiableList(list);
049  }
050
051  public static MetricSnapshots of(MetricSnapshot... snapshots) {
052    return new MetricSnapshots(snapshots);
053  }
054
055  @Override
056  public Iterator<MetricSnapshot> iterator() {
057    return snapshots.iterator();
058  }
059
060  public int size() {
061    return snapshots.size();
062  }
063
064  public MetricSnapshot get(int i) {
065    return snapshots.get(i);
066  }
067
068  public Stream<MetricSnapshot> stream() {
069    return snapshots.stream();
070  }
071
072  public static Builder builder() {
073    return new Builder();
074  }
075
076  public static class Builder {
077
078    private final List<MetricSnapshot> snapshots = new ArrayList<>();
079    private final Set<String> prometheusNames = new HashSet<>();
080
081    private Builder() {}
082
083    public boolean containsMetricName(String name) {
084      if (name == null) {
085        return false;
086      }
087      String prometheusName = prometheusName(name);
088      return prometheusNames.contains(prometheusName);
089    }
090
091    /** Add a metric snapshot. Call multiple times to add multiple metric snapshots. */
092    public Builder metricSnapshot(MetricSnapshot snapshot) {
093      snapshots.add(snapshot);
094      prometheusNames.add(snapshot.getMetadata().getPrometheusName());
095      return this;
096    }
097
098    public MetricSnapshots build() {
099      return new MetricSnapshots(snapshots);
100    }
101  }
102}