| // Copyright 2013 The Prometheus Authors |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package model |
| |
| import ( |
| "encoding/json" |
| "fmt" |
| "sort" |
| "strings" |
| ) |
| |
| // A LabelSet is a collection of LabelName and LabelValue pairs. The LabelSet |
| // may be fully-qualified down to the point where it may resolve to a single |
| // Metric in the data store or not. All operations that occur within the realm |
| // of a LabelSet can emit a vector of Metric entities to which the LabelSet may |
| // match. |
| type LabelSet map[LabelName]LabelValue |
| |
| // Validate checks whether all names and values in the label set |
| // are valid. |
| func (ls LabelSet) Validate() error { |
| for ln, lv := range ls { |
| if !ln.IsValid() { |
| return fmt.Errorf("invalid name %q", ln) |
| } |
| if !lv.IsValid() { |
| return fmt.Errorf("invalid value %q", lv) |
| } |
| } |
| return nil |
| } |
| |
| // Equal returns true iff both label sets have exactly the same key/value pairs. |
| func (ls LabelSet) Equal(o LabelSet) bool { |
| if len(ls) != len(o) { |
| return false |
| } |
| for ln, lv := range ls { |
| olv, ok := o[ln] |
| if !ok { |
| return false |
| } |
| if olv != lv { |
| return false |
| } |
| } |
| return true |
| } |
| |
| // Before compares the metrics, using the following criteria: |
| // |
| // If m has fewer labels than o, it is before o. If it has more, it is not. |
| // |
| // If the number of labels is the same, the superset of all label names is |
| // sorted alphanumerically. The first differing label pair found in that order |
| // determines the outcome: If the label does not exist at all in m, then m is |
| // before o, and vice versa. Otherwise the label value is compared |
| // alphanumerically. |
| // |
| // If m and o are equal, the method returns false. |
| func (ls LabelSet) Before(o LabelSet) bool { |
| if len(ls) < len(o) { |
| return true |
| } |
| if len(ls) > len(o) { |
| return false |
| } |
| |
| lns := make(LabelNames, 0, len(ls)+len(o)) |
| for ln := range ls { |
| lns = append(lns, ln) |
| } |
| for ln := range o { |
| lns = append(lns, ln) |
| } |
| // It's probably not worth it to de-dup lns. |
| sort.Sort(lns) |
| for _, ln := range lns { |
| mlv, ok := ls[ln] |
| if !ok { |
| return true |
| } |
| olv, ok := o[ln] |
| if !ok { |
| return false |
| } |
| if mlv < olv { |
| return true |
| } |
| if mlv > olv { |
| return false |
| } |
| } |
| return false |
| } |
| |
| // Clone returns a copy of the label set. |
| func (ls LabelSet) Clone() LabelSet { |
| lsn := make(LabelSet, len(ls)) |
| for ln, lv := range ls { |
| lsn[ln] = lv |
| } |
| return lsn |
| } |
| |
| // Merge is a helper function to non-destructively merge two label sets. |
| func (l LabelSet) Merge(other LabelSet) LabelSet { |
| result := make(LabelSet, len(l)) |
| |
| for k, v := range l { |
| result[k] = v |
| } |
| |
| for k, v := range other { |
| result[k] = v |
| } |
| |
| return result |
| } |
| |
| func (l LabelSet) String() string { |
| lstrs := make([]string, 0, len(l)) |
| for l, v := range l { |
| lstrs = append(lstrs, fmt.Sprintf("%s=%q", l, v)) |
| } |
| |
| sort.Strings(lstrs) |
| return fmt.Sprintf("{%s}", strings.Join(lstrs, ", ")) |
| } |
| |
| // Fingerprint returns the LabelSet's fingerprint. |
| func (ls LabelSet) Fingerprint() Fingerprint { |
| return labelSetToFingerprint(ls) |
| } |
| |
| // FastFingerprint returns the LabelSet's Fingerprint calculated by a faster hashing |
| // algorithm, which is, however, more susceptible to hash collisions. |
| func (ls LabelSet) FastFingerprint() Fingerprint { |
| return labelSetToFastFingerprint(ls) |
| } |
| |
| // UnmarshalJSON implements the json.Unmarshaler interface. |
| func (l *LabelSet) UnmarshalJSON(b []byte) error { |
| var m map[LabelName]LabelValue |
| if err := json.Unmarshal(b, &m); err != nil { |
| return err |
| } |
| // encoding/json only unmarshals maps of the form map[string]T. It treats |
| // LabelName as a string and does not call its UnmarshalJSON method. |
| // Thus, we have to replicate the behavior here. |
| for ln := range m { |
| if !ln.IsValid() { |
| return fmt.Errorf("%q is not a valid label name", ln) |
| } |
| } |
| *l = LabelSet(m) |
| return nil |
| } |