prometheus/storage/metric/matcher.go
Julius Volz c7c0b33d0b Add regex-matching support for labels.
There are four label-matching ops for selecting timeseries now:

- Equal: =
- NotEqual: !=
- RegexMatch: =~
- RegexNoMatch: !~

Instead of looking up labels by a simple clientmodel.LabelSet (basically
an equals op for every key/value pair in the set), timeseries
fingerprint selection is now done via a list of metric.LabelMatchers.

Change-Id: I510a83f761198e80946146770ebb64e4abc3bb96
2014-04-01 14:24:53 +02:00

113 lines
2.7 KiB
Go

// Copyright 2014 Prometheus Team
// 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 metric
import (
"regexp"
clientmodel "github.com/prometheus/client_golang/model"
)
// MatchType is an enum for label matching types.
type MatchType int
// Possible MatchTypes.
const (
Equal MatchType = iota
NotEqual
RegexMatch
RegexNoMatch
)
func (m MatchType) String() string {
typeToStr := map[MatchType]string{
Equal: "=",
NotEqual: "!=",
RegexMatch: "=~",
RegexNoMatch: "!~",
}
if str, ok := typeToStr[m]; ok {
return str
}
panic("unknown match type")
}
// LabelMatchers is a slice of LabelMatcher objects.
type LabelMatchers []*LabelMatcher
// LabelMatcher models the matching of a label.
type LabelMatcher struct {
Type MatchType
Name clientmodel.LabelName
Value clientmodel.LabelValue
re *regexp.Regexp
}
// NewLabelMatcher returns a LabelMatcher object ready to use.
func NewLabelMatcher(matchType MatchType, name clientmodel.LabelName, value clientmodel.LabelValue) (*LabelMatcher, error) {
m := &LabelMatcher{
Type: matchType,
Name: name,
Value: value,
}
if matchType == RegexMatch || matchType == RegexNoMatch {
re, err := regexp.Compile(string(value))
if err != nil {
return nil, err
}
m.re = re
}
return m, nil
}
// Match returns true if the label matcher matches the supplied label value.
func (m *LabelMatcher) Match(v clientmodel.LabelValue) bool {
switch m.Type {
case Equal:
return m.Value == v
case NotEqual:
return m.Value != v
case RegexMatch:
return m.re.MatchString(string(v))
case RegexNoMatch:
return !m.re.MatchString(string(v))
default:
panic("invalid match type")
}
}
// Filter takes a list of label values and returns all label values which match
// the label matcher.
func (m *LabelMatcher) Filter(in clientmodel.LabelValues) clientmodel.LabelValues {
out := clientmodel.LabelValues{}
for _, v := range in {
if m.Match(v) {
out = append(out, v)
}
}
return out
}
func labelMatchersFromLabelSet(l clientmodel.LabelSet) LabelMatchers {
m := make(LabelMatchers, 0, len(l))
for k, v := range l {
m = append(m, &LabelMatcher{
Type: Equal,
Name: k,
Value: v,
})
}
return m
}