counter.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  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. "sync/atomic"
  17. "math"
  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. // Value return value
  39. Value() float64
  40. // Lables return Lables
  41. Lables() []*dto.LabelPair
  42. }
  43. // CounterOpts is an alias for Opts. See there for doc comments.
  44. type CounterOpts Opts
  45. // NewCounter creates a new Counter based on the provided CounterOpts.
  46. func NewCounter(opts CounterOpts) Counter {
  47. desc := NewDesc(
  48. BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
  49. opts.Help,
  50. nil,
  51. opts.ConstLabels,
  52. )
  53. result := &counter{value: value{desc: desc, valType: CounterValue, labelPairs: desc.constLabelPairs}}
  54. result.init(result) // Init self-collection.
  55. return result
  56. }
  57. type counter struct {
  58. value
  59. }
  60. func (c *counter) Add(v float64) {
  61. if v < 0 {
  62. panic(errors.New("counter cannot decrease in value"))
  63. }
  64. c.value.Add(v)
  65. }
  66. func (c *counter) Value() float64 {
  67. return math.Float64frombits(atomic.LoadUint64(&c.value.valBits))
  68. }
  69. func (c *counter) Lables() []*dto.LabelPair {
  70. return c.labelPairs
  71. }
  72. // CounterVec is a Collector that bundles a set of Counters that all share the
  73. // same Desc, but have different values for their variable labels. This is used
  74. // if you want to count the same thing partitioned by various dimensions
  75. // (e.g. number of HTTP requests, partitioned by response code and
  76. // method). Create instances with NewCounterVec.
  77. //
  78. // CounterVec embeds MetricVec. See there for a full list of methods with
  79. // detailed documentation.
  80. type CounterVec struct {
  81. *MetricVec
  82. }
  83. // NewCounterVec creates a new CounterVec based on the provided CounterOpts and
  84. // partitioned by the given label names. At least one label name must be
  85. // provided.
  86. func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
  87. desc := NewDesc(
  88. BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
  89. opts.Help,
  90. labelNames,
  91. opts.ConstLabels,
  92. )
  93. return &CounterVec{
  94. MetricVec: newMetricVec(desc, func(lvs ...string) Metric {
  95. result := &counter{value: value{
  96. desc: desc,
  97. valType: CounterValue,
  98. labelPairs: makeLabelPairs(desc, lvs),
  99. }}
  100. result.init(result) // Init self-collection.
  101. return result
  102. }),
  103. }
  104. }
  105. // GetMetricWithLabelValues replaces the method of the same name in
  106. // MetricVec. The difference is that this method returns a Counter and not a
  107. // Metric so that no type conversion is required.
  108. func (m *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) {
  109. metric, err := m.MetricVec.GetMetricWithLabelValues(lvs...)
  110. if metric != nil {
  111. return metric.(Counter), err
  112. }
  113. return nil, err
  114. }
  115. // GetMetricWith replaces the method of the same name in MetricVec. The
  116. // difference is that this method returns a Counter and not a Metric so that no
  117. // type conversion is required.
  118. func (m *CounterVec) GetMetricWith(labels Labels) (Counter, error) {
  119. metric, err := m.MetricVec.GetMetricWith(labels)
  120. if metric != nil {
  121. return metric.(Counter), err
  122. }
  123. return nil, err
  124. }
  125. // WithLabelValues works as GetMetricWithLabelValues, but panics where
  126. // GetMetricWithLabelValues would have returned an error. By not returning an
  127. // error, WithLabelValues allows shortcuts like
  128. // myVec.WithLabelValues("404", "GET").Add(42)
  129. func (m *CounterVec) WithLabelValues(lvs ...string) Counter {
  130. return m.MetricVec.WithLabelValues(lvs...).(Counter)
  131. }
  132. // With works as GetMetricWith, but panics where GetMetricWithLabels would have
  133. // returned an error. By not returning an error, With allows shortcuts like
  134. // myVec.With(Labels{"code": "404", "method": "GET"}).Add(42)
  135. func (m *CounterVec) With(labels Labels) Counter {
  136. return m.MetricVec.With(labels).(Counter)
  137. }
  138. // CounterFunc is a Counter whose value is determined at collect time by calling a
  139. // provided function.
  140. //
  141. // To create CounterFunc instances, use NewCounterFunc.
  142. type CounterFunc interface {
  143. Metric
  144. Collector
  145. }
  146. // NewCounterFunc creates a new CounterFunc based on the provided
  147. // CounterOpts. The value reported is determined by calling the given function
  148. // from within the Write method. Take into account that metric collection may
  149. // happen concurrently. If that results in concurrent calls to Write, like in
  150. // the case where a CounterFunc is directly registered with Prometheus, the
  151. // provided function must be concurrency-safe. The function should also honor
  152. // the contract for a Counter (values only go up, not down), but compliance will
  153. // not be checked.
  154. func NewCounterFunc(opts CounterOpts, function func() float64) CounterFunc {
  155. return newValueFunc(NewDesc(
  156. BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
  157. opts.Help,
  158. nil,
  159. opts.ConstLabels,
  160. ), CounterValue, function)
  161. }