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}