blob: c778711b8abb5466e867bf475bb6a48dafb95430 [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"
khenaidood948f772021-08-11 17:49:24 -040019 "time"
20 "unicode/utf8"
khenaidooab1f7bd2019-11-14 14:00:27 -050021
khenaidood948f772021-08-11 17:49:24 -040022 //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
khenaidooab1f7bd2019-11-14 14:00:27 -050023 "github.com/golang/protobuf/proto"
khenaidood948f772021-08-11 17:49:24 -040024 "github.com/golang/protobuf/ptypes"
khenaidooab1f7bd2019-11-14 14:00:27 -050025
26 dto "github.com/prometheus/client_model/go"
27)
28
29// ValueType is an enumeration of metric types that represent a simple value.
30type ValueType int
31
khenaidood948f772021-08-11 17:49:24 -040032// Possible values for the ValueType enum. Use UntypedValue to mark a metric
33// with an unknown type.
khenaidooab1f7bd2019-11-14 14:00:27 -050034const (
35 _ ValueType = iota
36 CounterValue
37 GaugeValue
38 UntypedValue
39)
40
41// valueFunc is a generic metric for simple values retrieved on collect time
42// from a function. It implements Metric and Collector. Its effective type is
43// determined by ValueType. This is a low-level building block used by the
44// library to back the implementations of CounterFunc, GaugeFunc, and
45// UntypedFunc.
46type valueFunc struct {
47 selfCollector
48
49 desc *Desc
50 valType ValueType
51 function func() float64
52 labelPairs []*dto.LabelPair
53}
54
55// newValueFunc returns a newly allocated valueFunc with the given Desc and
56// ValueType. The value reported is determined by calling the given function
57// from within the Write method. Take into account that metric collection may
58// happen concurrently. If that results in concurrent calls to Write, like in
59// the case where a valueFunc is directly registered with Prometheus, the
60// provided function must be concurrency-safe.
61func newValueFunc(desc *Desc, valueType ValueType, function func() float64) *valueFunc {
62 result := &valueFunc{
63 desc: desc,
64 valType: valueType,
65 function: function,
khenaidood948f772021-08-11 17:49:24 -040066 labelPairs: MakeLabelPairs(desc, nil),
khenaidooab1f7bd2019-11-14 14:00:27 -050067 }
68 result.init(result)
69 return result
70}
71
72func (v *valueFunc) Desc() *Desc {
73 return v.desc
74}
75
76func (v *valueFunc) Write(out *dto.Metric) error {
khenaidood948f772021-08-11 17:49:24 -040077 return populateMetric(v.valType, v.function(), v.labelPairs, nil, out)
khenaidooab1f7bd2019-11-14 14:00:27 -050078}
79
80// NewConstMetric returns a metric with one fixed value that cannot be
81// changed. Users of this package will not have much use for it in regular
82// operations. However, when implementing custom Collectors, it is useful as a
83// throw-away metric that is generated on the fly to send it to Prometheus in
84// the Collect method. NewConstMetric returns an error if the length of
85// labelValues is not consistent with the variable labels in Desc or if Desc is
86// invalid.
87func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) (Metric, error) {
88 if desc.err != nil {
89 return nil, desc.err
90 }
91 if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil {
92 return nil, err
93 }
94 return &constMetric{
95 desc: desc,
96 valType: valueType,
97 val: value,
khenaidood948f772021-08-11 17:49:24 -040098 labelPairs: MakeLabelPairs(desc, labelValues),
khenaidooab1f7bd2019-11-14 14:00:27 -050099 }, nil
100}
101
102// MustNewConstMetric is a version of NewConstMetric that panics where
103// NewConstMetric would have returned an error.
104func MustNewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) Metric {
105 m, err := NewConstMetric(desc, valueType, value, labelValues...)
106 if err != nil {
107 panic(err)
108 }
109 return m
110}
111
112type constMetric struct {
113 desc *Desc
114 valType ValueType
115 val float64
116 labelPairs []*dto.LabelPair
117}
118
119func (m *constMetric) Desc() *Desc {
120 return m.desc
121}
122
123func (m *constMetric) Write(out *dto.Metric) error {
khenaidood948f772021-08-11 17:49:24 -0400124 return populateMetric(m.valType, m.val, m.labelPairs, nil, out)
khenaidooab1f7bd2019-11-14 14:00:27 -0500125}
126
127func populateMetric(
128 t ValueType,
129 v float64,
130 labelPairs []*dto.LabelPair,
khenaidood948f772021-08-11 17:49:24 -0400131 e *dto.Exemplar,
khenaidooab1f7bd2019-11-14 14:00:27 -0500132 m *dto.Metric,
133) error {
134 m.Label = labelPairs
135 switch t {
136 case CounterValue:
khenaidood948f772021-08-11 17:49:24 -0400137 m.Counter = &dto.Counter{Value: proto.Float64(v), Exemplar: e}
khenaidooab1f7bd2019-11-14 14:00:27 -0500138 case GaugeValue:
139 m.Gauge = &dto.Gauge{Value: proto.Float64(v)}
140 case UntypedValue:
141 m.Untyped = &dto.Untyped{Value: proto.Float64(v)}
142 default:
143 return fmt.Errorf("encountered unknown type %v", t)
144 }
145 return nil
146}
147
khenaidood948f772021-08-11 17:49:24 -0400148// MakeLabelPairs is a helper function to create protobuf LabelPairs from the
149// variable and constant labels in the provided Desc. The values for the
150// variable labels are defined by the labelValues slice, which must be in the
151// same order as the corresponding variable labels in the Desc.
152//
153// This function is only needed for custom Metric implementations. See MetricVec
154// example.
155func MakeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair {
khenaidooab1f7bd2019-11-14 14:00:27 -0500156 totalLen := len(desc.variableLabels) + len(desc.constLabelPairs)
157 if totalLen == 0 {
158 // Super fast path.
159 return nil
160 }
161 if len(desc.variableLabels) == 0 {
162 // Moderately fast path.
163 return desc.constLabelPairs
164 }
165 labelPairs := make([]*dto.LabelPair, 0, totalLen)
166 for i, n := range desc.variableLabels {
167 labelPairs = append(labelPairs, &dto.LabelPair{
168 Name: proto.String(n),
169 Value: proto.String(labelValues[i]),
170 })
171 }
172 labelPairs = append(labelPairs, desc.constLabelPairs...)
173 sort.Sort(labelPairSorter(labelPairs))
174 return labelPairs
175}
khenaidood948f772021-08-11 17:49:24 -0400176
177// ExemplarMaxRunes is the max total number of runes allowed in exemplar labels.
178const ExemplarMaxRunes = 64
179
180// newExemplar creates a new dto.Exemplar from the provided values. An error is
181// returned if any of the label names or values are invalid or if the total
182// number of runes in the label names and values exceeds ExemplarMaxRunes.
183func newExemplar(value float64, ts time.Time, l Labels) (*dto.Exemplar, error) {
184 e := &dto.Exemplar{}
185 e.Value = proto.Float64(value)
186 tsProto, err := ptypes.TimestampProto(ts)
187 if err != nil {
188 return nil, err
189 }
190 e.Timestamp = tsProto
191 labelPairs := make([]*dto.LabelPair, 0, len(l))
192 var runes int
193 for name, value := range l {
194 if !checkLabelName(name) {
195 return nil, fmt.Errorf("exemplar label name %q is invalid", name)
196 }
197 runes += utf8.RuneCountInString(name)
198 if !utf8.ValidString(value) {
199 return nil, fmt.Errorf("exemplar label value %q is not valid UTF-8", value)
200 }
201 runes += utf8.RuneCountInString(value)
202 labelPairs = append(labelPairs, &dto.LabelPair{
203 Name: proto.String(name),
204 Value: proto.String(value),
205 })
206 }
207 if runes > ExemplarMaxRunes {
208 return nil, fmt.Errorf("exemplar labels have %d runes, exceeding the limit of %d", runes, ExemplarMaxRunes)
209 }
210 e.Label = labelPairs
211 return e, nil
212}