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