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