blob: eb248f10874350f3c3fdcced6a18d3c5a0fc62e3 [file] [log] [blame]
khenaidooab1f7bd2019-11-14 14:00:27 -05001// 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
14package prometheus
15
16import (
17 "fmt"
18 "sort"
19
20 "github.com/golang/protobuf/proto"
21
22 dto "github.com/prometheus/client_model/go"
23)
24
25// ValueType is an enumeration of metric types that represent a simple value.
26type ValueType int
27
28// Possible values for the ValueType enum.
29const (
30 _ ValueType = iota
31 CounterValue
32 GaugeValue
33 UntypedValue
34)
35
36// valueFunc is a generic metric for simple values retrieved on collect time
37// from a function. It implements Metric and Collector. Its effective type is
38// determined by ValueType. This is a low-level building block used by the
39// library to back the implementations of CounterFunc, GaugeFunc, and
40// UntypedFunc.
41type valueFunc struct {
42 selfCollector
43
44 desc *Desc
45 valType ValueType
46 function func() float64
47 labelPairs []*dto.LabelPair
48}
49
50// newValueFunc returns a newly allocated valueFunc with the given Desc and
51// ValueType. The value reported is determined by calling the given function
52// from within the Write method. Take into account that metric collection may
53// happen concurrently. If that results in concurrent calls to Write, like in
54// the case where a valueFunc is directly registered with Prometheus, the
55// provided function must be concurrency-safe.
56func newValueFunc(desc *Desc, valueType ValueType, function func() float64) *valueFunc {
57 result := &valueFunc{
58 desc: desc,
59 valType: valueType,
60 function: function,
61 labelPairs: makeLabelPairs(desc, nil),
62 }
63 result.init(result)
64 return result
65}
66
67func (v *valueFunc) Desc() *Desc {
68 return v.desc
69}
70
71func (v *valueFunc) Write(out *dto.Metric) error {
72 return populateMetric(v.valType, v.function(), v.labelPairs, out)
73}
74
75// NewConstMetric returns a metric with one fixed value that cannot be
76// changed. Users of this package will not have much use for it in regular
77// operations. However, when implementing custom Collectors, it is useful as a
78// throw-away metric that is generated on the fly to send it to Prometheus in
79// the Collect method. NewConstMetric returns an error if the length of
80// labelValues is not consistent with the variable labels in Desc or if Desc is
81// invalid.
82func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) (Metric, error) {
83 if desc.err != nil {
84 return nil, desc.err
85 }
86 if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil {
87 return nil, err
88 }
89 return &constMetric{
90 desc: desc,
91 valType: valueType,
92 val: value,
93 labelPairs: makeLabelPairs(desc, labelValues),
94 }, nil
95}
96
97// MustNewConstMetric is a version of NewConstMetric that panics where
98// NewConstMetric would have returned an error.
99func MustNewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) Metric {
100 m, err := NewConstMetric(desc, valueType, value, labelValues...)
101 if err != nil {
102 panic(err)
103 }
104 return m
105}
106
107type constMetric struct {
108 desc *Desc
109 valType ValueType
110 val float64
111 labelPairs []*dto.LabelPair
112}
113
114func (m *constMetric) Desc() *Desc {
115 return m.desc
116}
117
118func (m *constMetric) Write(out *dto.Metric) error {
119 return populateMetric(m.valType, m.val, m.labelPairs, out)
120}
121
122func populateMetric(
123 t ValueType,
124 v float64,
125 labelPairs []*dto.LabelPair,
126 m *dto.Metric,
127) error {
128 m.Label = labelPairs
129 switch t {
130 case CounterValue:
131 m.Counter = &dto.Counter{Value: proto.Float64(v)}
132 case GaugeValue:
133 m.Gauge = &dto.Gauge{Value: proto.Float64(v)}
134 case UntypedValue:
135 m.Untyped = &dto.Untyped{Value: proto.Float64(v)}
136 default:
137 return fmt.Errorf("encountered unknown type %v", t)
138 }
139 return nil
140}
141
142func makeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair {
143 totalLen := len(desc.variableLabels) + len(desc.constLabelPairs)
144 if totalLen == 0 {
145 // Super fast path.
146 return nil
147 }
148 if len(desc.variableLabels) == 0 {
149 // Moderately fast path.
150 return desc.constLabelPairs
151 }
152 labelPairs := make([]*dto.LabelPair, 0, totalLen)
153 for i, n := range desc.variableLabels {
154 labelPairs = append(labelPairs, &dto.LabelPair{
155 Name: proto.String(n),
156 Value: proto.String(labelValues[i]),
157 })
158 }
159 labelPairs = append(labelPairs, desc.constLabelPairs...)
160 sort.Sort(labelPairSorter(labelPairs))
161 return labelPairs
162}