001package io.prometheus.metrics.model.snapshots;
002
003import java.util.ArrayList;
004import java.util.Arrays;
005import java.util.Collection;
006import java.util.HashSet;
007import java.util.Iterator;
008import java.util.List;
009import java.util.Set;
010import java.util.stream.Stream;
011
012import static io.prometheus.metrics.model.snapshots.PrometheusNaming.prometheusName;
013import static java.util.Collections.unmodifiableList;
014import static java.util.Comparator.comparing;
015
016/**
017 * Immutable list of metric snapshots.
018 */
019public class MetricSnapshots implements Iterable<MetricSnapshot> {
020
021    private final List<MetricSnapshot> snapshots;
022
023    /**
024     * See {@link #MetricSnapshots(Collection)}
025     */
026    public MetricSnapshots(MetricSnapshot... snapshots) {
027        this(Arrays.asList(snapshots));
028    }
029
030    /**
031     * To create MetricSnapshots, you can either call the constructor directly
032     * or use {@link #builder()}.
033     *
034     * @param snapshots the constructor creates a sorted copy of snapshots.
035     * @throws IllegalArgumentException if snapshots contains duplicate metric names.
036     *                                  To avoid duplicate metric names use {@link #builder()} and check
037     *                                  {@link Builder#containsMetricName(String)} before calling
038     *                                  {@link Builder#metricSnapshot(MetricSnapshot)}.
039     */
040    public MetricSnapshots(Collection<MetricSnapshot> snapshots) {
041        List<MetricSnapshot> list = new ArrayList<>(snapshots);
042        list.sort(comparing(s -> s.getMetadata().getPrometheusName()));
043        for (int i = 0; i < snapshots.size() - 1; i++) {
044            if (list.get(i).getMetadata().getPrometheusName().equals(list.get(i + 1).getMetadata().getPrometheusName())) {
045                throw new IllegalArgumentException(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
084        public boolean containsMetricName(String name) {
085            if (name == null) {
086                return false;
087            }
088            String prometheusName = prometheusName(name);
089            return prometheusNames.contains(prometheusName);
090        }
091
092        /**
093         * Add a metric snapshot. Call multiple times to add multiple metric snapshots.
094         */
095        public Builder metricSnapshot(MetricSnapshot snapshot) {
096            snapshots.add(snapshot);
097            prometheusNames.add(snapshot.getMetadata().getPrometheusName());
098            return this;
099        }
100
101        public MetricSnapshots build() {
102            return new MetricSnapshots(snapshots);
103        }
104    }
105}