1 // Copyright 2014 The Prometheus Authors
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
6 // http://www.apache.org/licenses/LICENSE-2.0
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
21 dto "github.com/prometheus/client_model/go"
24 // Counter is a Metric that represents a single numerical value that only ever
25 // goes up. That implies that it cannot be used to count items whose number can
26 // also go down, e.g. the number of currently running goroutines. Those
27 // "counters" are represented by Gauges.
29 // A Counter is typically used to count requests served, tasks completed, errors
32 // To create Counter instances, use NewCounter.
33 type Counter interface {
37 // Inc increments the counter by 1. Use Add to increment it by arbitrary
38 // non-negative values.
40 // Add adds the given value to the counter. It panics if the value is <
45 // CounterOpts is an alias for Opts. See there for doc comments.
48 // NewCounter creates a new Counter based on the provided CounterOpts.
50 // The returned implementation tracks the counter value in two separate
51 // variables, a float64 and a uint64. The latter is used to track calls of the
52 // Inc method and calls of the Add method with a value that can be represented
53 // as a uint64. This allows atomic increments of the counter with optimal
54 // performance. (It is common to have an Inc call in very hot execution paths.)
55 // Both internal tracking values are added up in the Write method. This has to
56 // be taken into account when it comes to precision and overflow behavior.
57 func NewCounter(opts CounterOpts) Counter {
59 BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
64 result := &counter{desc: desc, labelPairs: desc.constLabelPairs}
65 result.init(result) // Init self-collection.
70 // valBits contains the bits of the represented float64 value, while
71 // valInt stores values that are exact integers. Both have to go first
72 // in the struct to guarantee alignment for atomic operations.
73 // http://golang.org/pkg/sync/atomic/#pkg-note-BUG
80 labelPairs []*dto.LabelPair
83 func (c *counter) Desc() *Desc {
87 func (c *counter) Add(v float64) {
89 panic(errors.New("counter cannot decrease in value"))
92 if float64(ival) == v {
93 atomic.AddUint64(&c.valInt, ival)
98 oldBits := atomic.LoadUint64(&c.valBits)
99 newBits := math.Float64bits(math.Float64frombits(oldBits) + v)
100 if atomic.CompareAndSwapUint64(&c.valBits, oldBits, newBits) {
106 func (c *counter) Inc() {
107 atomic.AddUint64(&c.valInt, 1)
110 func (c *counter) Write(out *dto.Metric) error {
111 fval := math.Float64frombits(atomic.LoadUint64(&c.valBits))
112 ival := atomic.LoadUint64(&c.valInt)
113 val := fval + float64(ival)
115 return populateMetric(CounterValue, val, c.labelPairs, out)
118 // CounterVec is a Collector that bundles a set of Counters that all share the
119 // same Desc, but have different values for their variable labels. This is used
120 // if you want to count the same thing partitioned by various dimensions
121 // (e.g. number of HTTP requests, partitioned by response code and
122 // method). Create instances with NewCounterVec.
123 type CounterVec struct {
127 // NewCounterVec creates a new CounterVec based on the provided CounterOpts and
128 // partitioned by the given label names.
129 func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
131 BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
137 metricVec: newMetricVec(desc, func(lvs ...string) Metric {
138 if len(lvs) != len(desc.variableLabels) {
139 panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs))
141 result := &counter{desc: desc, labelPairs: makeLabelPairs(desc, lvs)}
142 result.init(result) // Init self-collection.
148 // GetMetricWithLabelValues returns the Counter for the given slice of label
149 // values (same order as the VariableLabels in Desc). If that combination of
150 // label values is accessed for the first time, a new Counter is created.
152 // It is possible to call this method without using the returned Counter to only
153 // create the new Counter but leave it at its starting value 0. See also the
154 // SummaryVec example.
156 // Keeping the Counter for later use is possible (and should be considered if
157 // performance is critical), but keep in mind that Reset, DeleteLabelValues and
158 // Delete can be used to delete the Counter from the CounterVec. In that case,
159 // the Counter will still exist, but it will not be exported anymore, even if a
160 // Counter with the same label values is created later.
162 // An error is returned if the number of label values is not the same as the
163 // number of VariableLabels in Desc (minus any curried labels).
165 // Note that for more than one label value, this method is prone to mistakes
166 // caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
167 // an alternative to avoid that type of mistake. For higher label numbers, the
168 // latter has a much more readable (albeit more verbose) syntax, but it comes
169 // with a performance overhead (for creating and processing the Labels map).
170 // See also the GaugeVec example.
171 func (v *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) {
172 metric, err := v.metricVec.getMetricWithLabelValues(lvs...)
174 return metric.(Counter), err
179 // GetMetricWith returns the Counter for the given Labels map (the label names
180 // must match those of the VariableLabels in Desc). If that label map is
181 // accessed for the first time, a new Counter is created. Implications of
182 // creating a Counter without using it and keeping the Counter for later use are
183 // the same as for GetMetricWithLabelValues.
185 // An error is returned if the number and names of the Labels are inconsistent
186 // with those of the VariableLabels in Desc (minus any curried labels).
188 // This method is used for the same purpose as
189 // GetMetricWithLabelValues(...string). See there for pros and cons of the two
191 func (v *CounterVec) GetMetricWith(labels Labels) (Counter, error) {
192 metric, err := v.metricVec.getMetricWith(labels)
194 return metric.(Counter), err
199 // WithLabelValues works as GetMetricWithLabelValues, but panics where
200 // GetMetricWithLabelValues would have returned an error. Not returning an
201 // error allows shortcuts like
202 // myVec.WithLabelValues("404", "GET").Add(42)
203 func (v *CounterVec) WithLabelValues(lvs ...string) Counter {
204 c, err := v.GetMetricWithLabelValues(lvs...)
211 // With works as GetMetricWith, but panics where GetMetricWithLabels would have
212 // returned an error. Not returning an error allows shortcuts like
213 // myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Add(42)
214 func (v *CounterVec) With(labels Labels) Counter {
215 c, err := v.GetMetricWith(labels)
222 // CurryWith returns a vector curried with the provided labels, i.e. the
223 // returned vector has those labels pre-set for all labeled operations performed
224 // on it. The cardinality of the curried vector is reduced accordingly. The
225 // order of the remaining labels stays the same (just with the curried labels
226 // taken out of the sequence – which is relevant for the
227 // (GetMetric)WithLabelValues methods). It is possible to curry a curried
228 // vector, but only with labels not yet used for currying before.
230 // The metrics contained in the CounterVec are shared between the curried and
231 // uncurried vectors. They are just accessed differently. Curried and uncurried
232 // vectors behave identically in terms of collection. Only one must be
233 // registered with a given registry (usually the uncurried version). The Reset
234 // method deletes all metrics, even if called on a curried vector.
235 func (v *CounterVec) CurryWith(labels Labels) (*CounterVec, error) {
236 vec, err := v.curryWith(labels)
238 return &CounterVec{vec}, err
243 // MustCurryWith works as CurryWith but panics where CurryWith would have
244 // returned an error.
245 func (v *CounterVec) MustCurryWith(labels Labels) *CounterVec {
246 vec, err := v.CurryWith(labels)
253 // CounterFunc is a Counter whose value is determined at collect time by calling a
254 // provided function.
256 // To create CounterFunc instances, use NewCounterFunc.
257 type CounterFunc interface {
262 // NewCounterFunc creates a new CounterFunc based on the provided
263 // CounterOpts. The value reported is determined by calling the given function
264 // from within the Write method. Take into account that metric collection may
265 // happen concurrently. If that results in concurrent calls to Write, like in
266 // the case where a CounterFunc is directly registered with Prometheus, the
267 // provided function must be concurrency-safe. The function should also honor
268 // the contract for a Counter (values only go up, not down), but compliance will
270 func NewCounterFunc(opts CounterOpts, function func() float64) CounterFunc {
271 return newValueFunc(NewDesc(
272 BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
276 ), CounterValue, function)