mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
lib/promrelabel: use regexutil.PromRegex for regex matching in actions labeldrop
,labelkeep
,drop
and keep
This makes possible optimizing additional cases inside regexutil.PromRegex
This commit is contained in:
parent
7afe8450fc
commit
4c6916f32a
7 changed files with 85 additions and 93 deletions
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/envtemplate"
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/envtemplate"
|
||||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fs"
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fs"
|
||||||
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
||||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/regexutil"
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/regexutil"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
@ -189,6 +190,13 @@ func ParseRelabelConfigs(rcs []RelabelConfig, relabelDebug bool) (*ParsedConfigs
|
||||||
var (
|
var (
|
||||||
defaultOriginalRegexForRelabelConfig = regexp.MustCompile(".*")
|
defaultOriginalRegexForRelabelConfig = regexp.MustCompile(".*")
|
||||||
defaultRegexForRelabelConfig = regexp.MustCompile("^(.*)$")
|
defaultRegexForRelabelConfig = regexp.MustCompile("^(.*)$")
|
||||||
|
defaultPromRegex = func() *regexutil.PromRegex {
|
||||||
|
pr, err := regexutil.NewPromRegex(".*")
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("BUG: unexpected error: %s", err))
|
||||||
|
}
|
||||||
|
return pr
|
||||||
|
}()
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseRelabelConfig(rc *RelabelConfig) (*parsedRelabelConfig, error) {
|
func parseRelabelConfig(rc *RelabelConfig) (*parsedRelabelConfig, error) {
|
||||||
|
@ -202,9 +210,9 @@ func parseRelabelConfig(rc *RelabelConfig) (*parsedRelabelConfig, error) {
|
||||||
action = "replace"
|
action = "replace"
|
||||||
}
|
}
|
||||||
targetLabel := rc.TargetLabel
|
targetLabel := rc.TargetLabel
|
||||||
regexCompiled := defaultRegexForRelabelConfig
|
regexAnchored := defaultRegexForRelabelConfig
|
||||||
regexOriginalCompiled := defaultOriginalRegexForRelabelConfig
|
regexOriginalCompiled := defaultOriginalRegexForRelabelConfig
|
||||||
var regexOrValues []string
|
promRegex := defaultPromRegex
|
||||||
if rc.Regex != nil && !isDefaultRegex(rc.Regex.S) {
|
if rc.Regex != nil && !isDefaultRegex(rc.Regex.S) {
|
||||||
regex := rc.Regex.S
|
regex := rc.Regex.S
|
||||||
regexOrig := regex
|
regexOrig := regex
|
||||||
|
@ -216,13 +224,16 @@ func parseRelabelConfig(rc *RelabelConfig) (*parsedRelabelConfig, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot parse `regex` %q: %w", regex, err)
|
return nil, fmt.Errorf("cannot parse `regex` %q: %w", regex, err)
|
||||||
}
|
}
|
||||||
regexCompiled = re
|
regexAnchored = re
|
||||||
reOriginal, err := regexp.Compile(regexOrig)
|
reOriginal, err := regexp.Compile(regexOrig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot parse `regex` %q: %w", regexOrig, err)
|
return nil, fmt.Errorf("cannot parse `regex` %q: %w", regexOrig, err)
|
||||||
}
|
}
|
||||||
regexOriginalCompiled = reOriginal
|
regexOriginalCompiled = reOriginal
|
||||||
regexOrValues = regexutil.GetOrValues(regexOrig)
|
promRegex, err = regexutil.NewPromRegex(regexOrig)
|
||||||
|
if err != nil {
|
||||||
|
logger.Panicf("BUG: cannot parse already parsed regex %q: %s", regexOrig, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
modulus := rc.Modulus
|
modulus := rc.Modulus
|
||||||
replacement := "$1"
|
replacement := "$1"
|
||||||
|
@ -335,20 +346,20 @@ func parseRelabelConfig(rc *RelabelConfig) (*parsedRelabelConfig, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &parsedRelabelConfig{
|
return &parsedRelabelConfig{
|
||||||
SourceLabels: sourceLabels,
|
SourceLabels: sourceLabels,
|
||||||
Separator: separator,
|
Separator: separator,
|
||||||
TargetLabel: targetLabel,
|
TargetLabel: targetLabel,
|
||||||
Regex: regexCompiled,
|
RegexAnchored: regexAnchored,
|
||||||
Modulus: modulus,
|
Modulus: modulus,
|
||||||
Replacement: replacement,
|
Replacement: replacement,
|
||||||
Action: action,
|
Action: action,
|
||||||
If: rc.If,
|
If: rc.If,
|
||||||
|
|
||||||
graphiteMatchTemplate: graphiteMatchTemplate,
|
graphiteMatchTemplate: graphiteMatchTemplate,
|
||||||
graphiteLabelRules: graphiteLabelRules,
|
graphiteLabelRules: graphiteLabelRules,
|
||||||
|
|
||||||
|
regex: promRegex,
|
||||||
regexOriginal: regexOriginalCompiled,
|
regexOriginal: regexOriginalCompiled,
|
||||||
regexOrValues: regexOrValues,
|
|
||||||
|
|
||||||
hasCaptureGroupInTargetLabel: strings.Contains(targetLabel, "$"),
|
hasCaptureGroupInTargetLabel: strings.Contains(targetLabel, "$"),
|
||||||
hasCaptureGroupInReplacement: strings.Contains(replacement, "$"),
|
hasCaptureGroupInReplacement: strings.Contains(replacement, "$"),
|
||||||
|
|
|
@ -126,7 +126,7 @@ func TestParsedConfigsString(t *testing.T) {
|
||||||
TargetLabel: "foo",
|
TargetLabel: "foo",
|
||||||
SourceLabels: []string{"aaa"},
|
SourceLabels: []string{"aaa"},
|
||||||
},
|
},
|
||||||
}, "[SourceLabels=[aaa], Separator=;, TargetLabel=foo, Regex=^(.*)$, Modulus=0, Replacement=$1, Action=replace, If=, "+
|
}, "[SourceLabels=[aaa], Separator=;, TargetLabel=foo, Regex=.*, Modulus=0, Replacement=$1, Action=replace, If=, "+
|
||||||
"graphiteMatchTemplate=<nil>, graphiteLabelRules=[]], relabelDebug=false")
|
"graphiteMatchTemplate=<nil>, graphiteLabelRules=[]], relabelDebug=false")
|
||||||
var ie IfExpression
|
var ie IfExpression
|
||||||
if err := ie.Parse("{foo=~'bar'}"); err != nil {
|
if err := ie.Parse("{foo=~'bar'}"); err != nil {
|
||||||
|
@ -141,7 +141,7 @@ func TestParsedConfigsString(t *testing.T) {
|
||||||
},
|
},
|
||||||
If: &ie,
|
If: &ie,
|
||||||
},
|
},
|
||||||
}, "[SourceLabels=[], Separator=;, TargetLabel=, Regex=^(.*)$, Modulus=0, Replacement=$1, Action=graphite, If={foo=~'bar'}, "+
|
}, "[SourceLabels=[], Separator=;, TargetLabel=, Regex=.*, Modulus=0, Replacement=$1, Action=graphite, If={foo=~'bar'}, "+
|
||||||
"graphiteMatchTemplate=foo.*.bar, graphiteLabelRules=[replaceTemplate=$1-zz, targetLabel=job]], relabelDebug=false")
|
"graphiteMatchTemplate=foo.*.bar, graphiteLabelRules=[replaceTemplate=$1-zz, targetLabel=job]], relabelDebug=false")
|
||||||
f([]RelabelConfig{
|
f([]RelabelConfig{
|
||||||
{
|
{
|
||||||
|
@ -150,7 +150,7 @@ func TestParsedConfigsString(t *testing.T) {
|
||||||
TargetLabel: "x",
|
TargetLabel: "x",
|
||||||
If: &ie,
|
If: &ie,
|
||||||
},
|
},
|
||||||
}, "[SourceLabels=[foo bar], Separator=;, TargetLabel=x, Regex=^(.*)$, Modulus=0, Replacement=$1, Action=replace, If={foo=~'bar'}, "+
|
}, "[SourceLabels=[foo bar], Separator=;, TargetLabel=x, Regex=.*, Modulus=0, Replacement=$1, Action=replace, If={foo=~'bar'}, "+
|
||||||
"graphiteMatchTemplate=<nil>, graphiteLabelRules=[]], relabelDebug=false")
|
"graphiteMatchTemplate=<nil>, graphiteLabelRules=[]], relabelDebug=false")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,13 +174,14 @@ func TestParseRelabelConfigsSuccess(t *testing.T) {
|
||||||
}, &ParsedConfigs{
|
}, &ParsedConfigs{
|
||||||
prcs: []*parsedRelabelConfig{
|
prcs: []*parsedRelabelConfig{
|
||||||
{
|
{
|
||||||
SourceLabels: []string{"foo", "bar"},
|
SourceLabels: []string{"foo", "bar"},
|
||||||
Separator: ";",
|
Separator: ";",
|
||||||
TargetLabel: "xxx",
|
TargetLabel: "xxx",
|
||||||
Regex: defaultRegexForRelabelConfig,
|
RegexAnchored: defaultRegexForRelabelConfig,
|
||||||
Replacement: "$1",
|
Replacement: "$1",
|
||||||
Action: "replace",
|
Action: "replace",
|
||||||
|
|
||||||
|
regex: defaultPromRegex,
|
||||||
regexOriginal: defaultOriginalRegexForRelabelConfig,
|
regexOriginal: defaultOriginalRegexForRelabelConfig,
|
||||||
hasCaptureGroupInReplacement: true,
|
hasCaptureGroupInReplacement: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/bytesutil"
|
||||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
||||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
|
||||||
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/regexutil"
|
||||||
"github.com/cespare/xxhash/v2"
|
"github.com/cespare/xxhash/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,20 +17,20 @@ import (
|
||||||
//
|
//
|
||||||
// See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config
|
// See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config
|
||||||
type parsedRelabelConfig struct {
|
type parsedRelabelConfig struct {
|
||||||
SourceLabels []string
|
SourceLabels []string
|
||||||
Separator string
|
Separator string
|
||||||
TargetLabel string
|
TargetLabel string
|
||||||
Regex *regexp.Regexp
|
RegexAnchored *regexp.Regexp
|
||||||
Modulus uint64
|
Modulus uint64
|
||||||
Replacement string
|
Replacement string
|
||||||
Action string
|
Action string
|
||||||
If *IfExpression
|
If *IfExpression
|
||||||
|
|
||||||
graphiteMatchTemplate *graphiteMatchTemplate
|
graphiteMatchTemplate *graphiteMatchTemplate
|
||||||
graphiteLabelRules []graphiteLabelRule
|
graphiteLabelRules []graphiteLabelRule
|
||||||
|
|
||||||
|
regex *regexutil.PromRegex
|
||||||
regexOriginal *regexp.Regexp
|
regexOriginal *regexp.Regexp
|
||||||
regexOrValues []string
|
|
||||||
|
|
||||||
hasCaptureGroupInTargetLabel bool
|
hasCaptureGroupInTargetLabel bool
|
||||||
hasCaptureGroupInReplacement bool
|
hasCaptureGroupInReplacement bool
|
||||||
|
@ -39,7 +40,8 @@ type parsedRelabelConfig struct {
|
||||||
// String returns human-readable representation for prc.
|
// String returns human-readable representation for prc.
|
||||||
func (prc *parsedRelabelConfig) String() string {
|
func (prc *parsedRelabelConfig) String() string {
|
||||||
return fmt.Sprintf("SourceLabels=%s, Separator=%s, TargetLabel=%s, Regex=%s, Modulus=%d, Replacement=%s, Action=%s, If=%s, graphiteMatchTemplate=%s, graphiteLabelRules=%s",
|
return fmt.Sprintf("SourceLabels=%s, Separator=%s, TargetLabel=%s, Regex=%s, Modulus=%d, Replacement=%s, Action=%s, If=%s, graphiteMatchTemplate=%s, graphiteLabelRules=%s",
|
||||||
prc.SourceLabels, prc.Separator, prc.TargetLabel, prc.Regex, prc.Modulus, prc.Replacement, prc.Action, prc.If, prc.graphiteMatchTemplate, prc.graphiteLabelRules)
|
prc.SourceLabels, prc.Separator, prc.TargetLabel, prc.regexOriginal, prc.Modulus, prc.Replacement,
|
||||||
|
prc.Action, prc.If, prc.graphiteMatchTemplate, prc.graphiteLabelRules)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply applies pcs to labels starting from the labelsOffset.
|
// Apply applies pcs to labels starting from the labelsOffset.
|
||||||
|
@ -183,7 +185,7 @@ func (prc *parsedRelabelConfig) apply(labels []prompbmarshal.Label, labelsOffset
|
||||||
replacement = string(bb.B)
|
replacement = string(bb.B)
|
||||||
}
|
}
|
||||||
bb.B = concatLabelValues(bb.B[:0], src, prc.SourceLabels, prc.Separator)
|
bb.B = concatLabelValues(bb.B[:0], src, prc.SourceLabels, prc.Separator)
|
||||||
if prc.Regex == defaultRegexForRelabelConfig && !prc.hasCaptureGroupInTargetLabel {
|
if prc.RegexAnchored == defaultRegexForRelabelConfig && !prc.hasCaptureGroupInTargetLabel {
|
||||||
if replacement == "$1" {
|
if replacement == "$1" {
|
||||||
// Fast path for the rule that copies source label values to destination:
|
// Fast path for the rule that copies source label values to destination:
|
||||||
// - source_labels: [...]
|
// - source_labels: [...]
|
||||||
|
@ -201,7 +203,7 @@ func (prc *parsedRelabelConfig) apply(labels []prompbmarshal.Label, labelsOffset
|
||||||
return labels
|
return labels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match := prc.Regex.FindSubmatchIndex(bb.B)
|
match := prc.RegexAnchored.FindSubmatchIndex(bb.B)
|
||||||
if match == nil {
|
if match == nil {
|
||||||
// Fast path - nothing to replace.
|
// Fast path - nothing to replace.
|
||||||
relabelBufPool.Put(bb)
|
relabelBufPool.Put(bb)
|
||||||
|
@ -253,7 +255,7 @@ func (prc *parsedRelabelConfig) apply(labels []prompbmarshal.Label, labelsOffset
|
||||||
return labels
|
return labels
|
||||||
case "keep":
|
case "keep":
|
||||||
// Keep the target if `source_labels` joined with `separator` match the `regex`.
|
// Keep the target if `source_labels` joined with `separator` match the `regex`.
|
||||||
if prc.Regex == defaultRegexForRelabelConfig {
|
if prc.RegexAnchored == defaultRegexForRelabelConfig {
|
||||||
// Fast path for the case with `if` and without explicitly set `regex`:
|
// Fast path for the case with `if` and without explicitly set `regex`:
|
||||||
//
|
//
|
||||||
// - action: keep
|
// - action: keep
|
||||||
|
@ -263,7 +265,7 @@ func (prc *parsedRelabelConfig) apply(labels []prompbmarshal.Label, labelsOffset
|
||||||
}
|
}
|
||||||
bb := relabelBufPool.Get()
|
bb := relabelBufPool.Get()
|
||||||
bb.B = concatLabelValues(bb.B[:0], src, prc.SourceLabels, prc.Separator)
|
bb.B = concatLabelValues(bb.B[:0], src, prc.SourceLabels, prc.Separator)
|
||||||
keep := prc.matchString(bytesutil.ToUnsafeString(bb.B))
|
keep := prc.regex.MatchString(bytesutil.ToUnsafeString(bb.B))
|
||||||
relabelBufPool.Put(bb)
|
relabelBufPool.Put(bb)
|
||||||
if !keep {
|
if !keep {
|
||||||
return labels[:labelsOffset]
|
return labels[:labelsOffset]
|
||||||
|
@ -271,7 +273,7 @@ func (prc *parsedRelabelConfig) apply(labels []prompbmarshal.Label, labelsOffset
|
||||||
return labels
|
return labels
|
||||||
case "drop":
|
case "drop":
|
||||||
// Drop the target if `source_labels` joined with `separator` don't match the `regex`.
|
// Drop the target if `source_labels` joined with `separator` don't match the `regex`.
|
||||||
if prc.Regex == defaultRegexForRelabelConfig {
|
if prc.RegexAnchored == defaultRegexForRelabelConfig {
|
||||||
// Fast path for the case with `if` and without explicitly set `regex`:
|
// Fast path for the case with `if` and without explicitly set `regex`:
|
||||||
//
|
//
|
||||||
// - action: drop
|
// - action: drop
|
||||||
|
@ -281,7 +283,7 @@ func (prc *parsedRelabelConfig) apply(labels []prompbmarshal.Label, labelsOffset
|
||||||
}
|
}
|
||||||
bb := relabelBufPool.Get()
|
bb := relabelBufPool.Get()
|
||||||
bb.B = concatLabelValues(bb.B[:0], src, prc.SourceLabels, prc.Separator)
|
bb.B = concatLabelValues(bb.B[:0], src, prc.SourceLabels, prc.Separator)
|
||||||
drop := prc.matchString(bytesutil.ToUnsafeString(bb.B))
|
drop := prc.regex.MatchString(bytesutil.ToUnsafeString(bb.B))
|
||||||
relabelBufPool.Put(bb)
|
relabelBufPool.Put(bb)
|
||||||
if drop {
|
if drop {
|
||||||
return labels[:labelsOffset]
|
return labels[:labelsOffset]
|
||||||
|
@ -317,7 +319,7 @@ func (prc *parsedRelabelConfig) apply(labels []prompbmarshal.Label, labelsOffset
|
||||||
dst := labels[:labelsOffset]
|
dst := labels[:labelsOffset]
|
||||||
for i := range src {
|
for i := range src {
|
||||||
label := &src[i]
|
label := &src[i]
|
||||||
if !prc.matchString(label.Name) {
|
if !prc.regex.MatchString(label.Name) {
|
||||||
dst = append(dst, *label)
|
dst = append(dst, *label)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -327,7 +329,7 @@ func (prc *parsedRelabelConfig) apply(labels []prompbmarshal.Label, labelsOffset
|
||||||
dst := labels[:labelsOffset]
|
dst := labels[:labelsOffset]
|
||||||
for i := range src {
|
for i := range src {
|
||||||
label := &src[i]
|
label := &src[i]
|
||||||
if prc.matchString(label.Name) {
|
if prc.regex.MatchString(label.Name) {
|
||||||
dst = append(dst, *label)
|
dst = append(dst, *label)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -387,12 +389,12 @@ func (prc *parsedRelabelConfig) replaceFullString(s, replacement string, hasCapt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Slow path - regexp processing
|
// Slow path - regexp processing
|
||||||
match := prc.Regex.FindStringSubmatchIndex(s)
|
match := prc.RegexAnchored.FindStringSubmatchIndex(s)
|
||||||
if match == nil {
|
if match == nil {
|
||||||
return s, false
|
return s, false
|
||||||
}
|
}
|
||||||
bb := relabelBufPool.Get()
|
bb := relabelBufPool.Get()
|
||||||
bb.B = prc.Regex.ExpandString(bb.B[:0], replacement, s, match)
|
bb.B = prc.RegexAnchored.ExpandString(bb.B[:0], replacement, s, match)
|
||||||
result := string(bb.B)
|
result := string(bb.B)
|
||||||
relabelBufPool.Put(bb)
|
relabelBufPool.Put(bb)
|
||||||
return result, true
|
return result, true
|
||||||
|
@ -413,39 +415,9 @@ func (prc *parsedRelabelConfig) replaceStringSubmatches(s, replacement string, h
|
||||||
return re.ReplaceAllString(s, replacement), true
|
return re.ReplaceAllString(s, replacement), true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (prc *parsedRelabelConfig) matchString(s string) bool {
|
|
||||||
if len(prc.regexOrValues) > 0 {
|
|
||||||
for _, orValue := range prc.regexOrValues {
|
|
||||||
if s == orValue {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
prefix, complete := prc.regexOriginal.LiteralPrefix()
|
|
||||||
if complete {
|
|
||||||
return prefix == s
|
|
||||||
}
|
|
||||||
if !strings.HasPrefix(s, prefix) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
reStr := prc.regexOriginal.String()
|
|
||||||
if strings.HasPrefix(reStr, prefix) {
|
|
||||||
// Fast path for `foo.*` and `bar.+` regexps
|
|
||||||
reSuffix := reStr[len(prefix):]
|
|
||||||
switch reSuffix {
|
|
||||||
case ".+", "(.+)":
|
|
||||||
return len(s) > len(prefix)
|
|
||||||
case ".*", "(.*)":
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return prc.Regex.MatchString(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (prc *parsedRelabelConfig) expandCaptureGroups(template, source string, match []int) string {
|
func (prc *parsedRelabelConfig) expandCaptureGroups(template, source string, match []int) string {
|
||||||
bb := relabelBufPool.Get()
|
bb := relabelBufPool.Get()
|
||||||
bb.B = prc.Regex.ExpandString(bb.B[:0], template, source, match)
|
bb.B = prc.RegexAnchored.ExpandString(bb.B[:0], template, source, match)
|
||||||
s := string(bb.B)
|
s := string(bb.B)
|
||||||
relabelBufPool.Put(bb)
|
relabelBufPool.Put(bb)
|
||||||
return s
|
return s
|
||||||
|
|
|
@ -728,12 +728,12 @@ func TestFillLabelReferences(t *testing.T) {
|
||||||
f(`{{bar}}-aa{{__name__}}.{{bar}}{{non-existing-label}}`, `foo{bar="baz"}`, `baz-aafoo.baz`)
|
f(`{{bar}}-aa{{__name__}}.{{bar}}{{non-existing-label}}`, `foo{bar="baz"}`, `baz-aafoo.baz`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRegexpMatchStringSuccess(t *testing.T) {
|
func TestRegexMatchStringSuccess(t *testing.T) {
|
||||||
f := func(pattern, s string) {
|
f := func(pattern, s string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
prc := newTestRegexRelabelConfig(pattern)
|
prc := newTestRegexRelabelConfig(pattern)
|
||||||
if !prc.matchString(s) {
|
if !prc.regex.MatchString(s) {
|
||||||
t.Fatalf("unexpected matchString(%q) result; got false; want true", s)
|
t.Fatalf("unexpected MatchString(%q) result; got false; want true", s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f("", "")
|
f("", "")
|
||||||
|
@ -753,8 +753,8 @@ func TestRegexpMatchStringFailure(t *testing.T) {
|
||||||
f := func(pattern, s string) {
|
f := func(pattern, s string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
prc := newTestRegexRelabelConfig(pattern)
|
prc := newTestRegexRelabelConfig(pattern)
|
||||||
if prc.matchString(s) {
|
if prc.regex.MatchString(s) {
|
||||||
t.Fatalf("unexpected matchString(%q) result; got true; want false", s)
|
t.Fatalf("unexpected MatchString(%q) result; got true; want false", s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f("", "foo")
|
f("", "foo")
|
||||||
|
|
|
@ -16,7 +16,7 @@ func BenchmarkMatchRegexPrefixDotPlusMatchOptimized(b *testing.B) {
|
||||||
b.SetBytes(1)
|
b.SetBytes(1)
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
if !prc.matchString(s) {
|
if !prc.regex.MatchString(s) {
|
||||||
panic(fmt.Errorf("unexpected string mismatch for pattern=%q, s=%q", pattern, s))
|
panic(fmt.Errorf("unexpected string mismatch for pattern=%q, s=%q", pattern, s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ func BenchmarkMatchRegexPrefixDotPlusMismatchOptimized(b *testing.B) {
|
||||||
b.SetBytes(1)
|
b.SetBytes(1)
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
if prc.matchString(s) {
|
if prc.regex.MatchString(s) {
|
||||||
panic(fmt.Errorf("unexpected string match for pattern=%q, s=%q", pattern, s))
|
panic(fmt.Errorf("unexpected string match for pattern=%q, s=%q", pattern, s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ func BenchmarkMatchRegexPrefixDotStarMatchOptimized(b *testing.B) {
|
||||||
b.SetBytes(1)
|
b.SetBytes(1)
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
if !prc.matchString(s) {
|
if !prc.regex.MatchString(s) {
|
||||||
panic(fmt.Errorf("unexpected string mismatch for pattern=%q, s=%q", pattern, s))
|
panic(fmt.Errorf("unexpected string mismatch for pattern=%q, s=%q", pattern, s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ func BenchmarkMatchRegexPrefixDotStarMismatchOptimized(b *testing.B) {
|
||||||
b.SetBytes(1)
|
b.SetBytes(1)
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
if prc.matchString(s) {
|
if prc.regex.MatchString(s) {
|
||||||
panic(fmt.Errorf("unexpected string match for pattern=%q, s=%q", pattern, s))
|
panic(fmt.Errorf("unexpected string match for pattern=%q, s=%q", pattern, s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ func BenchmarkMatchRegexSingleValueMatchOptimized(b *testing.B) {
|
||||||
b.SetBytes(1)
|
b.SetBytes(1)
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
if !prc.matchString(s) {
|
if !prc.regex.MatchString(s) {
|
||||||
panic(fmt.Errorf("unexpected string mismatch for pattern=%q, s=%q", pattern, s))
|
panic(fmt.Errorf("unexpected string mismatch for pattern=%q, s=%q", pattern, s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,7 @@ func BenchmarkMatchRegexSingleValueMismatchOptimized(b *testing.B) {
|
||||||
b.SetBytes(1)
|
b.SetBytes(1)
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
if prc.matchString(s) {
|
if prc.regex.MatchString(s) {
|
||||||
panic(fmt.Errorf("unexpected string match for pattern=%q, s=%q", pattern, s))
|
panic(fmt.Errorf("unexpected string match for pattern=%q, s=%q", pattern, s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,7 @@ func BenchmarkMatchRegexOrValuesMatchOptimized(b *testing.B) {
|
||||||
b.SetBytes(1)
|
b.SetBytes(1)
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
if !prc.matchString(s) {
|
if !prc.regex.MatchString(s) {
|
||||||
panic(fmt.Errorf("unexpected string mismatch for pattern=%q, s=%q", pattern, s))
|
panic(fmt.Errorf("unexpected string mismatch for pattern=%q, s=%q", pattern, s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,7 +226,7 @@ func BenchmarkMatchRegexOrValuesMismatchOptimized(b *testing.B) {
|
||||||
b.SetBytes(1)
|
b.SetBytes(1)
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
if prc.matchString(s) {
|
if prc.regex.MatchString(s) {
|
||||||
panic(fmt.Errorf("unexpected string match for pattern=%q, s=%q", pattern, s))
|
panic(fmt.Errorf("unexpected string match for pattern=%q, s=%q", pattern, s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
type PromRegex struct {
|
type PromRegex struct {
|
||||||
// prefix contains literal prefix for regex.
|
// prefix contains literal prefix for regex.
|
||||||
// For example, prefix="foo" for regex="foo(a|b)"
|
// For example, prefix="foo" for regex="foo(a|b)"
|
||||||
prefix string
|
prefix string
|
||||||
|
|
||||||
// Suffix contains regex suffix left after removing the prefix.
|
// Suffix contains regex suffix left after removing the prefix.
|
||||||
// For example, suffix="a|b" for regex="foo(a|b)"
|
// For example, suffix="a|b" for regex="foo(a|b)"
|
||||||
|
@ -51,12 +51,12 @@ func NewPromRegex(expr string) (*PromRegex, error) {
|
||||||
suffixExpr := "^(?:" + suffix + ")$"
|
suffixExpr := "^(?:" + suffix + ")$"
|
||||||
reSuffix := regexp.MustCompile(suffixExpr)
|
reSuffix := regexp.MustCompile(suffixExpr)
|
||||||
pr := &PromRegex{
|
pr := &PromRegex{
|
||||||
prefix: prefix,
|
prefix: prefix,
|
||||||
suffix: suffix,
|
suffix: suffix,
|
||||||
substrDotStar: substrDotStar,
|
substrDotStar: substrDotStar,
|
||||||
substrDotPlus: substrDotPlus,
|
substrDotPlus: substrDotPlus,
|
||||||
orValues: orValues,
|
orValues: orValues,
|
||||||
reSuffix: reSuffix,
|
reSuffix: reSuffix,
|
||||||
}
|
}
|
||||||
return pr, nil
|
return pr, nil
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ func (pr *PromRegex) MatchString(s string) bool {
|
||||||
if pr.substrDotPlus != "" {
|
if pr.substrDotPlus != "" {
|
||||||
// Fast path - pr contains ".+someText.+"
|
// Fast path - pr contains ".+someText.+"
|
||||||
n := strings.Index(s, pr.substrDotPlus)
|
n := strings.Index(s, pr.substrDotPlus)
|
||||||
return n > 0 && n + len(pr.substrDotPlus) < len(s)
|
return n > 0 && n+len(pr.substrDotPlus) < len(s)
|
||||||
}
|
}
|
||||||
switch pr.suffix {
|
switch pr.suffix {
|
||||||
case ".*":
|
case ".*":
|
||||||
|
@ -116,4 +116,3 @@ func getSubstringLiteral(expr, prefixSuffix string) string {
|
||||||
}
|
}
|
||||||
return prefix
|
return prefix
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,15 @@ func BenchmarkPromRegexMatchString(b *testing.B) {
|
||||||
b.Run("unpotimized-prefix-mismatch", func(b *testing.B) {
|
b.Run("unpotimized-prefix-mismatch", func(b *testing.B) {
|
||||||
benchmarkPromRegexMatchString(b, "foo(bar.*|baz)", "zfoobarz", false)
|
benchmarkPromRegexMatchString(b, "foo(bar.*|baz)", "zfoobarz", false)
|
||||||
})
|
})
|
||||||
|
b.Run("dot-star-match", func(b *testing.B) {
|
||||||
|
benchmarkPromRegexMatchString(b, ".*", "foo", true)
|
||||||
|
})
|
||||||
|
b.Run("dot-plus-match", func(b *testing.B) {
|
||||||
|
benchmarkPromRegexMatchString(b, ".+", "foo", true)
|
||||||
|
})
|
||||||
|
b.Run("dot-plus-mismatch", func(b *testing.B) {
|
||||||
|
benchmarkPromRegexMatchString(b, ".+", "", false)
|
||||||
|
})
|
||||||
b.Run("literal-match", func(b *testing.B) {
|
b.Run("literal-match", func(b *testing.B) {
|
||||||
benchmarkPromRegexMatchString(b, "foo", "foo", true)
|
benchmarkPromRegexMatchString(b, "foo", "foo", true)
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue