blob: d463e36d3e98d204d55648aeec64ce1c6fd0f7ba [file] [log] [blame]
khenaidooab1f7bd2019-11-14 14:00:27 -05001// 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
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
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.
13
14package prometheus
15
16import (
17 "errors"
18 "math"
19 "sync/atomic"
20
21 dto "github.com/prometheus/client_model/go"
22)
23
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.
28//
29// A Counter is typically used to count requests served, tasks completed, errors
30// occurred, etc.
31//
32// To create Counter instances, use NewCounter.
33type Counter interface {
34 Metric
35 Collector
36
37 // Inc increments the counter by 1. Use Add to increment it by arbitrary
38 // non-negative values.
39 Inc()
40 // Add adds the given value to the counter. It panics if the value is <
41 // 0.
42 Add(float64)
43}
44
45// CounterOpts is an alias for Opts. See there for doc comments.
46type CounterOpts Opts
47
48// NewCounter creates a new Counter based on the provided CounterOpts.
49//
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.
57func NewCounter(opts CounterOpts) Counter {
58 desc := NewDesc(
59 BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
60 opts.Help,
61 nil,
62 opts.ConstLabels,
63 )
64 result := &counter{desc: desc, labelPairs: desc.constLabelPairs}
65 result.init(result) // Init self-collection.
66 return result
67}
68
69type counter struct {
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
74 valBits uint64
75 valInt uint64
76
77 selfCollector
78 desc *Desc
79
80 labelPairs []*dto.LabelPair
81}
82
83func (c *counter) Desc() *Desc {
84 return c.desc
85}
86
87func (c *counter) Add(v float64) {
88 if v < 0 {
89 panic(errors.New("counter cannot decrease in value"))
90 }
91 ival := uint64(v)
92 if float64(ival) == v {
93 atomic.AddUint64(&c.valInt, ival)
94 return
95 }
96
97 for {
98 oldBits := atomic.LoadUint64(&c.valBits)
99 newBits := math.Float64bits(math.Float64frombits(oldBits) + v)
100 if atomic.CompareAndSwapUint64(&c.valBits, oldBits, newBits) {
101 return
102 }
103 }
104}
105
106func (c *counter) Inc() {
107 atomic.AddUint64(&c.valInt, 1)
108}
109
110func (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)
114
115 return populateMetric(CounterValue, val, c.labelPairs, out)
116}
117
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.
123type CounterVec struct {
124 *metricVec
125}
126
127// NewCounterVec creates a new CounterVec based on the provided CounterOpts and
128// partitioned by the given label names.
129func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
130 desc := NewDesc(
131 BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
132 opts.Help,
133 labelNames,
134 opts.ConstLabels,
135 )
136 return &CounterVec{
137 metricVec: newMetricVec(desc, func(lvs ...string) Metric {
138 if len(lvs) != len(desc.variableLabels) {
139 panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs))
140 }
141 result := &counter{desc: desc, labelPairs: makeLabelPairs(desc, lvs)}
142 result.init(result) // Init self-collection.
143 return result
144 }),
145 }
146}
147
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.
151//
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.
155//
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.
161//
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).
164//
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.
171func (v *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) {
172 metric, err := v.metricVec.getMetricWithLabelValues(lvs...)
173 if metric != nil {
174 return metric.(Counter), err
175 }
176 return nil, err
177}
178
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.
184//
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).
187//
188// This method is used for the same purpose as
189// GetMetricWithLabelValues(...string). See there for pros and cons of the two
190// methods.
191func (v *CounterVec) GetMetricWith(labels Labels) (Counter, error) {
192 metric, err := v.metricVec.getMetricWith(labels)
193 if metric != nil {
194 return metric.(Counter), err
195 }
196 return nil, err
197}
198
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)
203func (v *CounterVec) WithLabelValues(lvs ...string) Counter {
204 c, err := v.GetMetricWithLabelValues(lvs...)
205 if err != nil {
206 panic(err)
207 }
208 return c
209}
210
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)
214func (v *CounterVec) With(labels Labels) Counter {
215 c, err := v.GetMetricWith(labels)
216 if err != nil {
217 panic(err)
218 }
219 return c
220}
221
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.
229//
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.
235func (v *CounterVec) CurryWith(labels Labels) (*CounterVec, error) {
236 vec, err := v.curryWith(labels)
237 if vec != nil {
238 return &CounterVec{vec}, err
239 }
240 return nil, err
241}
242
243// MustCurryWith works as CurryWith but panics where CurryWith would have
244// returned an error.
245func (v *CounterVec) MustCurryWith(labels Labels) *CounterVec {
246 vec, err := v.CurryWith(labels)
247 if err != nil {
248 panic(err)
249 }
250 return vec
251}
252
253// CounterFunc is a Counter whose value is determined at collect time by calling a
254// provided function.
255//
256// To create CounterFunc instances, use NewCounterFunc.
257type CounterFunc interface {
258 Metric
259 Collector
260}
261
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
269// not be checked.
270func NewCounterFunc(opts CounterOpts, function func() float64) CounterFunc {
271 return newValueFunc(NewDesc(
272 BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
273 opts.Help,
274 nil,
275 opts.ConstLabels,
276 ), CounterValue, function)
277}