io.prometheus.client.Gauge Maven / Gradle / Ivy
Show all versions of simpleclient Show documentation
package io.prometheus.client;
import java.io.Closeable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Gauge metric, to report instantaneous values.
*
* Examples of Gauges include:
*
* - Inprogress requests
* - Number of items in a queue
* - Free memory
* - Total memory
* - Temperature
*
*
* Gauges can go both up and down.
*
* An example Gauge:
*
* {@code
* class YourClass {
* static final Gauge inprogressRequests = Gauge.build()
* .name("inprogress_requests").help("Inprogress requests.").register();
*
* void processRequest() {
* inprogressRequest.inc();
* // Your code here.
* inprogressRequest.dec();
* }
* }
* }
*
*
*
* You can also use labels to track different types of metric:
*
* {@code
* class YourClass {
* static final Gauge inprogressRequests = Gauge.build()
* .name("inprogress_requests").help("Inprogress requests.")
* .labelNames("method").register();
*
* void processGetRequest() {
* inprogressRequests.labels("get").inc();
* // Your code here.
* inprogressRequests.labels("get").dec();
* }
* void processPostRequest() {
* inprogressRequests.labels("post").inc();
* // Your code here.
* inprogressRequests.labels("post").dec();
* }
* }
* }
*
*
* These can be aggregated and processed together much more easily in the Prometheus
* server than individual metrics for each labelset.
*/
public class Gauge extends SimpleCollector implements Collector.Describable {
Gauge(Builder b) {
super(b);
}
public static class Builder extends SimpleCollector.Builder {
@Override
public Gauge create() {
return new Gauge(this);
}
}
/**
* Return a Builder to allow configuration of a new Gauge. Ensures required fields are provided.
*
* @param name The name of the metric
* @param help The help string of the metric
*/
public static Builder build(String name, String help) {
return new Builder().name(name).help(help);
}
/**
* Return a Builder to allow configuration of a new Gauge.
*/
public static Builder build() {
return new Builder();
}
@Override
protected Child newChild() {
return new Child();
}
/**
* Represents an event being timed.
*/
public static class Timer implements Closeable {
private final Child child;
private final long start;
private Timer(Child child) {
this.child = child;
start = Child.timeProvider.nanoTime();
}
/**
* Set the amount of time in seconds since {@link Child#startTimer} was called.
* @return Measured duration in seconds since {@link Child#startTimer} was called.
*/
public double setDuration() {
double elapsed = (Child.timeProvider.nanoTime() - start) / NANOSECONDS_PER_SECOND;
child.set(elapsed);
return elapsed;
}
/**
* Equivalent to calling {@link #setDuration()}.
*/
@Override
public void close() {
setDuration();
}
}
/**
* The value of a single Gauge.
*
* Warning: References to a Child become invalid after using
* {@link SimpleCollector#remove} or {@link SimpleCollector#clear},
*/
public static class Child {
private final DoubleAdder value = new DoubleAdder();
static TimeProvider timeProvider = new TimeProvider();
/**
* Increment the gauge by 1.
*/
public void inc() {
inc(1);
}
/**
* Increment the gauge by the given amount.
*/
public void inc(double amt) {
value.add(amt);
}
/**
* Decrement the gauge by 1.
*/
public void dec() {
dec(1);
}
/**
* Decrement the gauge by the given amount.
*/
public void dec(double amt) {
value.add(-amt);
}
/**
* Set the gauge to the given value.
*/
public void set(double val) {
synchronized(this) {
value.reset();
// If get() were called here it'd see an invalid value, so use a lock.
// inc()/dec() don't need locks, as all the possible outcomes
// are still possible if set() were atomic so no new races are introduced.
value.add(val);
}
}
/**
* Set the gauge to the current unixtime.
*/
public void setToCurrentTime() {
set(timeProvider.currentTimeMillis() / MILLISECONDS_PER_SECOND);
}
/**
* Start a timer to track a duration.
*
* Call {@link Timer#setDuration} at the end of what you want to measure the duration of.
*
* This is primarily useful for tracking the durations of major steps of batch jobs,
* which are then pushed to a PushGateway.
* For tracking other durations/latencies you should usually use a {@link Summary}.
*/
public Timer startTimer() {
return new Timer(this);
}
/**
* Executes runnable code (i.e. a Java 8 Lambda) and observes a duration of how long it took to run.
*
* @param timeable Code that is being timed
* @return Measured duration in seconds for timeable to complete.
*/
public double setToTime(Runnable timeable){
Timer timer = startTimer();
double elapsed;
try {
timeable.run();
} finally {
elapsed = timer.setDuration();
}
return elapsed;
}
/**
* Get the value of the gauge.
*/
public double get() {
synchronized(this) {
return value.sum();
}
}
}
// Convenience methods.
/**
* Increment the gauge with no labels by 1.
*/
public void inc() {
inc(1);
}
/**
* Increment the gauge with no labels by the given amount.
*/
public void inc(double amt) {
noLabelsChild.inc(amt);
}
/**
* Increment the gauge with no labels by 1.
*/
public void dec() {
dec(1);
}
/**
* Decrement the gauge with no labels by the given amount.
*/
public void dec(double amt) {
noLabelsChild.dec(amt);
}
/**
* Set the gauge with no labels to the given value.
*/
public void set(double val) {
noLabelsChild.set(val);
}
/**
* Set the gauge with no labels to the current unixtime.
*/
public void setToCurrentTime() {
noLabelsChild.setToCurrentTime();
}
/**
* Start a timer to track a duration, for the gauge with no labels.
*
* This is primarily useful for tracking the durations of major steps of batch jobs,
* which are then pushed to a PushGateway.
* For tracking other durations/latencies you should usually use a {@link Summary}.
*
* Call {@link Timer#setDuration} at the end of what you want to measure the duration of.
*/
public Timer startTimer() {
return noLabelsChild.startTimer();
}
/**
* Executes runnable code (i.e. a Java 8 Lambda) and observes a duration of how long it took to run.
*
* @param timeable Code that is being timed
* @return Measured duration in seconds for timeable to complete.
*/
public double setToTime(Runnable timeable){
return noLabelsChild.setToTime(timeable);
}
/**
* Get the value of the gauge.
*/
public double get() {
return noLabelsChild.get();
}
@Override
public List collect() {
List samples = new ArrayList(children.size());
for(Map.Entry, Child> c: children.entrySet()) {
samples.add(new MetricFamilySamples.Sample(fullname, labelNames, c.getKey(), c.getValue().get()));
}
return familySamplesList(Type.GAUGE, samples);
}
@Override
public List describe() {
return Collections.singletonList(new GaugeMetricFamily(fullname, help, labelNames));
}
static class TimeProvider {
long currentTimeMillis() {
return System.currentTimeMillis();
}
long nanoTime() {
return System.nanoTime();
}
}
}