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
6 // http://www.apache.org/licenses/LICENSE-2.0
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.
23 dto "github.com/prometheus/client_model/go"
25 "github.com/golang/protobuf/proto"
28 // ValueType is an enumeration of metric types that represent a simple value.
31 // Possible values for the ValueType enum.
39 var errInconsistentCardinality = errors.New("inconsistent label cardinality")
41 // value is a generic metric for simple values. It implements Metric, Collector,
42 // Counter, Gauge, and Untyped. Its effective type is determined by
43 // ValueType. This is a low-level building block used by the library to back the
44 // implementations of Counter, Gauge, and Untyped.
46 // valBits containst the bits of the represented float64 value. It has
47 // to go first in the struct to guarantee alignment for atomic
48 // operations. http://golang.org/pkg/sync/atomic/#pkg-note-BUG
55 labelPairs []*dto.LabelPair
58 // newValue returns a newly allocated value with the given Desc, ValueType,
59 // sample value and label values. It panics if the number of label
60 // values is different from the number of variable labels in Desc.
61 func newValue(desc *Desc, valueType ValueType, val float64, labelValues ...string) *value {
62 if len(labelValues) != len(desc.variableLabels) {
63 panic(errInconsistentCardinality)
68 valBits: math.Float64bits(val),
69 labelPairs: makeLabelPairs(desc, labelValues),
75 func (v *value) Desc() *Desc {
79 func (v *value) Set(val float64) {
80 atomic.StoreUint64(&v.valBits, math.Float64bits(val))
83 func (v *value) Inc() {
87 func (v *value) Dec() {
91 func (v *value) Add(val float64) {
93 oldBits := atomic.LoadUint64(&v.valBits)
94 newBits := math.Float64bits(math.Float64frombits(oldBits) + val)
95 if atomic.CompareAndSwapUint64(&v.valBits, oldBits, newBits) {
101 func (v *value) Sub(val float64) {
105 func (v *value) Write(out *dto.Metric) error {
106 val := math.Float64frombits(atomic.LoadUint64(&v.valBits))
107 return populateMetric(v.valType, val, v.labelPairs, out)
110 // valueFunc is a generic metric for simple values retrieved on collect time
111 // from a function. It implements Metric and Collector. Its effective type is
112 // determined by ValueType. This is a low-level building block used by the
113 // library to back the implementations of CounterFunc, GaugeFunc, and
115 type valueFunc struct {
120 function func() float64
121 labelPairs []*dto.LabelPair
124 // newValueFunc returns a newly allocated valueFunc with the given Desc and
125 // ValueType. The value reported is determined by calling the given function
126 // from within the Write method. Take into account that metric collection may
127 // happen concurrently. If that results in concurrent calls to Write, like in
128 // the case where a valueFunc is directly registered with Prometheus, the
129 // provided function must be concurrency-safe.
130 func newValueFunc(desc *Desc, valueType ValueType, function func() float64) *valueFunc {
131 result := &valueFunc{
135 labelPairs: makeLabelPairs(desc, nil),
141 func (v *valueFunc) Desc() *Desc {
145 func (v *valueFunc) Write(out *dto.Metric) error {
146 return populateMetric(v.valType, v.function(), v.labelPairs, out)
149 // NewConstMetric returns a metric with one fixed value that cannot be
150 // changed. Users of this package will not have much use for it in regular
151 // operations. However, when implementing custom Collectors, it is useful as a
152 // throw-away metric that is generated on the fly to send it to Prometheus in
153 // the Collect method. NewConstMetric returns an error if the length of
154 // labelValues is not consistent with the variable labels in Desc.
155 func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) (Metric, error) {
156 if len(desc.variableLabels) != len(labelValues) {
157 return nil, errInconsistentCardinality
163 labelPairs: makeLabelPairs(desc, labelValues),
167 // MustNewConstMetric is a version of NewConstMetric that panics where
168 // NewConstMetric would have returned an error.
169 func MustNewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) Metric {
170 m, err := NewConstMetric(desc, valueType, value, labelValues...)
177 type constMetric struct {
181 labelPairs []*dto.LabelPair
184 func (m *constMetric) Desc() *Desc {
188 func (m *constMetric) Write(out *dto.Metric) error {
189 return populateMetric(m.valType, m.val, m.labelPairs, out)
195 labelPairs []*dto.LabelPair,
201 m.Counter = &dto.Counter{Value: proto.Float64(v)}
203 m.Gauge = &dto.Gauge{Value: proto.Float64(v)}
205 m.Untyped = &dto.Untyped{Value: proto.Float64(v)}
207 return fmt.Errorf("encountered unknown type %v", t)
212 func makeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair {
213 totalLen := len(desc.variableLabels) + len(desc.constLabelPairs)
218 if len(desc.variableLabels) == 0 {
219 // Moderately fast path.
220 return desc.constLabelPairs
222 labelPairs := make([]*dto.LabelPair, 0, totalLen)
223 for i, n := range desc.variableLabels {
224 labelPairs = append(labelPairs, &dto.LabelPair{
225 Name: proto.String(n),
226 Value: proto.String(labelValues[i]),
229 for _, lp := range desc.constLabelPairs {
230 labelPairs = append(labelPairs, lp)
232 sort.Sort(LabelPairSorter(labelPairs))