001package io.prometheus.client; 002 003import java.util.ArrayList; 004import java.util.Collections; 005import java.util.List; 006import java.util.Map; 007 008/** 009 * Counter metric, to track counts of events or running totals. 010 * <p> 011 * Example of Counters include: 012 * <ul> 013 * <li>Number of requests processed</li> 014 * <li>Number of items that were inserted into a queue</li> 015 * <li>Total amount of data a system has processed</li> 016 * </ul> 017 * 018 * Counters can only go up (and be reset), if your use case can go down you should use a {@link Gauge} instead. 019 * Use the <code>rate()</code> function in Prometheus to calculate the rate of increase of a Counter. 020 * By convention, the names of Counters are suffixed by <code>_total</code>. 021 * 022 * <p> 023 * An example Counter: 024 * <pre> 025 * {@code 026 * class YourClass { 027 * static final Counter requests = Counter.build() 028 * .name("requests_total").help("Total requests.").register(); 029 * static final Counter failedRequests = Counter.build() 030 * .name("requests_failed_total").help("Total failed requests.").register(); 031 * 032 * void processRequest() { 033 * requests.inc(); 034 * try { 035 * // Your code here. 036 * } catch (Exception e) { 037 * failedRequests.inc(); 038 * throw e; 039 * } 040 * } 041 * } 042 * } 043 * </pre> 044 * 045 * <p> 046 * You can also use labels to track different types of metric: 047 * <pre> 048 * {@code 049 * class YourClass { 050 * static final Counter requests = Counter.build() 051 * .name("requests_total").help("Total requests.") 052 * .labelNames("method").register(); 053 * 054 * void processGetRequest() { 055 * requests.labels("get").inc(); 056 * // Your code here. 057 * } 058 * void processPostRequest() { 059 * requests.labels("post").inc(); 060 * // Your code here. 061 * } 062 * } 063 * } 064 * </pre> 065 * These can be aggregated and processed together much more easily in the Prometheus 066 * server than individual metrics for each labelset. 067 */ 068public class Counter extends SimpleCollector<Counter.Child> implements Collector.Describable { 069 070 Counter(Builder b) { 071 super(b); 072 } 073 074 public static class Builder extends SimpleCollector.Builder<Builder, Counter> { 075 @Override 076 public Counter create() { 077 return new Counter(this); 078 } 079 } 080 081 /** 082 * Return a Builder to allow configuration of a new Counter. Ensures required fields are provided. 083 * 084 * @param name The name of the metric 085 * @param help The help string of the metric 086 */ 087 public static Builder build(String name, String help) { 088 return new Builder().name(name).help(help); 089 } 090 091 /** 092 * Return a Builder to allow configuration of a new Counter. 093 */ 094 public static Builder build() { 095 return new Builder(); 096 } 097 098 @Override 099 protected Child newChild() { 100 return new Child(); 101 } 102 103 /** 104 * The value of a single Counter. 105 * <p> 106 * <em>Warning:</em> References to a Child become invalid after using 107 * {@link SimpleCollector#remove} or {@link SimpleCollector#clear}, 108 */ 109 public static class Child { 110 private final DoubleAdder value = new DoubleAdder(); 111 /** 112 * Increment the counter by 1. 113 */ 114 public void inc() { 115 inc(1); 116 } 117 /** 118 * Increment the counter by the given amount. 119 * @throws IllegalArgumentException If amt is negative. 120 */ 121 public void inc(double amt) { 122 if (amt < 0) { 123 throw new IllegalArgumentException("Amount to increment must be non-negative."); 124 } 125 value.add(amt); 126 } 127 /** 128 * Get the value of the counter. 129 */ 130 public double get() { 131 return value.sum(); 132 } 133 } 134 135 // Convenience methods. 136 /** 137 * Increment the counter with no labels by 1. 138 */ 139 public void inc() { 140 inc(1); 141 } 142 /** 143 * Increment the counter with no labels by the given amount. 144 * @throws IllegalArgumentException If amt is negative. 145 */ 146 public void inc(double amt) { 147 noLabelsChild.inc(amt); 148 } 149 150 /** 151 * Get the value of the counter. 152 */ 153 public double get() { 154 return noLabelsChild.get(); 155 } 156 157 @Override 158 public List<MetricFamilySamples> collect() { 159 List<MetricFamilySamples.Sample> samples = new ArrayList<MetricFamilySamples.Sample>(children.size()); 160 for(Map.Entry<List<String>, Child> c: children.entrySet()) { 161 samples.add(new MetricFamilySamples.Sample(fullname, labelNames, c.getKey(), c.getValue().get())); 162 } 163 return familySamplesList(Type.COUNTER, samples); 164 } 165 166 @Override 167 public List<MetricFamilySamples> describe() { 168 return Collections.<MetricFamilySamples>singletonList(new CounterMetricFamily(fullname, help, labelNames)); 169 } 170}