github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/scrape/labels/labels.go (about) 1 // Copyright 2017 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 labels 15 16 import ( 17 "bytes" 18 "encoding/json" 19 "sort" 20 "strconv" 21 22 "github.com/cespare/xxhash/v2" 23 ) 24 25 // Well-known label names used by Prometheus components. 26 const ( 27 MetricName = "__name__" 28 AlertName = "alertname" 29 BucketLabel = "le" 30 InstanceName = "instance" 31 32 labelSep = '\xfe' 33 ) 34 35 var seps = []byte{'\xff'} 36 37 // Label is a key/value pair of strings. 38 type Label struct { 39 Name, Value string 40 } 41 42 // Labels is a sorted set of labels. Order has to be guaranteed upon 43 // instantiation. 44 type Labels []Label 45 46 func (ls Labels) Len() int { return len(ls) } 47 func (ls Labels) Swap(i, j int) { ls[i], ls[j] = ls[j], ls[i] } 48 func (ls Labels) Less(i, j int) bool { return ls[i].Name < ls[j].Name } 49 50 func (ls Labels) String() string { 51 var b bytes.Buffer 52 53 b.WriteByte('{') 54 for i, l := range ls { 55 if i > 0 { 56 b.WriteByte(',') 57 b.WriteByte(' ') 58 } 59 b.WriteString(l.Name) 60 b.WriteByte('=') 61 b.WriteString(strconv.Quote(l.Value)) 62 } 63 b.WriteByte('}') 64 return b.String() 65 } 66 67 // Bytes returns ls as a byte slice. 68 // It uses an byte invalid character as a separator and so should not be used for printing. 69 func (ls Labels) Bytes(buf []byte) []byte { 70 b := bytes.NewBuffer(buf[:0]) 71 b.WriteByte(labelSep) 72 for i, l := range ls { 73 if i > 0 { 74 b.WriteByte(seps[0]) 75 } 76 b.WriteString(l.Name) 77 b.WriteByte(seps[0]) 78 b.WriteString(l.Value) 79 } 80 return b.Bytes() 81 } 82 83 // MarshalJSON implements json.Marshaler. 84 func (ls Labels) MarshalJSON() ([]byte, error) { 85 return json.Marshal(ls.Map()) 86 } 87 88 // UnmarshalJSON implements json.Unmarshaler. 89 func (ls *Labels) UnmarshalJSON(b []byte) error { 90 var m map[string]string 91 92 if err := json.Unmarshal(b, &m); err != nil { 93 return err 94 } 95 96 *ls = FromMap(m) 97 return nil 98 } 99 100 // MarshalYAML implements yaml.Marshaler. 101 func (ls Labels) MarshalYAML() (interface{}, error) { 102 return ls.Map(), nil 103 } 104 105 // UnmarshalYAML implements yaml.Unmarshaler. 106 func (ls *Labels) UnmarshalYAML(unmarshal func(interface{}) error) error { 107 var m map[string]string 108 109 if err := unmarshal(&m); err != nil { 110 return err 111 } 112 113 *ls = FromMap(m) 114 return nil 115 } 116 117 // MatchLabels returns a subset of Labels that matches/does not match with the provided label names based on the 'on' boolean. 118 // If on is set to true, it returns the subset of labels that match with the provided label names and its inverse when 'on' is set to false. 119 func (ls Labels) MatchLabels(on bool, names ...string) Labels { 120 matchedLabels := Labels{} 121 122 nameSet := map[string]struct{}{} 123 for _, n := range names { 124 nameSet[n] = struct{}{} 125 } 126 127 for _, v := range ls { 128 if _, ok := nameSet[v.Name]; on == ok && (on || v.Name != MetricName) { 129 matchedLabels = append(matchedLabels, v) 130 } 131 } 132 133 return matchedLabels 134 } 135 136 // Hash returns a hash value for the label set. 137 func (ls Labels) Hash() uint64 { 138 // Use xxhash.Sum64(b) for fast path as it's faster. 139 b := make([]byte, 0, 1024) 140 for i, v := range ls { 141 if len(b)+len(v.Name)+len(v.Value)+2 >= cap(b) { 142 // If labels entry is 1KB+ do not allocate whole entry. 143 h := xxhash.New() 144 _, _ = h.Write(b) 145 for _, v := range ls[i:] { 146 _, _ = h.WriteString(v.Name) 147 _, _ = h.Write(seps) 148 _, _ = h.WriteString(v.Value) 149 _, _ = h.Write(seps) 150 } 151 return h.Sum64() 152 } 153 154 b = append(b, v.Name...) 155 b = append(b, seps[0]) 156 b = append(b, v.Value...) 157 b = append(b, seps[0]) 158 } 159 return xxhash.Sum64(b) 160 } 161 162 // HashForLabels returns a hash value for the labels matching the provided names. 163 // 'names' have to be sorted in ascending order. 164 func (ls Labels) HashForLabels(b []byte, names ...string) (uint64, []byte) { 165 b = b[:0] 166 i, j := 0, 0 167 for i < len(ls) && j < len(names) { 168 if names[j] < ls[i].Name { 169 j++ 170 } else if ls[i].Name < names[j] { 171 i++ 172 } else { 173 b = append(b, ls[i].Name...) 174 b = append(b, seps[0]) 175 b = append(b, ls[i].Value...) 176 b = append(b, seps[0]) 177 i++ 178 j++ 179 } 180 } 181 return xxhash.Sum64(b), b 182 } 183 184 // HashWithoutLabels returns a hash value for all labels except those matching 185 // the provided names. 186 // 'names' have to be sorted in ascending order. 187 func (ls Labels) HashWithoutLabels(b []byte, names ...string) (uint64, []byte) { 188 b = b[:0] 189 j := 0 190 for i := range ls { 191 for j < len(names) && names[j] < ls[i].Name { 192 j++ 193 } 194 if ls[i].Name == MetricName || (j < len(names) && ls[i].Name == names[j]) { 195 continue 196 } 197 b = append(b, ls[i].Name...) 198 b = append(b, seps[0]) 199 b = append(b, ls[i].Value...) 200 b = append(b, seps[0]) 201 } 202 return xxhash.Sum64(b), b 203 } 204 205 // WithLabels returns a new labels.Labels from ls that only contains labels matching names. 206 // 'names' have to be sorted in ascending order. 207 func (ls Labels) WithLabels(names ...string) Labels { 208 ret := make([]Label, 0, len(ls)) 209 210 i, j := 0, 0 211 for i < len(ls) && j < len(names) { 212 if names[j] < ls[i].Name { 213 j++ 214 } else if ls[i].Name < names[j] { 215 i++ 216 } else { 217 ret = append(ret, ls[i]) 218 i++ 219 j++ 220 } 221 } 222 return ret 223 } 224 225 // WithoutLabels returns a new labels.Labels from ls that contains labels not matching names. 226 // 'names' have to be sorted in ascending order. 227 func (ls Labels) WithoutLabels(names ...string) Labels { 228 ret := make([]Label, 0, len(ls)) 229 230 j := 0 231 for i := range ls { 232 for j < len(names) && names[j] < ls[i].Name { 233 j++ 234 } 235 if ls[i].Name == MetricName || (j < len(names) && ls[i].Name == names[j]) { 236 continue 237 } 238 ret = append(ret, ls[i]) 239 } 240 return ret 241 } 242 243 // Copy returns a copy of the labels. 244 func (ls Labels) Copy() Labels { 245 res := make(Labels, len(ls)) 246 copy(res, ls) 247 return res 248 } 249 250 // Get returns the value for the label with the given name. 251 // Returns an empty string if the label doesn't exist. 252 func (ls Labels) Get(name string) string { 253 for _, l := range ls { 254 if l.Name == name { 255 return l.Value 256 } 257 } 258 return "" 259 } 260 261 // Has returns true if the label with the given name is present. 262 func (ls Labels) Has(name string) bool { 263 for _, l := range ls { 264 if l.Name == name { 265 return true 266 } 267 } 268 return false 269 } 270 271 // HasDuplicateLabelNames returns whether ls has duplicate label names. 272 // It assumes that the labelset is sorted. 273 func (ls Labels) HasDuplicateLabelNames() (string, bool) { 274 for i, l := range ls { 275 if i == 0 { 276 continue 277 } 278 if l.Name == ls[i-1].Name { 279 return l.Name, true 280 } 281 } 282 return "", false 283 } 284 285 // WithoutEmpty returns the labelset without empty labels. 286 // May return the same labelset. 287 func (ls Labels) WithoutEmpty() Labels { 288 for _, v := range ls { 289 if v.Value != "" { 290 continue 291 } 292 // Do not copy the slice until it's necessary. 293 els := make(Labels, 0, len(ls)-1) 294 for _, v := range ls { 295 if v.Value != "" { 296 els = append(els, v) 297 } 298 } 299 return els 300 } 301 return ls 302 } 303 304 // Equal returns whether the two label sets are equal. 305 func Equal(ls, o Labels) bool { 306 if len(ls) != len(o) { 307 return false 308 } 309 for i, l := range ls { 310 if l.Name != o[i].Name || l.Value != o[i].Value { 311 return false 312 } 313 } 314 return true 315 } 316 317 // Map returns a string map of the labels. 318 func (ls Labels) Map() map[string]string { 319 m := make(map[string]string, len(ls)) 320 for _, l := range ls { 321 m[l.Name] = l.Value 322 } 323 return m 324 } 325 326 // New returns a sorted Labels from the given labels. 327 // The caller has to guarantee that all label names are unique. 328 func New(ls ...Label) Labels { 329 set := make(Labels, 0, len(ls)) 330 for _, l := range ls { 331 set = append(set, l) 332 } 333 sort.Sort(set) 334 335 return set 336 } 337 338 // FromMap returns new sorted Labels from the given map. 339 func FromMap(m map[string]string) Labels { 340 l := make([]Label, 0, len(m)) 341 for k, v := range m { 342 l = append(l, Label{Name: k, Value: v}) 343 } 344 return New(l...) 345 } 346 347 // FromStrings creates new labels from pairs of strings. 348 func FromStrings(ss ...string) Labels { 349 if len(ss)%2 != 0 { 350 panic("invalid number of strings") 351 } 352 var res Labels 353 for i := 0; i < len(ss); i += 2 { 354 res = append(res, Label{Name: ss[i], Value: ss[i+1]}) 355 } 356 357 sort.Sort(res) 358 return res 359 } 360 361 // Compare compares the two label sets. 362 // The result will be 0 if a==b, <0 if a < b, and >0 if a > b. 363 func Compare(a, b Labels) int { 364 l := len(a) 365 if len(b) < l { 366 l = len(b) 367 } 368 369 for i := 0; i < l; i++ { 370 if a[i].Name != b[i].Name { 371 if a[i].Name < b[i].Name { 372 return -1 373 } 374 return 1 375 } 376 if a[i].Value != b[i].Value { 377 if a[i].Value < b[i].Value { 378 return -1 379 } 380 return 1 381 } 382 } 383 // If all labels so far were in common, the set with fewer labels comes first. 384 return len(a) - len(b) 385 } 386 387 // Builder allows modifying Labels. 388 type Builder struct { 389 base Labels 390 del []string 391 add []Label 392 } 393 394 // NewBuilder returns a new LabelsBuilder. 395 func NewBuilder(base Labels) *Builder { 396 b := &Builder{ 397 del: make([]string, 0, 5), 398 add: make([]Label, 0, 5), 399 } 400 b.Reset(base) 401 return b 402 } 403 404 // Reset clears all current state for the builder. 405 func (b *Builder) Reset(base Labels) { 406 b.base = base 407 b.del = b.del[:0] 408 b.add = b.add[:0] 409 for _, l := range b.base { 410 if l.Value == "" { 411 b.del = append(b.del, l.Name) 412 } 413 } 414 } 415 416 // Del deletes the label of the given name. 417 func (b *Builder) Del(ns ...string) *Builder { 418 for _, n := range ns { 419 for i, a := range b.add { 420 if a.Name == n { 421 b.add = append(b.add[:i], b.add[i+1:]...) 422 } 423 } 424 b.del = append(b.del, n) 425 } 426 return b 427 } 428 429 // Set the name/value pair as a label. 430 func (b *Builder) Set(n, v string) *Builder { 431 if v == "" { 432 // Empty labels are the same as missing labels. 433 return b.Del(n) 434 } 435 for i, a := range b.add { 436 if a.Name == n { 437 b.add[i].Value = v 438 return b 439 } 440 } 441 b.add = append(b.add, Label{Name: n, Value: v}) 442 443 return b 444 } 445 446 // Labels returns the labels from the builder. If no modifications 447 // were made, the original labels are returned. 448 func (b *Builder) Labels() Labels { 449 if len(b.del) == 0 && len(b.add) == 0 { 450 return b.base 451 } 452 453 // In the general case, labels are removed, modified or moved 454 // rather than added. 455 res := make(Labels, 0, len(b.base)) 456 Outer: 457 for _, l := range b.base { 458 for _, n := range b.del { 459 if l.Name == n { 460 continue Outer 461 } 462 } 463 for _, la := range b.add { 464 if l.Name == la.Name { 465 continue Outer 466 } 467 } 468 res = append(res, l) 469 } 470 res = append(res, b.add...) 471 sort.Sort(res) 472 473 return res 474 }