123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- // Copyright 2014 The Prometheus Authors
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package prometheus
- import (
- "math"
- "sync/atomic"
- "time"
- dto "github.com/prometheus/client_model/go"
- )
- // Gauge is a Metric that represents a single numerical value that can
- // arbitrarily go up and down.
- //
- // A Gauge is typically used for measured values like temperatures or current
- // memory usage, but also "counts" that can go up and down, like the number of
- // running goroutines.
- //
- // To create Gauge instances, use NewGauge.
- type Gauge interface {
- Metric
- Collector
- // Set sets the Gauge to an arbitrary value.
- Set(float64)
- // Inc increments the Gauge by 1. Use Add to increment it by arbitrary
- // values.
- Inc()
- // Dec decrements the Gauge by 1. Use Sub to decrement it by arbitrary
- // values.
- Dec()
- // Add adds the given value to the Gauge. (The value can be negative,
- // resulting in a decrease of the Gauge.)
- Add(float64)
- // Sub subtracts the given value from the Gauge. (The value can be
- // negative, resulting in an increase of the Gauge.)
- Sub(float64)
- // SetToCurrentTime sets the Gauge to the current Unix time in seconds.
- SetToCurrentTime()
- }
- // GaugeOpts is an alias for Opts. See there for doc comments.
- type GaugeOpts Opts
- // NewGauge creates a new Gauge based on the provided GaugeOpts.
- //
- // The returned implementation is optimized for a fast Set method. If you have a
- // choice for managing the value of a Gauge via Set vs. Inc/Dec/Add/Sub, pick
- // the former. For example, the Inc method of the returned Gauge is slower than
- // the Inc method of a Counter returned by NewCounter. This matches the typical
- // scenarios for Gauges and Counters, where the former tends to be Set-heavy and
- // the latter Inc-heavy.
- func NewGauge(opts GaugeOpts) Gauge {
- desc := NewDesc(
- BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
- opts.Help,
- nil,
- opts.ConstLabels,
- )
- result := &gauge{desc: desc, labelPairs: desc.constLabelPairs}
- result.init(result) // Init self-collection.
- return result
- }
- type gauge struct {
- // valBits contains the bits of the represented float64 value. It has
- // to go first in the struct to guarantee alignment for atomic
- // operations. http://golang.org/pkg/sync/atomic/#pkg-note-BUG
- valBits uint64
- selfCollector
- desc *Desc
- labelPairs []*dto.LabelPair
- }
- func (g *gauge) Desc() *Desc {
- return g.desc
- }
- func (g *gauge) Set(val float64) {
- atomic.StoreUint64(&g.valBits, math.Float64bits(val))
- }
- func (g *gauge) SetToCurrentTime() {
- g.Set(float64(time.Now().UnixNano()) / 1e9)
- }
- func (g *gauge) Inc() {
- g.Add(1)
- }
- func (g *gauge) Dec() {
- g.Add(-1)
- }
- func (g *gauge) Add(val float64) {
- for {
- oldBits := atomic.LoadUint64(&g.valBits)
- newBits := math.Float64bits(math.Float64frombits(oldBits) + val)
- if atomic.CompareAndSwapUint64(&g.valBits, oldBits, newBits) {
- return
- }
- }
- }
- func (g *gauge) Sub(val float64) {
- g.Add(val * -1)
- }
- func (g *gauge) Write(out *dto.Metric) error {
- val := math.Float64frombits(atomic.LoadUint64(&g.valBits))
- return populateMetric(GaugeValue, val, g.labelPairs, nil, out)
- }
- // GaugeVec is a Collector that bundles a set of Gauges that all share the same
- // Desc, but have different values for their variable labels. This is used if
- // you want to count the same thing partitioned by various dimensions
- // (e.g. number of operations queued, partitioned by user and operation
- // type). Create instances with NewGaugeVec.
- type GaugeVec struct {
- *MetricVec
- }
- // NewGaugeVec creates a new GaugeVec based on the provided GaugeOpts and
- // partitioned by the given label names.
- func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec {
- desc := NewDesc(
- BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
- opts.Help,
- labelNames,
- opts.ConstLabels,
- )
- return &GaugeVec{
- MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
- if len(lvs) != len(desc.variableLabels) {
- panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs))
- }
- result := &gauge{desc: desc, labelPairs: MakeLabelPairs(desc, lvs)}
- result.init(result) // Init self-collection.
- return result
- }),
- }
- }
- // GetMetricWithLabelValues returns the Gauge for the given slice of label
- // values (same order as the variable labels in Desc). If that combination of
- // label values is accessed for the first time, a new Gauge is created.
- //
- // It is possible to call this method without using the returned Gauge to only
- // create the new Gauge but leave it at its starting value 0. See also the
- // SummaryVec example.
- //
- // Keeping the Gauge for later use is possible (and should be considered if
- // performance is critical), but keep in mind that Reset, DeleteLabelValues and
- // Delete can be used to delete the Gauge from the GaugeVec. In that case, the
- // Gauge will still exist, but it will not be exported anymore, even if a
- // Gauge with the same label values is created later. See also the CounterVec
- // example.
- //
- // An error is returned if the number of label values is not the same as the
- // number of variable labels in Desc (minus any curried labels).
- //
- // Note that for more than one label value, this method is prone to mistakes
- // caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
- // an alternative to avoid that type of mistake. For higher label numbers, the
- // latter has a much more readable (albeit more verbose) syntax, but it comes
- // with a performance overhead (for creating and processing the Labels map).
- func (v *GaugeVec) GetMetricWithLabelValues(lvs ...string) (Gauge, error) {
- metric, err := v.MetricVec.GetMetricWithLabelValues(lvs...)
- if metric != nil {
- return metric.(Gauge), err
- }
- return nil, err
- }
- // GetMetricWith returns the Gauge for the given Labels map (the label names
- // must match those of the variable labels in Desc). If that label map is
- // accessed for the first time, a new Gauge is created. Implications of
- // creating a Gauge without using it and keeping the Gauge for later use are
- // the same as for GetMetricWithLabelValues.
- //
- // An error is returned if the number and names of the Labels are inconsistent
- // with those of the variable labels in Desc (minus any curried labels).
- //
- // This method is used for the same purpose as
- // GetMetricWithLabelValues(...string). See there for pros and cons of the two
- // methods.
- func (v *GaugeVec) GetMetricWith(labels Labels) (Gauge, error) {
- metric, err := v.MetricVec.GetMetricWith(labels)
- if metric != nil {
- return metric.(Gauge), err
- }
- return nil, err
- }
- // WithLabelValues works as GetMetricWithLabelValues, but panics where
- // GetMetricWithLabelValues would have returned an error. Not returning an
- // error allows shortcuts like
- // myVec.WithLabelValues("404", "GET").Add(42)
- func (v *GaugeVec) WithLabelValues(lvs ...string) Gauge {
- g, err := v.GetMetricWithLabelValues(lvs...)
- if err != nil {
- panic(err)
- }
- return g
- }
- // With works as GetMetricWith, but panics where GetMetricWithLabels would have
- // returned an error. Not returning an error allows shortcuts like
- // myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Add(42)
- func (v *GaugeVec) With(labels Labels) Gauge {
- g, err := v.GetMetricWith(labels)
- if err != nil {
- panic(err)
- }
- return g
- }
- // CurryWith returns a vector curried with the provided labels, i.e. the
- // returned vector has those labels pre-set for all labeled operations performed
- // on it. The cardinality of the curried vector is reduced accordingly. The
- // order of the remaining labels stays the same (just with the curried labels
- // taken out of the sequence – which is relevant for the
- // (GetMetric)WithLabelValues methods). It is possible to curry a curried
- // vector, but only with labels not yet used for currying before.
- //
- // The metrics contained in the GaugeVec are shared between the curried and
- // uncurried vectors. They are just accessed differently. Curried and uncurried
- // vectors behave identically in terms of collection. Only one must be
- // registered with a given registry (usually the uncurried version). The Reset
- // method deletes all metrics, even if called on a curried vector.
- func (v *GaugeVec) CurryWith(labels Labels) (*GaugeVec, error) {
- vec, err := v.MetricVec.CurryWith(labels)
- if vec != nil {
- return &GaugeVec{vec}, err
- }
- return nil, err
- }
- // MustCurryWith works as CurryWith but panics where CurryWith would have
- // returned an error.
- func (v *GaugeVec) MustCurryWith(labels Labels) *GaugeVec {
- vec, err := v.CurryWith(labels)
- if err != nil {
- panic(err)
- }
- return vec
- }
- // GaugeFunc is a Gauge whose value is determined at collect time by calling a
- // provided function.
- //
- // To create GaugeFunc instances, use NewGaugeFunc.
- type GaugeFunc interface {
- Metric
- Collector
- }
- // NewGaugeFunc creates a new GaugeFunc based on the provided GaugeOpts. The
- // value reported is determined by calling the given function from within the
- // Write method. Take into account that metric collection may happen
- // concurrently. Therefore, it must be safe to call the provided function
- // concurrently.
- //
- // NewGaugeFunc is a good way to create an “info” style metric with a constant
- // value of 1. Example:
- // https://github.com/prometheus/common/blob/8558a5b7db3c84fa38b4766966059a7bd5bfa2ee/version/info.go#L36-L56
- func NewGaugeFunc(opts GaugeOpts, function func() float64) GaugeFunc {
- return newValueFunc(NewDesc(
- BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
- opts.Help,
- nil,
- opts.ConstLabels,
- ), GaugeValue, function)
- }
|