blob: 6eda08a7395a1b96c9d762f816343ee069feae56 [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001// 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
14package model
15
16import (
17 "encoding/json"
18 "fmt"
19 "sort"
20 "strings"
21)
22
23// A LabelSet is a collection of LabelName and LabelValue pairs. The LabelSet
24// may be fully-qualified down to the point where it may resolve to a single
25// Metric in the data store or not. All operations that occur within the realm
26// of a LabelSet can emit a vector of Metric entities to which the LabelSet may
27// match.
28type LabelSet map[LabelName]LabelValue
29
30// Validate checks whether all names and values in the label set
31// are valid.
32func (ls LabelSet) Validate() error {
33 for ln, lv := range ls {
34 if !ln.IsValid() {
35 return fmt.Errorf("invalid name %q", ln)
36 }
37 if !lv.IsValid() {
38 return fmt.Errorf("invalid value %q", lv)
39 }
40 }
41 return nil
42}
43
44// Equal returns true iff both label sets have exactly the same key/value pairs.
45func (ls LabelSet) Equal(o LabelSet) bool {
46 if len(ls) != len(o) {
47 return false
48 }
49 for ln, lv := range ls {
50 olv, ok := o[ln]
51 if !ok {
52 return false
53 }
54 if olv != lv {
55 return false
56 }
57 }
58 return true
59}
60
61// Before compares the metrics, using the following criteria:
62//
63// If m has fewer labels than o, it is before o. If it has more, it is not.
64//
65// If the number of labels is the same, the superset of all label names is
66// sorted alphanumerically. The first differing label pair found in that order
67// determines the outcome: If the label does not exist at all in m, then m is
68// before o, and vice versa. Otherwise the label value is compared
69// alphanumerically.
70//
71// If m and o are equal, the method returns false.
72func (ls LabelSet) Before(o LabelSet) bool {
73 if len(ls) < len(o) {
74 return true
75 }
76 if len(ls) > len(o) {
77 return false
78 }
79
80 lns := make(LabelNames, 0, len(ls)+len(o))
81 for ln := range ls {
82 lns = append(lns, ln)
83 }
84 for ln := range o {
85 lns = append(lns, ln)
86 }
87 // It's probably not worth it to de-dup lns.
88 sort.Sort(lns)
89 for _, ln := range lns {
90 mlv, ok := ls[ln]
91 if !ok {
92 return true
93 }
94 olv, ok := o[ln]
95 if !ok {
96 return false
97 }
98 if mlv < olv {
99 return true
100 }
101 if mlv > olv {
102 return false
103 }
104 }
105 return false
106}
107
108// Clone returns a copy of the label set.
109func (ls LabelSet) Clone() LabelSet {
110 lsn := make(LabelSet, len(ls))
111 for ln, lv := range ls {
112 lsn[ln] = lv
113 }
114 return lsn
115}
116
117// Merge is a helper function to non-destructively merge two label sets.
118func (l LabelSet) Merge(other LabelSet) LabelSet {
119 result := make(LabelSet, len(l))
120
121 for k, v := range l {
122 result[k] = v
123 }
124
125 for k, v := range other {
126 result[k] = v
127 }
128
129 return result
130}
131
132func (l LabelSet) String() string {
133 lstrs := make([]string, 0, len(l))
134 for l, v := range l {
135 lstrs = append(lstrs, fmt.Sprintf("%s=%q", l, v))
136 }
137
138 sort.Strings(lstrs)
139 return fmt.Sprintf("{%s}", strings.Join(lstrs, ", "))
140}
141
142// Fingerprint returns the LabelSet's fingerprint.
143func (ls LabelSet) Fingerprint() Fingerprint {
144 return labelSetToFingerprint(ls)
145}
146
147// FastFingerprint returns the LabelSet's Fingerprint calculated by a faster hashing
148// algorithm, which is, however, more susceptible to hash collisions.
149func (ls LabelSet) FastFingerprint() Fingerprint {
150 return labelSetToFastFingerprint(ls)
151}
152
153// UnmarshalJSON implements the json.Unmarshaler interface.
154func (l *LabelSet) UnmarshalJSON(b []byte) error {
155 var m map[LabelName]LabelValue
156 if err := json.Unmarshal(b, &m); err != nil {
157 return err
158 }
159 // encoding/json only unmarshals maps of the form map[string]T. It treats
160 // LabelName as a string and does not call its UnmarshalJSON method.
161 // Thus, we have to replicate the behavior here.
162 for ln := range m {
163 if !ln.IsValid() {
164 return fmt.Errorf("%q is not a valid label name", ln)
165 }
166 }
167 *l = LabelSet(m)
168 return nil
169}