001package io.prometheus.client;
002
003import java.util.Arrays;
004import java.util.Collections;
005import java.util.concurrent.ConcurrentHashMap;
006import java.util.Enumeration;
007import java.util.Iterator;
008import java.util.List;
009import java.util.NoSuchElementException;
010import java.util.Set;
011
012/**
013 * A registry of Collectors.
014 * <p>
015 * The majority of users should use the {@link #defaultRegistry}, rather than instantiating their own.
016 * <p>
017 * Creating a registry other than the default is primarily useful for unittests, or
018 * pushing a subset of metrics to the <a href="https://github.com/prometheus/pushgateway">Pushgateway</a>
019 * from batch jobs.
020 */
021public class CollectorRegistry {
022  /**
023   * The default registry.
024   */
025  public static final CollectorRegistry defaultRegistry = new CollectorRegistry();
026
027  private final Set<Collector> collectors = 
028      Collections.newSetFromMap(new ConcurrentHashMap<Collector, Boolean>());
029
030  /**
031   * Register a Collector.
032   * <p>
033   * A collector can be registered to multiple CollectorRegistries.
034   */
035  public void register(Collector m) {
036    collectors.add(m);
037  }
038  
039  /**
040   * Unregister a Collector.
041   */
042  public void unregister(Collector m) {
043    collectors.remove(m);
044  }
045  /**
046   * Unregister all Collectors.
047   */
048  public void clear() {
049    collectors.clear();
050  }
051 
052  /**
053   * Enumeration of metrics of all registered collectors.
054   */
055  public Enumeration<Collector.MetricFamilySamples> metricFamilySamples() {
056    return new MetricFamilySamplesEnumeration();
057  }
058  class MetricFamilySamplesEnumeration implements Enumeration<Collector.MetricFamilySamples> {
059
060    private final Iterator<Collector> collectorIter = collectors.iterator();
061    private Iterator<Collector.MetricFamilySamples> metricFamilySamples;
062    private Collector.MetricFamilySamples next;
063
064    MetricFamilySamplesEnumeration() {
065      findNextElement();
066    }
067    
068    private void findNextElement() {
069      if (metricFamilySamples != null && metricFamilySamples.hasNext()) {
070        next = metricFamilySamples.next();
071      } else {
072        while (collectorIter.hasNext()) {
073          metricFamilySamples = collectorIter.next().collect().iterator();
074          if (metricFamilySamples.hasNext()) {
075            next = metricFamilySamples.next();
076            return;
077          }
078        }
079        next = null;
080      }
081    }
082
083    public Collector.MetricFamilySamples nextElement() {
084      Collector.MetricFamilySamples current = next;
085      if (current == null) {
086        throw new NoSuchElementException();
087      }
088      findNextElement();
089      return current;
090    }
091    
092    public boolean hasMoreElements() {
093      return next != null;
094    }
095  }
096
097  /**
098   * Returns the given value, or null if it doesn't exist.
099   * <p>
100   * This is inefficient, and intended only for use in unittests.
101   */
102  public Double getSampleValue(String name) {
103    return getSampleValue(name, new String[]{}, new String[]{});
104  }
105
106  /**
107   * Returns the given value, or null if it doesn't exist.
108   * <p>
109   * This is inefficient, and intended only for use in unittests.
110   */
111  public Double getSampleValue(String name, String[] labelNames, String[] labelValues) {
112    for (Collector.MetricFamilySamples metricFamilySamples: Collections.list(metricFamilySamples())) {
113      for (Collector.MetricFamilySamples.Sample sample: metricFamilySamples.samples) {
114        if (sample.name.equals(name)
115            && Arrays.equals(sample.labelNames.toArray(), labelNames)
116            && Arrays.equals(sample.labelValues.toArray(), labelValues)) {
117          return new Double(sample.value);
118        }
119      }
120    }
121    return null;
122  }
123
124}