You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

312 lines
10 KiB

  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. "math"
  16. "sync/atomic"
  17. "time"
  18. dto "github.com/prometheus/client_model/go"
  19. )
  20. // Gauge is a Metric that represents a single numerical value that can
  21. // arbitrarily go up and down.
  22. //
  23. // A Gauge is typically used for measured values like temperatures or current
  24. // memory usage, but also "counts" that can go up and down, like the number of
  25. // running goroutines.
  26. //
  27. // To create Gauge instances, use NewGauge.
  28. type Gauge interface {
  29. Metric
  30. Collector
  31. // Set sets the Gauge to an arbitrary value.
  32. Set(float64)
  33. // Inc increments the Gauge by 1. Use Add to increment it by arbitrary
  34. // values.
  35. Inc()
  36. // Dec decrements the Gauge by 1. Use Sub to decrement it by arbitrary
  37. // values.
  38. Dec()
  39. // Add adds the given value to the Gauge. (The value can be negative,
  40. // resulting in a decrease of the Gauge.)
  41. Add(float64)
  42. // Sub subtracts the given value from the Gauge. (The value can be
  43. // negative, resulting in an increase of the Gauge.)
  44. Sub(float64)
  45. // SetToCurrentTime sets the Gauge to the current Unix time in seconds.
  46. SetToCurrentTime()
  47. }
  48. // GaugeOpts is an alias for Opts. See there for doc comments.
  49. type GaugeOpts Opts
  50. // GaugeVecOpts bundles the options to create a GaugeVec metric.
  51. // It is mandatory to set GaugeOpts, see there for mandatory fields. VariableLabels
  52. // is optional and can safely be left to its default value.
  53. type GaugeVecOpts struct {
  54. GaugeOpts
  55. // VariableLabels are used to partition the metric vector by the given set
  56. // of labels. Each label value will be constrained with the optional Contraint
  57. // function, if provided.
  58. VariableLabels ConstrainableLabels
  59. }
  60. // NewGauge creates a new Gauge based on the provided GaugeOpts.
  61. //
  62. // The returned implementation is optimized for a fast Set method. If you have a
  63. // choice for managing the value of a Gauge via Set vs. Inc/Dec/Add/Sub, pick
  64. // the former. For example, the Inc method of the returned Gauge is slower than
  65. // the Inc method of a Counter returned by NewCounter. This matches the typical
  66. // scenarios for Gauges and Counters, where the former tends to be Set-heavy and
  67. // the latter Inc-heavy.
  68. func NewGauge(opts GaugeOpts) Gauge {
  69. desc := NewDesc(
  70. BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
  71. opts.Help,
  72. nil,
  73. opts.ConstLabels,
  74. )
  75. result := &gauge{desc: desc, labelPairs: desc.constLabelPairs}
  76. result.init(result) // Init self-collection.
  77. return result
  78. }
  79. type gauge struct {
  80. // valBits contains the bits of the represented float64 value. It has
  81. // to go first in the struct to guarantee alignment for atomic
  82. // operations. http://golang.org/pkg/sync/atomic/#pkg-note-BUG
  83. valBits uint64
  84. selfCollector
  85. desc *Desc
  86. labelPairs []*dto.LabelPair
  87. }
  88. func (g *gauge) Desc() *Desc {
  89. return g.desc
  90. }
  91. func (g *gauge) Set(val float64) {
  92. atomic.StoreUint64(&g.valBits, math.Float64bits(val))
  93. }
  94. func (g *gauge) SetToCurrentTime() {
  95. g.Set(float64(time.Now().UnixNano()) / 1e9)
  96. }
  97. func (g *gauge) Inc() {
  98. g.Add(1)
  99. }
  100. func (g *gauge) Dec() {
  101. g.Add(-1)
  102. }
  103. func (g *gauge) Add(val float64) {
  104. for {
  105. oldBits := atomic.LoadUint64(&g.valBits)
  106. newBits := math.Float64bits(math.Float64frombits(oldBits) + val)
  107. if atomic.CompareAndSwapUint64(&g.valBits, oldBits, newBits) {
  108. return
  109. }
  110. }
  111. }
  112. func (g *gauge) Sub(val float64) {
  113. g.Add(val * -1)
  114. }
  115. func (g *gauge) Write(out *dto.Metric) error {
  116. val := math.Float64frombits(atomic.LoadUint64(&g.valBits))
  117. return populateMetric(GaugeValue, val, g.labelPairs, nil, out)
  118. }
  119. // GaugeVec is a Collector that bundles a set of Gauges that all share the same
  120. // Desc, but have different values for their variable labels. This is used if
  121. // you want to count the same thing partitioned by various dimensions
  122. // (e.g. number of operations queued, partitioned by user and operation
  123. // type). Create instances with NewGaugeVec.
  124. type GaugeVec struct {
  125. *MetricVec
  126. }
  127. // NewGaugeVec creates a new GaugeVec based on the provided GaugeOpts and
  128. // partitioned by the given label names.
  129. func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
  130. return V2.NewGaugeVec(GaugeVecOpts{
  131. GaugeOpts: opts,
  132. VariableLabels: UnconstrainedLabels(labelNames),
  133. })
  134. }
  135. // NewGaugeVec creates a new GaugeVec based on the provided GaugeVecOpts.
  136. func (v2) NewGaugeVec(opts GaugeVecOpts) *GaugeVec {
  137. desc := V2.NewDesc(
  138. BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
  139. opts.Help,
  140. opts.VariableLabels,
  141. opts.ConstLabels,
  142. )
  143. return &GaugeVec{
  144. MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
  145. if len(lvs) != len(desc.variableLabels) {
  146. panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels.labelNames(), lvs))
  147. }
  148. result := &gauge{desc: desc, labelPairs: MakeLabelPairs(desc, lvs)}
  149. result.init(result) // Init self-collection.
  150. return result
  151. }),
  152. }
  153. }
  154. // GetMetricWithLabelValues returns the Gauge for the given slice of label
  155. // values (same order as the variable labels in Desc). If that combination of
  156. // label values is accessed for the first time, a new Gauge is created.
  157. //
  158. // It is possible to call this method without using the returned Gauge to only
  159. // create the new Gauge but leave it at its starting value 0. See also the
  160. // SummaryVec example.
  161. //
  162. // Keeping the Gauge for later use is possible (and should be considered if
  163. // performance is critical), but keep in mind that Reset, DeleteLabelValues and
  164. // Delete can be used to delete the Gauge from the GaugeVec. In that case, the
  165. // Gauge will still exist, but it will not be exported anymore, even if a
  166. // Gauge with the same label values is created later. See also the CounterVec
  167. // example.
  168. //
  169. // An error is returned if the number of label values is not the same as the
  170. // number of variable labels in Desc (minus any curried labels).
  171. //
  172. // Note that for more than one label value, this method is prone to mistakes
  173. // caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
  174. // an alternative to avoid that type of mistake. For higher label numbers, the
  175. // latter has a much more readable (albeit more verbose) syntax, but it comes
  176. // with a performance overhead (for creating and processing the Labels map).
  177. func (v *GaugeVec) GetMetricWithLabelValues(lvs ...string) (Gauge, error) {
  178. metric, err := v.MetricVec.GetMetricWithLabelValues(lvs...)
  179. if metric != nil {
  180. return metric.(Gauge), err
  181. }
  182. return nil, err
  183. }
  184. // GetMetricWith returns the Gauge for the given Labels map (the label names
  185. // must match those of the variable labels in Desc). If that label map is
  186. // accessed for the first time, a new Gauge is created. Implications of
  187. // creating a Gauge without using it and keeping the Gauge for later use are
  188. // the same as for GetMetricWithLabelValues.
  189. //
  190. // An error is returned if the number and names of the Labels are inconsistent
  191. // with those of the variable labels in Desc (minus any curried labels).
  192. //
  193. // This method is used for the same purpose as
  194. // GetMetricWithLabelValues(...string). See there for pros and cons of the two
  195. // methods.
  196. func (v *GaugeVec) GetMetricWith(labels Labels) (Gauge, error) {
  197. metric, err := v.MetricVec.GetMetricWith(labels)
  198. if metric != nil {
  199. return metric.(Gauge), err
  200. }
  201. return nil, err
  202. }
  203. // WithLabelValues works as GetMetricWithLabelValues, but panics where
  204. // GetMetricWithLabelValues would have returned an error. Not returning an
  205. // error allows shortcuts like
  206. //
  207. // myVec.WithLabelValues("404", "GET").Add(42)
  208. func (v *GaugeVec) WithLabelValues(lvs ...string) Gauge {
  209. g, err := v.GetMetricWithLabelValues(lvs...)
  210. if err != nil {
  211. panic(err)
  212. }
  213. return g
  214. }
  215. // With works as GetMetricWith, but panics where GetMetricWithLabels would have
  216. // returned an error. Not returning an error allows shortcuts like
  217. //
  218. // myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Add(42)
  219. func (v *GaugeVec) With(labels Labels) Gauge {
  220. g, err := v.GetMetricWith(labels)
  221. if err != nil {
  222. panic(err)
  223. }
  224. return g
  225. }
  226. // CurryWith returns a vector curried with the provided labels, i.e. the
  227. // returned vector has those labels pre-set for all labeled operations performed
  228. // on it. The cardinality of the curried vector is reduced accordingly. The
  229. // order of the remaining labels stays the same (just with the curried labels
  230. // taken out of the sequence – which is relevant for the
  231. // (GetMetric)WithLabelValues methods). It is possible to curry a curried
  232. // vector, but only with labels not yet used for currying before.
  233. //
  234. // The metrics contained in the GaugeVec are shared between the curried and
  235. // uncurried vectors. They are just accessed differently. Curried and uncurried
  236. // vectors behave identically in terms of collection. Only one must be
  237. // registered with a given registry (usually the uncurried version). The Reset
  238. // method deletes all metrics, even if called on a curried vector.
  239. func (v *GaugeVec) CurryWith(labels Labels) (*GaugeVec, error) {
  240. vec, err := v.MetricVec.CurryWith(labels)
  241. if vec != nil {
  242. return &GaugeVec{vec}, err
  243. }
  244. return nil, err
  245. }
  246. // MustCurryWith works as CurryWith but panics where CurryWith would have
  247. // returned an error.
  248. func (v *GaugeVec) MustCurryWith(labels Labels) *GaugeVec {
  249. vec, err := v.CurryWith(labels)
  250. if err != nil {
  251. panic(err)
  252. }
  253. return vec
  254. }
  255. // GaugeFunc is a Gauge whose value is determined at collect time by calling a
  256. // provided function.
  257. //
  258. // To create GaugeFunc instances, use NewGaugeFunc.
  259. type GaugeFunc interface {
  260. Metric
  261. Collector
  262. }
  263. // NewGaugeFunc creates a new GaugeFunc based on the provided GaugeOpts. The
  264. // value reported is determined by calling the given function from within the
  265. // Write method. Take into account that metric collection may happen
  266. // concurrently. Therefore, it must be safe to call the provided function
  267. // concurrently.
  268. //
  269. // NewGaugeFunc is a good way to create an “info” style metric with a constant
  270. // value of 1. Example:
  271. // https://github.com/prometheus/common/blob/8558a5b7db3c84fa38b4766966059a7bd5bfa2ee/version/info.go#L36-L56
  272. func NewGaugeFunc(opts GaugeOpts, function func() float64) GaugeFunc {
  273. return newValueFunc(NewDesc(
  274. BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
  275. opts.Help,
  276. nil,
  277. opts.ConstLabels,
  278. ), GaugeValue, function)
  279. }