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