您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 

238 行
7.2 KiB

  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. package prometheus
  14. import (
  15. "fmt"
  16. "sort"
  17. "time"
  18. "unicode/utf8"
  19. //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
  20. "github.com/golang/protobuf/proto"
  21. "google.golang.org/protobuf/types/known/timestamppb"
  22. "github.com/prometheus/client_golang/prometheus/internal"
  23. dto "github.com/prometheus/client_model/go"
  24. )
  25. // ValueType is an enumeration of metric types that represent a simple value.
  26. type ValueType int
  27. // Possible values for the ValueType enum. Use UntypedValue to mark a metric
  28. // with an unknown type.
  29. const (
  30. _ ValueType = iota
  31. CounterValue
  32. GaugeValue
  33. UntypedValue
  34. )
  35. var (
  36. CounterMetricTypePtr = func() *dto.MetricType { d := dto.MetricType_COUNTER; return &d }()
  37. GaugeMetricTypePtr = func() *dto.MetricType { d := dto.MetricType_GAUGE; return &d }()
  38. UntypedMetricTypePtr = func() *dto.MetricType { d := dto.MetricType_UNTYPED; return &d }()
  39. )
  40. func (v ValueType) ToDTO() *dto.MetricType {
  41. switch v {
  42. case CounterValue:
  43. return CounterMetricTypePtr
  44. case GaugeValue:
  45. return GaugeMetricTypePtr
  46. default:
  47. return UntypedMetricTypePtr
  48. }
  49. }
  50. // valueFunc is a generic metric for simple values retrieved on collect time
  51. // from a function. It implements Metric and Collector. Its effective type is
  52. // determined by ValueType. This is a low-level building block used by the
  53. // library to back the implementations of CounterFunc, GaugeFunc, and
  54. // UntypedFunc.
  55. type valueFunc struct {
  56. selfCollector
  57. desc *Desc
  58. valType ValueType
  59. function func() float64
  60. labelPairs []*dto.LabelPair
  61. }
  62. // newValueFunc returns a newly allocated valueFunc with the given Desc and
  63. // ValueType. The value reported is determined by calling the given function
  64. // from within the Write method. Take into account that metric collection may
  65. // happen concurrently. If that results in concurrent calls to Write, like in
  66. // the case where a valueFunc is directly registered with Prometheus, the
  67. // provided function must be concurrency-safe.
  68. func newValueFunc(desc *Desc, valueType ValueType, function func() float64) *valueFunc {
  69. result := &valueFunc{
  70. desc: desc,
  71. valType: valueType,
  72. function: function,
  73. labelPairs: MakeLabelPairs(desc, nil),
  74. }
  75. result.init(result)
  76. return result
  77. }
  78. func (v *valueFunc) Desc() *Desc {
  79. return v.desc
  80. }
  81. func (v *valueFunc) Write(out *dto.Metric) error {
  82. return populateMetric(v.valType, v.function(), v.labelPairs, nil, out)
  83. }
  84. // NewConstMetric returns a metric with one fixed value that cannot be
  85. // changed. Users of this package will not have much use for it in regular
  86. // operations. However, when implementing custom Collectors, it is useful as a
  87. // throw-away metric that is generated on the fly to send it to Prometheus in
  88. // the Collect method. NewConstMetric returns an error if the length of
  89. // labelValues is not consistent with the variable labels in Desc or if Desc is
  90. // invalid.
  91. func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) (Metric, error) {
  92. if desc.err != nil {
  93. return nil, desc.err
  94. }
  95. if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil {
  96. return nil, err
  97. }
  98. metric := &dto.Metric{}
  99. if err := populateMetric(valueType, value, MakeLabelPairs(desc, labelValues), nil, metric); err != nil {
  100. return nil, err
  101. }
  102. return &constMetric{
  103. desc: desc,
  104. metric: metric,
  105. }, nil
  106. }
  107. // MustNewConstMetric is a version of NewConstMetric that panics where
  108. // NewConstMetric would have returned an error.
  109. func MustNewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues ...string) Metric {
  110. m, err := NewConstMetric(desc, valueType, value, labelValues...)
  111. if err != nil {
  112. panic(err)
  113. }
  114. return m
  115. }
  116. type constMetric struct {
  117. desc *Desc
  118. metric *dto.Metric
  119. }
  120. func (m *constMetric) Desc() *Desc {
  121. return m.desc
  122. }
  123. func (m *constMetric) Write(out *dto.Metric) error {
  124. out.Label = m.metric.Label
  125. out.Counter = m.metric.Counter
  126. out.Gauge = m.metric.Gauge
  127. out.Untyped = m.metric.Untyped
  128. return nil
  129. }
  130. func populateMetric(
  131. t ValueType,
  132. v float64,
  133. labelPairs []*dto.LabelPair,
  134. e *dto.Exemplar,
  135. m *dto.Metric,
  136. ) error {
  137. m.Label = labelPairs
  138. switch t {
  139. case CounterValue:
  140. m.Counter = &dto.Counter{Value: proto.Float64(v), Exemplar: e}
  141. case GaugeValue:
  142. m.Gauge = &dto.Gauge{Value: proto.Float64(v)}
  143. case UntypedValue:
  144. m.Untyped = &dto.Untyped{Value: proto.Float64(v)}
  145. default:
  146. return fmt.Errorf("encountered unknown type %v", t)
  147. }
  148. return nil
  149. }
  150. // MakeLabelPairs is a helper function to create protobuf LabelPairs from the
  151. // variable and constant labels in the provided Desc. The values for the
  152. // variable labels are defined by the labelValues slice, which must be in the
  153. // same order as the corresponding variable labels in the Desc.
  154. //
  155. // This function is only needed for custom Metric implementations. See MetricVec
  156. // example.
  157. func MakeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair {
  158. totalLen := len(desc.variableLabels) + len(desc.constLabelPairs)
  159. if totalLen == 0 {
  160. // Super fast path.
  161. return nil
  162. }
  163. if len(desc.variableLabels) == 0 {
  164. // Moderately fast path.
  165. return desc.constLabelPairs
  166. }
  167. labelPairs := make([]*dto.LabelPair, 0, totalLen)
  168. for i, n := range desc.variableLabels {
  169. labelPairs = append(labelPairs, &dto.LabelPair{
  170. Name: proto.String(n),
  171. Value: proto.String(labelValues[i]),
  172. })
  173. }
  174. labelPairs = append(labelPairs, desc.constLabelPairs...)
  175. sort.Sort(internal.LabelPairSorter(labelPairs))
  176. return labelPairs
  177. }
  178. // ExemplarMaxRunes is the max total number of runes allowed in exemplar labels.
  179. const ExemplarMaxRunes = 128
  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.
  183. func newExemplar(value float64, ts time.Time, l Labels) (*dto.Exemplar, error) {
  184. e := &dto.Exemplar{}
  185. e.Value = proto.Float64(value)
  186. tsProto := timestamppb.New(ts)
  187. if err := tsProto.CheckValid(); 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. }