github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/prometheus/common/model/labelset.go (about) 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 "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. 28 type LabelSet map[LabelName]LabelValue 29 30 // Validate checks whether all names and values in the label set 31 // are valid. 32 func (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. 45 func (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. 72 func (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. 109 func (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. 118 func (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 132 func (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. 143 func (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. 149 func (ls LabelSet) FastFingerprint() Fingerprint { 150 return labelSetToFastFingerprint(ls) 151 } 152 153 // UnmarshalJSON implements the json.Unmarshaler interface. 154 func (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 }