counter.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  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
  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. package prometheus
  14. import (
  15. "errors"
  16. "math"
  17. "sync/atomic"
  18. dto "github.com/prometheus/client_model/go"
  19. )
  20. // Counter is a Metric that represents a single numerical value that only ever
  21. // goes up. That implies that it cannot be used to count items whose number can
  22. // also go down, e.g. the number of currently running goroutines. Those
  23. // "counters" are represented by Gauges.
  24. //
  25. // A Counter is typically used to count requests served, tasks completed, errors
  26. // occurred, etc.
  27. //
  28. // To create Counter instances, use NewCounter.
  29. type Counter interface {
  30. Metric
  31. Collector
  32. // Inc increments the counter by 1. Use Add to increment it by arbitrary
  33. // non-negative values.
  34. Inc()
  35. // Add adds the given value to the counter. It panics if the value is <
  36. // 0.
  37. Add(float64)
  38. }
  39. // CounterOpts is an alias for Opts. See there for doc comments.
  40. type CounterOpts Opts
  41. // NewCounter creates a new Counter based on the provided CounterOpts.
  42. //
  43. // The returned implementation tracks the counter value in two separate
  44. // variables, a float64 and a uint64. The latter is used to track calls of the
  45. // Inc method and calls of the Add method with a value that can be represented
  46. // as a uint64. This allows atomic increments of the counter with optimal
  47. // performance. (It is common to have an Inc call in very hot execution paths.)
  48. // Both internal tracking values are added up in the Write method. This has to
  49. // be taken into account when it comes to precision and overflow behavior.
  50. func NewCounter(opts CounterOpts) Counter {
  51. desc := NewDesc(
  52. BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
  53. opts.Help,
  54. nil,
  55. opts.ConstLabels,
  56. )
  57. result := &counter{desc: desc, labelPairs: desc.constLabelPairs}
  58. result.init(result) // Init self-collection.
  59. return result
  60. }
  61. type counter struct {
  62. // valBits contains the bits of the represented float64 value, while
  63. // valInt stores values that are exact integers. Both have to go first
  64. // in the struct to guarantee alignment for atomic operations.
  65. // http://golang.org/pkg/sync/atomic/#pkg-note-BUG
  66. valBits uint64
  67. valInt uint64
  68. selfCollector
  69. desc *Desc
  70. labelPairs []*dto.LabelPair
  71. }
  72. func (c *counter) Desc() *Desc {
  73. return c.desc
  74. }
  75. func (c *counter) Add(v float64) {
  76. if v < 0 {
  77. panic(errors.New("counter cannot decrease in value"))
  78. }
  79. ival := uint64(v)
  80. if float64(ival) == v {
  81. atomic.AddUint64(&c.valInt, ival)
  82. return
  83. }
  84. for {
  85. oldBits := atomic.LoadUint64(&c.valBits)
  86. newBits := math.Float64bits(math.Float64frombits(oldBits) + v)
  87. if atomic.CompareAndSwapUint64(&c.valBits, oldBits, newBits) {
  88. return
  89. }
  90. }
  91. }
  92. func (c *counter) Inc() {
  93. atomic.AddUint64(&c.valInt, 1)
  94. }
  95. func (c *counter) Write(out *dto.Metric) error {
  96. fval := math.Float64frombits(atomic.LoadUint64(&c.valBits))
  97. ival := atomic.LoadUint64(&c.valInt)
  98. val := fval + float64(ival)
  99. return populateMetric(CounterValue, val, c.labelPairs, out)
  100. }
  101. // CounterVec is a Collector that bundles a set of Counters that all share the
  102. // same Desc, but have different values for their variable labels. This is used
  103. // if you want to count the same thing partitioned by various dimensions
  104. // (e.g. number of HTTP requests, partitioned by response code and
  105. // method). Create instances with NewCounterVec.
  106. type CounterVec struct {
  107. *metricVec
  108. }
  109. // NewCounterVec creates a new CounterVec based on the provided CounterOpts and
  110. // partitioned by the given label names.
  111. func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
  112. desc := NewDesc(
  113. BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
  114. opts.Help,
  115. labelNames,
  116. opts.ConstLabels,
  117. )
  118. return &CounterVec{
  119. metricVec: newMetricVec(desc, func(lvs ...string) Metric {
  120. if len(lvs) != len(desc.variableLabels) {
  121. panic(errInconsistentCardinality)
  122. }
  123. result := &counter{desc: desc, labelPairs: makeLabelPairs(desc, lvs)}
  124. result.init(result) // Init self-collection.
  125. return result
  126. }),
  127. }
  128. }
  129. // GetMetricWithLabelValues returns the Counter for the given slice of label
  130. // values (same order as the VariableLabels in Desc). If that combination of
  131. // label values is accessed for the first time, a new Counter is created.
  132. //
  133. // It is possible to call this method without using the returned Counter to only
  134. // create the new Counter but leave it at its starting value 0. See also the
  135. // SummaryVec example.
  136. //
  137. // Keeping the Counter for later use is possible (and should be considered if
  138. // performance is critical), but keep in mind that Reset, DeleteLabelValues and
  139. // Delete can be used to delete the Counter from the CounterVec. In that case,
  140. // the Counter will still exist, but it will not be exported anymore, even if a
  141. // Counter with the same label values is created later.
  142. //
  143. // An error is returned if the number of label values is not the same as the
  144. // number of VariableLabels in Desc (minus any curried labels).
  145. //
  146. // Note that for more than one label value, this method is prone to mistakes
  147. // caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
  148. // an alternative to avoid that type of mistake. For higher label numbers, the
  149. // latter has a much more readable (albeit more verbose) syntax, but it comes
  150. // with a performance overhead (for creating and processing the Labels map).
  151. // See also the GaugeVec example.
  152. func (v *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) {
  153. metric, err := v.metricVec.getMetricWithLabelValues(lvs...)
  154. if metric != nil {
  155. return metric.(Counter), err
  156. }
  157. return nil, err
  158. }
  159. // GetMetricWith returns the Counter for the given Labels map (the label names
  160. // must match those of the VariableLabels in Desc). If that label map is
  161. // accessed for the first time, a new Counter is created. Implications of
  162. // creating a Counter without using it and keeping the Counter for later use are
  163. // the same as for GetMetricWithLabelValues.
  164. //
  165. // An error is returned if the number and names of the Labels are inconsistent
  166. // with those of the VariableLabels in Desc (minus any curried labels).
  167. //
  168. // This method is used for the same purpose as
  169. // GetMetricWithLabelValues(...string). See there for pros and cons of the two
  170. // methods.
  171. func (v *CounterVec) GetMetricWith(labels Labels) (Counter, error) {
  172. metric, err := v.metricVec.getMetricWith(labels)
  173. if metric != nil {
  174. return metric.(Counter), err
  175. }
  176. return nil, err
  177. }
  178. // WithLabelValues works as GetMetricWithLabelValues, but panics where
  179. // GetMetricWithLabelValues would have returned an error. Not returning an
  180. // error allows shortcuts like
  181. // myVec.WithLabelValues("404", "GET").Add(42)
  182. func (v *CounterVec) WithLabelValues(lvs ...string) Counter {
  183. c, err := v.GetMetricWithLabelValues(lvs...)
  184. if err != nil {
  185. panic(err)
  186. }
  187. return c
  188. }
  189. // With works as GetMetricWith, but panics where GetMetricWithLabels would have
  190. // returned an error. Not returning an error allows shortcuts like
  191. // myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Add(42)
  192. func (v *CounterVec) With(labels Labels) Counter {
  193. c, err := v.GetMetricWith(labels)
  194. if err != nil {
  195. panic(err)
  196. }
  197. return c
  198. }
  199. // CurryWith returns a vector curried with the provided labels, i.e. the
  200. // returned vector has those labels pre-set for all labeled operations performed
  201. // on it. The cardinality of the curried vector is reduced accordingly. The
  202. // order of the remaining labels stays the same (just with the curried labels
  203. // taken out of the sequence – which is relevant for the
  204. // (GetMetric)WithLabelValues methods). It is possible to curry a curried
  205. // vector, but only with labels not yet used for currying before.
  206. //
  207. // The metrics contained in the CounterVec are shared between the curried and
  208. // uncurried vectors. They are just accessed differently. Curried and uncurried
  209. // vectors behave identically in terms of collection. Only one must be
  210. // registered with a given registry (usually the uncurried version). The Reset
  211. // method deletes all metrics, even if called on a curried vector.
  212. func (v *CounterVec) CurryWith(labels Labels) (*CounterVec, error) {
  213. vec, err := v.curryWith(labels)
  214. if vec != nil {
  215. return &CounterVec{vec}, err
  216. }
  217. return nil, err
  218. }
  219. // MustCurryWith works as CurryWith but panics where CurryWith would have
  220. // returned an error.
  221. func (v *CounterVec) MustCurryWith(labels Labels) *CounterVec {
  222. vec, err := v.CurryWith(labels)
  223. if err != nil {
  224. panic(err)
  225. }
  226. return vec
  227. }
  228. // CounterFunc is a Counter whose value is determined at collect time by calling a
  229. // provided function.
  230. //
  231. // To create CounterFunc instances, use NewCounterFunc.
  232. type CounterFunc interface {
  233. Metric
  234. Collector
  235. }
  236. // NewCounterFunc creates a new CounterFunc based on the provided
  237. // CounterOpts. The value reported is determined by calling the given function
  238. // from within the Write method. Take into account that metric collection may
  239. // happen concurrently. If that results in concurrent calls to Write, like in
  240. // the case where a CounterFunc is directly registered with Prometheus, the
  241. // provided function must be concurrency-safe. The function should also honor
  242. // the contract for a Counter (values only go up, not down), but compliance will
  243. // not be checked.
  244. func NewCounterFunc(opts CounterOpts, function func() float64) CounterFunc {
  245. return newValueFunc(NewDesc(
  246. BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
  247. opts.Help,
  248. nil,
  249. opts.ConstLabels,
  250. ), CounterValue, function)
  251. }