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