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  }