1 | // Copyright 2013 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 model
|
---|
15 |
|
---|
16 | import (
|
---|
17 | "fmt"
|
---|
18 | "regexp"
|
---|
19 | "sort"
|
---|
20 | "strings"
|
---|
21 | )
|
---|
22 |
|
---|
23 | var (
|
---|
24 | // MetricNameRE is a regular expression matching valid metric
|
---|
25 | // names. Note that the IsValidMetricName function performs the same
|
---|
26 | // check but faster than a match with this regular expression.
|
---|
27 | MetricNameRE = regexp.MustCompile(`^[a-zA-Z_:][a-zA-Z0-9_:]*$`)
|
---|
28 | )
|
---|
29 |
|
---|
30 | // A Metric is similar to a LabelSet, but the key difference is that a Metric is
|
---|
31 | // a singleton and refers to one and only one stream of samples.
|
---|
32 | type Metric LabelSet
|
---|
33 |
|
---|
34 | // Equal compares the metrics.
|
---|
35 | func (m Metric) Equal(o Metric) bool {
|
---|
36 | return LabelSet(m).Equal(LabelSet(o))
|
---|
37 | }
|
---|
38 |
|
---|
39 | // Before compares the metrics' underlying label sets.
|
---|
40 | func (m Metric) Before(o Metric) bool {
|
---|
41 | return LabelSet(m).Before(LabelSet(o))
|
---|
42 | }
|
---|
43 |
|
---|
44 | // Clone returns a copy of the Metric.
|
---|
45 | func (m Metric) Clone() Metric {
|
---|
46 | clone := make(Metric, len(m))
|
---|
47 | for k, v := range m {
|
---|
48 | clone[k] = v
|
---|
49 | }
|
---|
50 | return clone
|
---|
51 | }
|
---|
52 |
|
---|
53 | func (m Metric) String() string {
|
---|
54 | metricName, hasName := m[MetricNameLabel]
|
---|
55 | numLabels := len(m) - 1
|
---|
56 | if !hasName {
|
---|
57 | numLabels = len(m)
|
---|
58 | }
|
---|
59 | labelStrings := make([]string, 0, numLabels)
|
---|
60 | for label, value := range m {
|
---|
61 | if label != MetricNameLabel {
|
---|
62 | labelStrings = append(labelStrings, fmt.Sprintf("%s=%q", label, value))
|
---|
63 | }
|
---|
64 | }
|
---|
65 |
|
---|
66 | switch numLabels {
|
---|
67 | case 0:
|
---|
68 | if hasName {
|
---|
69 | return string(metricName)
|
---|
70 | }
|
---|
71 | return "{}"
|
---|
72 | default:
|
---|
73 | sort.Strings(labelStrings)
|
---|
74 | return fmt.Sprintf("%s{%s}", metricName, strings.Join(labelStrings, ", "))
|
---|
75 | }
|
---|
76 | }
|
---|
77 |
|
---|
78 | // Fingerprint returns a Metric's Fingerprint.
|
---|
79 | func (m Metric) Fingerprint() Fingerprint {
|
---|
80 | return LabelSet(m).Fingerprint()
|
---|
81 | }
|
---|
82 |
|
---|
83 | // FastFingerprint returns a Metric's Fingerprint calculated by a faster hashing
|
---|
84 | // algorithm, which is, however, more susceptible to hash collisions.
|
---|
85 | func (m Metric) FastFingerprint() Fingerprint {
|
---|
86 | return LabelSet(m).FastFingerprint()
|
---|
87 | }
|
---|
88 |
|
---|
89 | // IsValidMetricName returns true iff name matches the pattern of MetricNameRE.
|
---|
90 | // This function, however, does not use MetricNameRE for the check but a much
|
---|
91 | // faster hardcoded implementation.
|
---|
92 | func IsValidMetricName(n LabelValue) bool {
|
---|
93 | if len(n) == 0 {
|
---|
94 | return false
|
---|
95 | }
|
---|
96 | for i, b := range n {
|
---|
97 | if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || b == ':' || (b >= '0' && b <= '9' && i > 0)) {
|
---|
98 | return false
|
---|
99 | }
|
---|
100 | }
|
---|
101 | return true
|
---|
102 | }
|
---|