Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / prometheus / client_golang / prometheus / value.go
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
14 package prometheus
15
16 import (
17         "errors"
18         "fmt"
19         "math"
20         "sort"
21         "sync/atomic"
22
23         dto "github.com/prometheus/client_model/go"
24
25         "github.com/golang/protobuf/proto"
26 )
27
28 // ValueType is an enumeration of metric types that represent a simple value.
29 type ValueType int
30
31 // Possible values for the ValueType enum.
32 const (
33         _ ValueType = iota
34         CounterValue
35         GaugeValue
36         UntypedValue
37 )
38
39 var errInconsistentCardinality = errors.New("inconsistent label cardinality")
40
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.
45 type value struct {
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
49         valBits uint64
50
51         SelfCollector
52
53         desc       *Desc
54         valType    ValueType
55         labelPairs []*dto.LabelPair
56 }
57
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)
64         }
65         result := &value{
66                 desc:       desc,
67                 valType:    valueType,
68                 valBits:    math.Float64bits(val),
69                 labelPairs: makeLabelPairs(desc, labelValues),
70         }
71         result.Init(result)
72         return result
73 }
74
75 func (v *value) Desc() *Desc {
76         return v.desc
77 }
78
79 func (v *value) Set(val float64) {
80         atomic.StoreUint64(&v.valBits, math.Float64bits(val))
81 }
82
83 func (v *value) Inc() {
84         v.Add(1)
85 }
86
87 func (v *value) Dec() {
88         v.Add(-1)
89 }
90
91 func (v *value) Add(val float64) {
92         for {
93                 oldBits := atomic.LoadUint64(&v.valBits)
94                 newBits := math.Float64bits(math.Float64frombits(oldBits) + val)
95                 if atomic.CompareAndSwapUint64(&v.valBits, oldBits, newBits) {
96                         return
97                 }
98         }
99 }
100
101 func (v *value) Sub(val float64) {
102         v.Add(val * -1)
103 }
104
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)
108 }
109
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
114 // UntypedFunc.
115 type valueFunc struct {
116         SelfCollector
117
118         desc       *Desc
119         valType    ValueType
120         function   func() float64
121         labelPairs []*dto.LabelPair
122 }
123
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{
132                 desc:       desc,
133                 valType:    valueType,
134                 function:   function,
135                 labelPairs: makeLabelPairs(desc, nil),
136         }
137         result.Init(result)
138         return result
139 }
140
141 func (v *valueFunc) Desc() *Desc {
142         return v.desc
143 }
144
145 func (v *valueFunc) Write(out *dto.Metric) error {
146         return populateMetric(v.valType, v.function(), v.labelPairs, out)
147 }
148
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
158         }
159         return &constMetric{
160                 desc:       desc,
161                 valType:    valueType,
162                 val:        value,
163                 labelPairs: makeLabelPairs(desc, labelValues),
164         }, nil
165 }
166
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...)
171         if err != nil {
172                 panic(err)
173         }
174         return m
175 }
176
177 type constMetric struct {
178         desc       *Desc
179         valType    ValueType
180         val        float64
181         labelPairs []*dto.LabelPair
182 }
183
184 func (m *constMetric) Desc() *Desc {
185         return m.desc
186 }
187
188 func (m *constMetric) Write(out *dto.Metric) error {
189         return populateMetric(m.valType, m.val, m.labelPairs, out)
190 }
191
192 func populateMetric(
193         t ValueType,
194         v float64,
195         labelPairs []*dto.LabelPair,
196         m *dto.Metric,
197 ) error {
198         m.Label = labelPairs
199         switch t {
200         case CounterValue:
201                 m.Counter = &dto.Counter{Value: proto.Float64(v)}
202         case GaugeValue:
203                 m.Gauge = &dto.Gauge{Value: proto.Float64(v)}
204         case UntypedValue:
205                 m.Untyped = &dto.Untyped{Value: proto.Float64(v)}
206         default:
207                 return fmt.Errorf("encountered unknown type %v", t)
208         }
209         return nil
210 }
211
212 func makeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair {
213         totalLen := len(desc.variableLabels) + len(desc.constLabelPairs)
214         if totalLen == 0 {
215                 // Super fast path.
216                 return nil
217         }
218         if len(desc.variableLabels) == 0 {
219                 // Moderately fast path.
220                 return desc.constLabelPairs
221         }
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]),
227                 })
228         }
229         for _, lp := range desc.constLabelPairs {
230                 labelPairs = append(labelPairs, lp)
231         }
232         sort.Sort(LabelPairSorter(labelPairs))
233         return labelPairs
234 }