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 /** 141 * Increment the gauge by 1. 142 */ 143 public void inc() { 144 inc(1); 145 } 146 /** 147 * Increment the gauge by the given amount. 148 */ 149 public void inc(double amt) { 150 value.add(amt); 151 } 152 /** 153 * Decrement the gauge by 1. 154 */ 155 public void dec() { 156 dec(1); 157 } 158 /** 159 * Decrement the gauge by the given amount. 160 */ 161 public void dec(double amt) { 162 value.add(-amt); 163 } 164 /** 165 * Set the gauge to the given value. 166 */ 167 public void set(double val) { 168 synchronized(this) { 169 value.reset(); 170 // If get() were called here it'd see an invalid value, so use a lock. 171 // inc()/dec() don't need locks, as all the possible outcomes 172 // are still possible if set() were atomic so no new races are introduced. 173 value.add(val); 174 } 175 } 176 /** 177 * Set the gauge to the current unixtime. 178 */ 179 public void setToCurrentTime() { 180 set(timeProvider.currentTimeMillis() / MILLISECONDS_PER_SECOND); 181 } 182 /** 183 * Start a timer to track a duration. 184 * <p> 185 * Call {@link Timer#setDuration} at the end of what you want to measure the duration of. 186 * <p> 187 * This is primarily useful for tracking the durations of major steps of batch jobs, 188 * which are then pushed to a PushGateway. 189 * For tracking other durations/latencies you should usually use a {@link Summary}. 190 */ 191 public Timer startTimer() { 192 return new Timer(this); 193 } 194 195 /** 196 * Executes runnable code (i.e. a Java 8 Lambda) and observes a duration of how long it took to run. 197 * 198 * @param timeable Code that is being timed 199 * @return Measured duration in seconds for timeable to complete. 200 */ 201 public double setToTime(Runnable timeable){ 202 Timer timer = startTimer(); 203 204 double elapsed; 205 try { 206 timeable.run(); 207 } finally { 208 elapsed = timer.setDuration(); 209 } 210 211 return elapsed; 212 } 213 214 /** 215 * Get the value of the gauge. 216 */ 217 public double get() { 218 synchronized(this) { 219 return value.sum(); 220 } 221 } 222 } 223 224 // Convenience methods. 225 /** 226 * Increment the gauge with no labels by 1. 227 */ 228 public void inc() { 229 inc(1); 230 } 231 /** 232 * Increment the gauge with no labels by the given amount. 233 */ 234 public void inc(double amt) { 235 noLabelsChild.inc(amt); 236 } 237 /** 238 * Increment the gauge with no labels by 1. 239 */ 240 public void dec() { 241 dec(1); 242 } 243 /** 244 * Decrement the gauge with no labels by the given amount. 245 */ 246 public void dec(double amt) { 247 noLabelsChild.dec(amt); 248 } 249 /** 250 * Set the gauge with no labels to the given value. 251 */ 252 public void set(double val) { 253 noLabelsChild.set(val); 254 } 255 /** 256 * Set the gauge with no labels to the current unixtime. 257 */ 258 public void setToCurrentTime() { 259 noLabelsChild.setToCurrentTime(); 260 } 261 /** 262 * Start a timer to track a duration, for the gauge with no labels. 263 * <p> 264 * This is primarily useful for tracking the durations of major steps of batch jobs, 265 * which are then pushed to a PushGateway. 266 * For tracking other durations/latencies you should usually use a {@link Summary}. 267 * <p> 268 * Call {@link Timer#setDuration} at the end of what you want to measure the duration of. 269 */ 270 public Timer startTimer() { 271 return noLabelsChild.startTimer(); 272 } 273 274 /** 275 * Executes runnable code (i.e. a Java 8 Lambda) and observes a duration of how long it took to run. 276 * 277 * @param timeable Code that is being timed 278 * @return Measured duration in seconds for timeable to complete. 279 */ 280 public double setToTime(Runnable timeable){ 281 return noLabelsChild.setToTime(timeable); 282 } 283 284 /** 285 * Get the value of the gauge. 286 */ 287 public double get() { 288 return noLabelsChild.get(); 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}