001package io.prometheus.client;
002
003import java.io.Closeable;
004import java.util.ArrayList;
005import java.util.Collections;
006import java.util.List;
007import java.util.Map;
008import java.util.concurrent.Callable;
009
010/**
011 * Gauge metric, to report instantaneous values.
012 * <p>
013 * Examples of Gauges include:
014 * <ul>
015 *  <li>Inprogress requests</li>
016 *  <li>Number of items in a queue</li>
017 *  <li>Free memory</li>
018 *  <li>Total memory</li>
019 *  <li>Temperature</li>
020 * </ul>
021 *
022 * Gauges can go both up and down.
023 * <p>
024 * An example Gauge:
025 * <pre>
026 * {@code
027 *   class YourClass {
028 *     static final Gauge inprogressRequests = Gauge.build()
029 *         .name("inprogress_requests").help("Inprogress requests.").register();
030 *
031 *     void processRequest() {
032 *        inprogressRequests.inc();
033 *        // Your code here.
034 *        inprogressRequests.dec();
035 *     }
036 *   }
037 * }
038 * </pre>
039 *
040 * <p>
041 * You can also use labels to track different types of metric:
042 * <pre>
043 * {@code
044 *   class YourClass {
045 *     static final Gauge inprogressRequests = Gauge.build()
046 *         .name("inprogress_requests").help("Inprogress requests.")
047 *         .labelNames("method").register();
048 *
049 *     void processGetRequest() {
050 *        inprogressRequests.labels("get").inc();
051 *        // Your code here.
052 *        inprogressRequests.labels("get").dec();
053 *     }
054 *     void processPostRequest() {
055 *        inprogressRequests.labels("post").inc();
056 *        // Your code here.
057 *        inprogressRequests.labels("post").dec();
058 *     }
059 *   }
060 * }
061 * </pre>
062 * <p>
063 * These can be aggregated and processed together much more easily in the Prometheus
064 * server than individual metrics for each labelset.
065 */
066public class Gauge extends SimpleCollector<Gauge.Child> implements Collector.Describable {
067
068  Gauge(Builder b) {
069    super(b);
070  }
071
072  public static class Builder extends SimpleCollector.Builder<Builder, Gauge> {
073    @Override
074    public Gauge create() {
075      return new Gauge(this);
076    }
077  }
078
079  /**
080   *  Return a Builder to allow configuration of a new Gauge. Ensures required fields are provided.
081   *
082   *  @param name The name of the metric
083   *  @param help The help string of the metric
084   */
085  public static Builder build(String name, String help) {
086    return new Builder().name(name).help(help);
087  }
088
089  /**
090   *  Return a Builder to allow configuration of a new Gauge.
091   */
092  public static Builder build() {
093    return new Builder();
094  }
095
096  @Override
097  protected Child newChild() {
098    return new Child();
099  }
100
101   /**
102    * Represents an event being timed.
103    */
104   public static class Timer implements Closeable {
105     private final Child child;
106     private final long start;
107     private Timer(Child child) {
108       this.child = child;
109       start = Child.timeProvider.nanoTime();
110     }
111     /**
112      * Set the amount of time in seconds since {@link Child#startTimer} was called.
113      * @return Measured duration in seconds since {@link Child#startTimer} was called.
114      */
115     public double setDuration() {
116       double elapsed = (Child.timeProvider.nanoTime() - start) / NANOSECONDS_PER_SECOND;
117       child.set(elapsed);
118       return elapsed;
119     }
120
121     /**
122      * Equivalent to calling {@link #setDuration()}.
123      */
124     @Override
125     public void close() {
126       setDuration();
127     }
128   }
129
130  /**
131   * The value of a single Gauge.
132   * <p>
133   * <em>Warning:</em> References to a Child become invalid after using
134   * {@link SimpleCollector#remove} or {@link SimpleCollector#clear},
135   */
136  public static class Child {
137
138    private final DoubleAdder value = new DoubleAdder();
139
140    static TimeProvider timeProvider = new TimeProvider();
141
142    /**
143     * Increment the gauge by 1.
144     */
145    public void inc() {
146      inc(1);
147    }
148    /**
149     * Increment the gauge by the given amount.
150     */
151    public void inc(double amt) {
152      value.add(amt);
153    }
154    /**
155     * Decrement the gauge by 1.
156     */
157    public void dec() {
158      dec(1);
159    }
160    /**
161     * Decrement the gauge by the given amount.
162     */
163    public void dec(double amt) {
164      value.add(-amt);
165    }
166    /**
167     * Set the gauge to the given value.
168     */
169    public void set(double val) {
170      value.set(val);
171    }
172    /**
173     * Set the gauge to the current unixtime.
174     */
175    public void setToCurrentTime() {
176      set(timeProvider.currentTimeMillis() / MILLISECONDS_PER_SECOND);
177    }
178    /**
179     * Start a timer to track a duration.
180     * <p>
181     * Call {@link Timer#setDuration} at the end of what you want to measure the duration of.
182     * <p>
183     * This is primarily useful for tracking the durations of major steps of batch jobs,
184     * which are then pushed to a PushGateway.
185     * For tracking other durations/latencies you should usually use a {@link Summary}.
186     */
187    public Timer startTimer() {
188      return new Timer(this);
189    }
190
191    /**
192     * Executes runnable code (e.g. a Java 8 Lambda) and observes a duration of how long it took to run.
193     *
194     * @param timeable Code that is being timed
195     * @return Measured duration in seconds for timeable to complete.
196     */
197    public double setToTime(Runnable timeable){
198      Timer timer = startTimer();
199
200      double elapsed;
201      try {
202        timeable.run();
203      } finally {
204        elapsed = timer.setDuration();
205      }
206
207      return elapsed;
208    }
209
210    /**
211     * Executes callable code (e.g. a Java 8 Lambda) and observes a duration of how long it took to run.
212     *
213     * @param timeable Code that is being timed
214     * @return Result returned by callable.
215     */
216    public <E> E setToTime(Callable<E> timeable){
217      Timer timer = startTimer();
218
219      try {
220        return timeable.call();
221      } catch (Exception e) {
222        throw new RuntimeException(e);
223      } finally {
224        timer.setDuration();
225      }
226    }
227
228    /**
229     * Get the value of the gauge.
230     */
231    public double get() {
232      return value.sum();
233    }
234  }
235
236  // Convenience methods.
237  /**
238   * Increment the gauge with no labels by 1.
239   */
240  public void inc() {
241    inc(1);
242  }
243  /**
244   * Increment the gauge with no labels by the given amount.
245   */
246  public void inc(double amt) {
247    noLabelsChild.inc(amt);
248  }
249  /**
250   * Decrement the gauge with no labels by 1.
251   */
252  public void dec() {
253    dec(1);
254  }
255  /**
256   * Decrement the gauge with no labels by the given amount.
257   */
258  public void dec(double amt) {
259    noLabelsChild.dec(amt);
260  }
261  /**
262   * Set the gauge with no labels to the given value.
263   */
264  public void set(double val) {
265    noLabelsChild.set(val);
266  }
267  /**
268   * Set the gauge with no labels to the current unixtime.
269   */
270  public void setToCurrentTime() {
271    noLabelsChild.setToCurrentTime();
272  }
273  /**
274   * Start a timer to track a duration, for the gauge with no labels.
275   * <p>
276   * This is primarily useful for tracking the durations of major steps of batch jobs,
277   * which are then pushed to a PushGateway.
278   * For tracking other durations/latencies you should usually use a {@link Summary}.
279   * <p>
280   * Call {@link Timer#setDuration} at the end of what you want to measure the duration of.
281   */
282  public Timer startTimer() {
283    return noLabelsChild.startTimer();
284  }
285
286  /**
287   * Executes runnable code (e.g. a Java 8 Lambda) and observes a duration of how long it took to run.
288   *
289   * @param timeable Code that is being timed
290   * @return Measured duration in seconds for timeable to complete.
291   */
292  public double setToTime(Runnable timeable){
293    return noLabelsChild.setToTime(timeable);
294  }
295
296  /**
297   * Executes callable code (e.g. a Java 8 Lambda) and observes a duration of how long it took to run.
298   *
299   * @param timeable Code that is being timed
300   * @return Result returned by callable.
301   */
302  public <E> E setToTime(Callable<E> timeable){
303    return noLabelsChild.setToTime(timeable);
304  }
305
306  /**
307   * Get the value of the gauge.
308   */
309  public double get() {
310    return noLabelsChild.get();
311  }
312
313  @Override
314  public List<MetricFamilySamples> collect() {
315    List<MetricFamilySamples.Sample> samples = new ArrayList<MetricFamilySamples.Sample>(children.size());
316    for(Map.Entry<List<String>, Child> c: children.entrySet()) {
317      samples.add(new MetricFamilySamples.Sample(fullname, labelNames, c.getKey(), c.getValue().get()));
318    }
319    return familySamplesList(Type.GAUGE, samples);
320  }
321
322  @Override
323  public List<MetricFamilySamples> describe() {
324    return Collections.<MetricFamilySamples>singletonList(new GaugeMetricFamily(fullname, help, labelNames));
325  }
326
327  static class TimeProvider {
328    long currentTimeMillis() {
329      return System.currentTimeMillis();
330    }
331    long nanoTime() {
332      return System.nanoTime();
333    }
334  }
335}