counter.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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. )
  17. // Counter is a Metric that represents a single numerical value that only ever
  18. // goes up. That implies that it cannot be used to count items whose number can
  19. // also go down, e.g. the number of currently running goroutines. Those
  20. // "counters" are represented by Gauges.
  21. //
  22. // A Counter is typically used to count requests served, tasks completed, errors
  23. // occurred, etc.
  24. //
  25. // To create Counter instances, use NewCounter.
  26. type Counter interface {
  27. Metric
  28. Collector
  29. // Inc increments the counter by 1. Use Add to increment it by arbitrary
  30. // non-negative values.
  31. Inc()
  32. // Add adds the given value to the counter. It panics if the value is <
  33. // 0.
  34. Add(float64)
  35. }
  36. // CounterOpts is an alias for Opts. See there for doc comments.
  37. type CounterOpts Opts
  38. // NewCounter creates a new Counter based on the provided CounterOpts.
  39. func NewCounter(opts CounterOpts) Counter {
  40. desc := NewDesc(
  41. BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
  42. opts.Help,
  43. nil,
  44. opts.ConstLabels,
  45. )
  46. result := &counter{value: value{desc: desc, valType: CounterValue, labelPairs: desc.constLabelPairs}}
  47. result.init(result) // Init self-collection.
  48. return result
  49. }
  50. type counter struct {
  51. value
  52. }
  53. func (c *counter) Add(v float64) {
  54. if v < 0 {
  55. panic(errors.New("counter cannot decrease in value"))
  56. }
  57. c.value.Add(v)
  58. }
  59. // CounterVec is a Collector that bundles a set of Counters that all share the
  60. // same Desc, but have different values for their variable labels. This is used
  61. // if you want to count the same thing partitioned by various dimensions
  62. // (e.g. number of HTTP requests, partitioned by response code and
  63. // method). Create instances with NewCounterVec.
  64. type CounterVec struct {
  65. *metricVec
  66. }
  67. // NewCounterVec creates a new CounterVec based on the provided CounterOpts and
  68. // partitioned by the given label names.
  69. func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
  70. desc := NewDesc(
  71. BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
  72. opts.Help,
  73. labelNames,
  74. opts.ConstLabels,
  75. )
  76. return &CounterVec{
  77. metricVec: newMetricVec(desc, func(lvs ...string) Metric {
  78. result := &counter{value: value{
  79. desc: desc,
  80. valType: CounterValue,
  81. labelPairs: makeLabelPairs(desc, lvs),
  82. }}
  83. result.init(result) // Init self-collection.
  84. return result
  85. }),
  86. }
  87. }
  88. // GetMetricWithLabelValues returns the Counter for the given slice of label
  89. // values (same order as the VariableLabels in Desc). If that combination of
  90. // label values is accessed for the first time, a new Counter is created.
  91. //
  92. // It is possible to call this method without using the returned Counter to only
  93. // create the new Counter but leave it at its starting value 0. See also the
  94. // SummaryVec example.
  95. //
  96. // Keeping the Counter for later use is possible (and should be considered if
  97. // performance is critical), but keep in mind that Reset, DeleteLabelValues and
  98. // Delete can be used to delete the Counter from the CounterVec. In that case,
  99. // the Counter will still exist, but it will not be exported anymore, even if a
  100. // Counter with the same label values is created later.
  101. //
  102. // An error is returned if the number of label values is not the same as the
  103. // number of VariableLabels in Desc.
  104. //
  105. // Note that for more than one label value, this method is prone to mistakes
  106. // caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
  107. // an alternative to avoid that type of mistake. For higher label numbers, the
  108. // latter has a much more readable (albeit more verbose) syntax, but it comes
  109. // with a performance overhead (for creating and processing the Labels map).
  110. // See also the GaugeVec example.
  111. func (m *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) {
  112. metric, err := m.metricVec.getMetricWithLabelValues(lvs...)
  113. if metric != nil {
  114. return metric.(Counter), err
  115. }
  116. return nil, err
  117. }
  118. // GetMetricWith returns the Counter for the given Labels map (the label names
  119. // must match those of the VariableLabels in Desc). If that label map is
  120. // accessed for the first time, a new Counter is created. Implications of
  121. // creating a Counter without using it and keeping the Counter for later use are
  122. // the same as for GetMetricWithLabelValues.
  123. //
  124. // An error is returned if the number and names of the Labels are inconsistent
  125. // with those of the VariableLabels in Desc.
  126. //
  127. // This method is used for the same purpose as
  128. // GetMetricWithLabelValues(...string). See there for pros and cons of the two
  129. // methods.
  130. func (m *CounterVec) GetMetricWith(labels Labels) (Counter, error) {
  131. metric, err := m.metricVec.getMetricWith(labels)
  132. if metric != nil {
  133. return metric.(Counter), err
  134. }
  135. return nil, err
  136. }
  137. // WithLabelValues works as GetMetricWithLabelValues, but panics where
  138. // GetMetricWithLabelValues would have returned an error. By not returning an
  139. // error, WithLabelValues allows shortcuts like
  140. // myVec.WithLabelValues("404", "GET").Add(42)
  141. func (m *CounterVec) WithLabelValues(lvs ...string) Counter {
  142. return m.metricVec.withLabelValues(lvs...).(Counter)
  143. }
  144. // With works as GetMetricWith, but panics where GetMetricWithLabels would have
  145. // returned an error. By not returning an error, With allows shortcuts like
  146. // myVec.With(Labels{"code": "404", "method": "GET"}).Add(42)
  147. func (m *CounterVec) With(labels Labels) Counter {
  148. return m.metricVec.with(labels).(Counter)
  149. }
  150. // CounterFunc is a Counter whose value is determined at collect time by calling a
  151. // provided function.
  152. //
  153. // To create CounterFunc instances, use NewCounterFunc.
  154. type CounterFunc interface {
  155. Metric
  156. Collector
  157. }
  158. // NewCounterFunc creates a new CounterFunc based on the provided
  159. // CounterOpts. The value reported is determined by calling the given function
  160. // from within the Write method. Take into account that metric collection may
  161. // happen concurrently. If that results in concurrent calls to Write, like in
  162. // the case where a CounterFunc is directly registered with Prometheus, the
  163. // provided function must be concurrency-safe. The function should also honor
  164. // the contract for a Counter (values only go up, not down), but compliance will
  165. // not be checked.
  166. func NewCounterFunc(opts CounterOpts, function func() float64) CounterFunc {
  167. return newValueFunc(NewDesc(
  168. BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
  169. opts.Help,
  170. nil,
  171. opts.ConstLabels,
  172. ), CounterValue, function)
  173. }