lib/promrelabel: add more optimizations for relabeling for common cases

This commit is contained in:
Aliaksandr Valialkin 2021-02-22 16:33:55 +02:00
parent dd1e53b119
commit d136081040
12 changed files with 751 additions and 725 deletions

View file

@ -41,7 +41,7 @@ func loadRelabelConfigs() (*relabelConfigs, error) {
return nil, fmt.Errorf("too many -remoteWrite.urlRelabelConfig args: %d; it mustn't exceed the number of -remoteWrite.url args: %d",
len(*relabelConfigPaths), len(*remoteWriteURLs))
}
rcs.perURL = make([][]promrelabel.ParsedRelabelConfig, len(*remoteWriteURLs))
rcs.perURL = make([]*promrelabel.ParsedConfigs, len(*remoteWriteURLs))
for i, path := range *relabelConfigPaths {
if len(path) == 0 {
// Skip empty relabel config.
@ -57,8 +57,8 @@ func loadRelabelConfigs() (*relabelConfigs, error) {
}
type relabelConfigs struct {
global []promrelabel.ParsedRelabelConfig
perURL [][]promrelabel.ParsedRelabelConfig
global *promrelabel.ParsedConfigs
perURL []*promrelabel.ParsedConfigs
}
// initLabelsGlobal must be called after parsing command-line flags.
@ -79,8 +79,8 @@ func initLabelsGlobal() {
}
}
func (rctx *relabelCtx) applyRelabeling(tss []prompbmarshal.TimeSeries, extraLabels []prompbmarshal.Label, prcs []promrelabel.ParsedRelabelConfig) []prompbmarshal.TimeSeries {
if len(extraLabels) == 0 && len(prcs) == 0 {
func (rctx *relabelCtx) applyRelabeling(tss []prompbmarshal.TimeSeries, extraLabels []prompbmarshal.Label, pcs *promrelabel.ParsedConfigs) []prompbmarshal.TimeSeries {
if len(extraLabels) == 0 && pcs.Len() == 0 {
// Nothing to change.
return tss
}
@ -100,7 +100,7 @@ func (rctx *relabelCtx) applyRelabeling(tss []prompbmarshal.TimeSeries, extraLab
labels = append(labels, *extraLabel)
}
}
labels = promrelabel.ApplyRelabelConfigs(labels, labelsLen, prcs, true)
labels = pcs.Apply(labels, labelsLen, true)
if len(labels) == labelsLen {
// Drop the current time series, since relabeling removed all the labels.
continue

View file

@ -142,8 +142,8 @@ func Stop() {
func Push(wr *prompbmarshal.WriteRequest) {
var rctx *relabelCtx
rcs := allRelabelConfigs.Load().(*relabelConfigs)
prcsGlobal := rcs.global
if len(prcsGlobal) > 0 || len(labelsGlobal) > 0 {
pcsGlobal := rcs.global
if pcsGlobal.Len() > 0 || len(labelsGlobal) > 0 {
rctx = getRelabelCtx()
}
tss := wr.Timeseries
@ -167,7 +167,7 @@ func Push(wr *prompbmarshal.WriteRequest) {
}
if rctx != nil {
tssBlockLen := len(tssBlock)
tssBlock = rctx.applyRelabeling(tssBlock, labelsGlobal, prcsGlobal)
tssBlock = rctx.applyRelabeling(tssBlock, labelsGlobal, pcsGlobal)
globalRelabelMetricsDropped.Add(tssBlockLen - len(tssBlock))
}
for _, rwctx := range rwctxs {
@ -240,8 +240,8 @@ func (rwctx *remoteWriteCtx) Push(tss []prompbmarshal.TimeSeries) {
var rctx *relabelCtx
var v *[]prompbmarshal.TimeSeries
rcs := allRelabelConfigs.Load().(*relabelConfigs)
prcs := rcs.perURL[rwctx.idx]
if len(prcs) > 0 {
pcs := rcs.perURL[rwctx.idx]
if pcs.Len() > 0 {
rctx = getRelabelCtx()
// Make a copy of tss before applying relabeling in order to prevent
// from affecting time series for other remoteWrite.url configs.
@ -250,7 +250,7 @@ func (rwctx *remoteWriteCtx) Push(tss []prompbmarshal.TimeSeries) {
v = tssRelabelPool.Get().(*[]prompbmarshal.TimeSeries)
tss = append(*v, tss...)
tssLen := len(tss)
tss = rctx.applyRelabeling(tss, nil, prcs)
tss = rctx.applyRelabeling(tss, nil, pcs)
rwctx.relabelMetricsDropped.Add(tssLen - len(tss))
}
pss := rwctx.pss

View file

@ -19,11 +19,11 @@ var relabelConfig = flag.String("relabelConfig", "", "Optional path to a file wi
// Init must be called after flag.Parse and before using the relabel package.
func Init() {
prcs, err := loadRelabelConfig()
pcs, err := loadRelabelConfig()
if err != nil {
logger.Fatalf("cannot load relabelConfig: %s", err)
}
prcsGlobal.Store(&prcs)
pcsGlobal.Store(pcs)
if len(*relabelConfig) == 0 {
return
}
@ -31,34 +31,34 @@ func Init() {
go func() {
for range sighupCh {
logger.Infof("received SIGHUP; reloading -relabelConfig=%q...", *relabelConfig)
prcs, err := loadRelabelConfig()
pcs, err := loadRelabelConfig()
if err != nil {
logger.Errorf("cannot load the updated relabelConfig: %s; preserving the previous config", err)
continue
}
prcsGlobal.Store(&prcs)
pcsGlobal.Store(pcs)
logger.Infof("successfully reloaded -relabelConfig=%q", *relabelConfig)
}
}()
}
var prcsGlobal atomic.Value
var pcsGlobal atomic.Value
func loadRelabelConfig() ([]promrelabel.ParsedRelabelConfig, error) {
func loadRelabelConfig() (*promrelabel.ParsedConfigs, error) {
if len(*relabelConfig) == 0 {
return nil, nil
}
prcs, err := promrelabel.LoadRelabelConfigs(*relabelConfig)
pcs, err := promrelabel.LoadRelabelConfigs(*relabelConfig)
if err != nil {
return nil, fmt.Errorf("error when reading -relabelConfig=%q: %w", *relabelConfig, err)
}
return prcs, nil
return pcs, nil
}
// HasRelabeling returns true if there is global relabeling.
func HasRelabeling() bool {
prcs := prcsGlobal.Load().(*[]promrelabel.ParsedRelabelConfig)
return len(*prcs) > 0
pcs := pcsGlobal.Load().(*promrelabel.ParsedConfigs)
return pcs.Len() > 0
}
// Ctx holds relabeling context.
@ -77,8 +77,8 @@ func (ctx *Ctx) Reset() {
//
// The returned labels are valid until the next call to ApplyRelabeling.
func (ctx *Ctx) ApplyRelabeling(labels []prompb.Label) []prompb.Label {
prcs := prcsGlobal.Load().(*[]promrelabel.ParsedRelabelConfig)
if len(*prcs) == 0 {
pcs := pcsGlobal.Load().(*promrelabel.ParsedConfigs)
if pcs.Len() == 0 {
// There are no relabeling rules.
return labels
}
@ -97,7 +97,7 @@ func (ctx *Ctx) ApplyRelabeling(labels []prompb.Label) []prompb.Label {
}
// Apply relabeling
tmpLabels = promrelabel.ApplyRelabelConfigs(tmpLabels, 0, *prcs, true)
tmpLabels = pcs.Apply(tmpLabels, 0, true)
ctx.tmpLabels = tmpLabels
if len(tmpLabels) == 0 {
metricsDropped.Inc()

View file

@ -23,38 +23,78 @@ type RelabelConfig struct {
Action string `yaml:"action,omitempty"`
}
// ParsedConfigs represents parsed relabel configs.
type ParsedConfigs struct {
prcs []*parsedRelabelConfig
}
// Len returns the number of relabel configs in pcs.
func (pcs *ParsedConfigs) Len() int {
if pcs == nil {
return 0
}
return len(pcs.prcs)
}
// String returns human-readabale representation for pcs.
func (pcs *ParsedConfigs) String() string {
if pcs == nil {
return ""
}
var sb strings.Builder
for _, prc := range pcs.prcs {
fmt.Fprintf(&sb, "%s", prc.String())
}
return sb.String()
}
// LoadRelabelConfigs loads relabel configs from the given path.
func LoadRelabelConfigs(path string) ([]ParsedRelabelConfig, error) {
func LoadRelabelConfigs(path string) (*ParsedConfigs, error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("cannot read `relabel_configs` from %q: %w", path, err)
}
data = envtemplate.Replace(data)
var rcs []RelabelConfig
if err := yaml.UnmarshalStrict(data, &rcs); err != nil {
pcs, err := ParseRelabelConfigsData(data)
if err != nil {
return nil, fmt.Errorf("cannot unmarshal `relabel_configs` from %q: %w", path, err)
}
return ParseRelabelConfigs(nil, rcs)
return pcs, nil
}
// ParseRelabelConfigsData parses relabel configs from the given data.
func ParseRelabelConfigsData(data []byte) (*ParsedConfigs, error) {
var rcs []RelabelConfig
if err := yaml.UnmarshalStrict(data, &rcs); err != nil {
return nil, err
}
return ParseRelabelConfigs(rcs)
}
// ParseRelabelConfigs parses rcs to dst.
func ParseRelabelConfigs(dst []ParsedRelabelConfig, rcs []RelabelConfig) ([]ParsedRelabelConfig, error) {
func ParseRelabelConfigs(rcs []RelabelConfig) (*ParsedConfigs, error) {
if len(rcs) == 0 {
return dst, nil
return nil, nil
}
prcs := make([]*parsedRelabelConfig, len(rcs))
for i := range rcs {
var err error
dst, err = parseRelabelConfig(dst, &rcs[i])
prc, err := parseRelabelConfig(&rcs[i])
if err != nil {
return dst, fmt.Errorf("error when parsing `relabel_config` #%d: %w", i+1, err)
return nil, fmt.Errorf("error when parsing `relabel_config` #%d: %w", i+1, err)
}
prcs[i] = prc
}
return dst, nil
return &ParsedConfigs{
prcs: prcs,
}, nil
}
var defaultRegexForRelabelConfig = regexp.MustCompile("^(.*)$")
var (
defaultOriginalRegexForRelabelConfig = regexp.MustCompile(".*")
defaultRegexForRelabelConfig = regexp.MustCompile("^(.*)$")
)
func parseRelabelConfig(dst []ParsedRelabelConfig, rc *RelabelConfig) ([]ParsedRelabelConfig, error) {
func parseRelabelConfig(rc *RelabelConfig) (*parsedRelabelConfig, error) {
sourceLabels := rc.SourceLabels
separator := ";"
if rc.Separator != nil {
@ -62,6 +102,7 @@ func parseRelabelConfig(dst []ParsedRelabelConfig, rc *RelabelConfig) ([]ParsedR
}
targetLabel := rc.TargetLabel
regexCompiled := defaultRegexForRelabelConfig
regexOriginalCompiled := defaultOriginalRegexForRelabelConfig
if rc.Regex != nil {
regex := *rc.Regex
if rc.Action != "replace_all" && rc.Action != "labelmap_all" {
@ -69,9 +110,14 @@ func parseRelabelConfig(dst []ParsedRelabelConfig, rc *RelabelConfig) ([]ParsedR
}
re, err := regexp.Compile(regex)
if err != nil {
return dst, fmt.Errorf("cannot parse `regex` %q: %w", regex, err)
return nil, fmt.Errorf("cannot parse `regex` %q: %w", regex, err)
}
regexCompiled = re
reOriginal, err := regexp.Compile(*rc.Regex)
if err != nil {
return nil, fmt.Errorf("cannot parse `regex` %q: %w", *rc.Regex, err)
}
regexOriginalCompiled = reOriginal
}
modulus := rc.Modulus
replacement := "$1"
@ -85,49 +131,49 @@ func parseRelabelConfig(dst []ParsedRelabelConfig, rc *RelabelConfig) ([]ParsedR
switch action {
case "replace":
if targetLabel == "" {
return dst, fmt.Errorf("missing `target_label` for `action=replace`")
return nil, fmt.Errorf("missing `target_label` for `action=replace`")
}
case "replace_all":
if len(sourceLabels) == 0 {
return dst, fmt.Errorf("missing `source_labels` for `action=replace_all`")
return nil, fmt.Errorf("missing `source_labels` for `action=replace_all`")
}
if targetLabel == "" {
return dst, fmt.Errorf("missing `target_label` for `action=replace_all`")
return nil, fmt.Errorf("missing `target_label` for `action=replace_all`")
}
case "keep_if_equal":
if len(sourceLabels) < 2 {
return dst, fmt.Errorf("`source_labels` must contain at least two entries for `action=keep_if_equal`; got %q", sourceLabels)
return nil, fmt.Errorf("`source_labels` must contain at least two entries for `action=keep_if_equal`; got %q", sourceLabels)
}
case "drop_if_equal":
if len(sourceLabels) < 2 {
return dst, fmt.Errorf("`source_labels` must contain at least two entries for `action=drop_if_equal`; got %q", sourceLabels)
return nil, fmt.Errorf("`source_labels` must contain at least two entries for `action=drop_if_equal`; got %q", sourceLabels)
}
case "keep":
if len(sourceLabels) == 0 {
return dst, fmt.Errorf("missing `source_labels` for `action=keep`")
return nil, fmt.Errorf("missing `source_labels` for `action=keep`")
}
case "drop":
if len(sourceLabels) == 0 {
return dst, fmt.Errorf("missing `source_labels` for `action=drop`")
return nil, fmt.Errorf("missing `source_labels` for `action=drop`")
}
case "hashmod":
if len(sourceLabels) == 0 {
return dst, fmt.Errorf("missing `source_labels` for `action=hashmod`")
return nil, fmt.Errorf("missing `source_labels` for `action=hashmod`")
}
if targetLabel == "" {
return dst, fmt.Errorf("missing `target_label` for `action=hashmod`")
return nil, fmt.Errorf("missing `target_label` for `action=hashmod`")
}
if modulus < 1 {
return dst, fmt.Errorf("unexpected `modulus` for `action=hashmod`: %d; must be greater than 0", modulus)
return nil, fmt.Errorf("unexpected `modulus` for `action=hashmod`: %d; must be greater than 0", modulus)
}
case "labelmap":
case "labelmap_all":
case "labeldrop":
case "labelkeep":
default:
return dst, fmt.Errorf("unknown `action` %q", action)
return nil, fmt.Errorf("unknown `action` %q", action)
}
dst = append(dst, ParsedRelabelConfig{
return &parsedRelabelConfig{
SourceLabels: sourceLabels,
Separator: separator,
TargetLabel: targetLabel,
@ -136,8 +182,8 @@ func parseRelabelConfig(dst []ParsedRelabelConfig, rc *RelabelConfig) ([]ParsedR
Replacement: replacement,
Action: action,
regexOriginal: regexOriginalCompiled,
hasCaptureGroupInTargetLabel: strings.Contains(targetLabel, "$"),
hasCaptureGroupInReplacement: strings.Contains(replacement, "$"),
})
return dst, nil
}, nil
}

View file

@ -7,12 +7,12 @@ import (
func TestLoadRelabelConfigsSuccess(t *testing.T) {
path := "testdata/relabel_configs_valid.yml"
prcs, err := LoadRelabelConfigs(path)
pcs, err := LoadRelabelConfigs(path)
if err != nil {
t.Fatalf("cannot load relabel configs from %q: %s", path, err)
}
if len(prcs) != 9 {
t.Fatalf("unexpected number of relabel configs loaded from %q; got %d; want %d", path, len(prcs), 9)
if n := pcs.Len(); n != 9 {
t.Fatalf("unexpected number of relabel configs loaded from %q; got %d; want %d", path, n, 9)
}
}
@ -23,7 +23,7 @@ func TestLoadRelabelConfigsFailure(t *testing.T) {
if err == nil {
t.Fatalf("expecting non-nil error")
}
if len(rcs) != 0 {
if rcs.Len() != 0 {
t.Fatalf("unexpected non-empty rcs: %#v", rcs)
}
}
@ -36,14 +36,14 @@ func TestLoadRelabelConfigsFailure(t *testing.T) {
}
func TestParseRelabelConfigsSuccess(t *testing.T) {
f := func(rcs []RelabelConfig, prcsExpected []ParsedRelabelConfig) {
f := func(rcs []RelabelConfig, pcsExpected *ParsedConfigs) {
t.Helper()
prcs, err := ParseRelabelConfigs(nil, rcs)
pcs, err := ParseRelabelConfigs(rcs)
if err != nil {
t.Fatalf("unexected error: %s", err)
}
if !reflect.DeepEqual(prcs, prcsExpected) {
t.Fatalf("unexpected prcs; got\n%#v\nwant\n%#v", prcs, prcsExpected)
if !reflect.DeepEqual(pcs, pcsExpected) {
t.Fatalf("unexpected pcs; got\n%#v\nwant\n%#v", pcs, pcsExpected)
}
}
f(nil, nil)
@ -52,16 +52,19 @@ func TestParseRelabelConfigsSuccess(t *testing.T) {
SourceLabels: []string{"foo", "bar"},
TargetLabel: "xxx",
},
}, []ParsedRelabelConfig{
{
SourceLabels: []string{"foo", "bar"},
Separator: ";",
TargetLabel: "xxx",
Regex: defaultRegexForRelabelConfig,
Replacement: "$1",
Action: "replace",
}, &ParsedConfigs{
prcs: []*parsedRelabelConfig{
{
SourceLabels: []string{"foo", "bar"},
Separator: ";",
TargetLabel: "xxx",
Regex: defaultRegexForRelabelConfig,
Replacement: "$1",
Action: "replace",
hasCaptureGroupInReplacement: true,
regexOriginal: defaultOriginalRegexForRelabelConfig,
hasCaptureGroupInReplacement: true,
},
},
})
}
@ -69,12 +72,12 @@ func TestParseRelabelConfigsSuccess(t *testing.T) {
func TestParseRelabelConfigsFailure(t *testing.T) {
f := func(rcs []RelabelConfig) {
t.Helper()
prcs, err := ParseRelabelConfigs(nil, rcs)
pcs, err := ParseRelabelConfigs(rcs)
if err == nil {
t.Fatalf("expecting non-nil error")
}
if len(prcs) > 0 {
t.Fatalf("unexpected non-empty prcs: %#v", prcs)
if pcs.Len() > 0 {
t.Fatalf("unexpected non-empty pcs: %#v", pcs)
}
}
t.Run("invalid-regex", func(t *testing.T) {

View file

@ -12,10 +12,10 @@ import (
xxhash "github.com/cespare/xxhash/v2"
)
// ParsedRelabelConfig contains parsed `relabel_config`.
// parsedRelabelConfig contains parsed `relabel_config`.
//
// See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config
type ParsedRelabelConfig struct {
type parsedRelabelConfig struct {
SourceLabels []string
Separator string
TargetLabel string
@ -24,29 +24,32 @@ type ParsedRelabelConfig struct {
Replacement string
Action string
regexOriginal *regexp.Regexp
hasCaptureGroupInTargetLabel bool
hasCaptureGroupInReplacement bool
}
// 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",
prc.SourceLabels, prc.Separator, prc.TargetLabel, prc.Regex.String(), prc.Modulus, prc.Replacement, prc.Action)
}
// ApplyRelabelConfigs applies prcs to labels starting from the labelsOffset.
// Apply applies pcs to labels starting from the labelsOffset.
//
// If isFinalize is set, then FinalizeLabels is called on the labels[labelsOffset:].
//
// The returned labels at labels[labelsOffset:] are sorted.
func ApplyRelabelConfigs(labels []prompbmarshal.Label, labelsOffset int, prcs []ParsedRelabelConfig, isFinalize bool) []prompbmarshal.Label {
for i := range prcs {
tmp := applyRelabelConfig(labels, labelsOffset, &prcs[i])
if len(tmp) == labelsOffset {
// All the labels have been removed.
return tmp
func (pcs *ParsedConfigs) Apply(labels []prompbmarshal.Label, labelsOffset int, isFinalize bool) []prompbmarshal.Label {
if pcs != nil {
for _, prc := range pcs.prcs {
tmp := prc.apply(labels, labelsOffset)
if len(tmp) == labelsOffset {
// All the labels have been removed.
return tmp
}
labels = tmp
}
labels = tmp
}
labels = removeEmptyLabels(labels, labelsOffset)
if isFinalize {
@ -106,10 +109,10 @@ func FinalizeLabels(dst, src []prompbmarshal.Label) []prompbmarshal.Label {
return dst
}
// applyRelabelConfig applies relabeling according to prc.
// apply applies relabeling according to prc.
//
// See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config
func applyRelabelConfig(labels []prompbmarshal.Label, labelsOffset int, prc *ParsedRelabelConfig) []prompbmarshal.Label {
func (prc *parsedRelabelConfig) apply(labels []prompbmarshal.Label, labelsOffset int) []prompbmarshal.Label {
src := labels[labelsOffset:]
switch prc.Action {
case "replace":
@ -150,22 +153,13 @@ func applyRelabelConfig(labels []prompbmarshal.Label, labelsOffset int, prc *Par
case "replace_all":
bb := relabelBufPool.Get()
bb.B = concatLabelValues(bb.B[:0], src, prc.SourceLabels, prc.Separator)
if prefix, complete := prc.Regex.LiteralPrefix(); complete && !prc.hasCaptureGroupInReplacement {
// Fast path - string replacement without regexp.
sourceStr := string(bb.B)
relabelBufPool.Put(bb)
valueStr := strings.ReplaceAll(sourceStr, prefix, prc.Replacement)
return setLabelValue(labels, labelsOffset, prc.TargetLabel, valueStr)
}
if !prc.Regex.Match(bb.B) {
// Fast path - nothing to replace.
relabelBufPool.Put(bb)
return labels
}
sourceStr := string(bb.B) // Make a copy of bb, since it can be returned from ReplaceAllString
sourceStr := string(bb.B)
relabelBufPool.Put(bb)
valueStr := prc.Regex.ReplaceAllString(sourceStr, prc.Replacement)
return setLabelValue(labels, labelsOffset, prc.TargetLabel, valueStr)
valueStr, ok := prc.replaceStringSubmatches(sourceStr, prc.Replacement, prc.hasCaptureGroupInReplacement)
if ok {
labels = setLabelValue(labels, labelsOffset, prc.TargetLabel, valueStr)
}
return labels
case "keep_if_equal":
// Keep the entry if all the label values in source_labels are equal.
// For example:
@ -193,14 +187,7 @@ func applyRelabelConfig(labels []prompbmarshal.Label, labelsOffset int, prc *Par
case "keep":
bb := relabelBufPool.Get()
bb.B = concatLabelValues(bb.B[:0], src, prc.SourceLabels, prc.Separator)
keep := false
if prefix, complete := prc.Regex.LiteralPrefix(); complete {
// Fast path - simple string match
keep = prefix == string(bb.B)
} else {
// Slow path - match by regexp
keep = prc.Regex.Match(bb.B)
}
keep := prc.matchString(bytesutil.ToUnsafeString(bb.B))
relabelBufPool.Put(bb)
if !keep {
return labels[:labelsOffset]
@ -209,14 +196,7 @@ func applyRelabelConfig(labels []prompbmarshal.Label, labelsOffset int, prc *Par
case "drop":
bb := relabelBufPool.Get()
bb.B = concatLabelValues(bb.B[:0], src, prc.SourceLabels, prc.Separator)
drop := false
if prefix, complete := prc.Regex.LiteralPrefix(); complete {
// Fast path - simple string match
drop = prefix == string(bb.B)
} else {
// Slow path - match by regexp
drop = prc.Regex.Match(bb.B)
}
drop := prc.matchString(bytesutil.ToUnsafeString(bb.B))
relabelBufPool.Put(bb)
if drop {
return labels[:labelsOffset]
@ -232,42 +212,23 @@ func applyRelabelConfig(labels []prompbmarshal.Label, labelsOffset int, prc *Par
case "labelmap":
for i := range src {
label := &src[i]
match := prc.Regex.FindStringSubmatchIndex(label.Name)
if match == nil {
continue
labelName, ok := prc.replaceFullString(label.Name, prc.Replacement, prc.hasCaptureGroupInReplacement)
if ok {
labels = setLabelValue(labels, labelsOffset, labelName, label.Value)
}
value := relabelBufPool.Get()
value.B = prc.Regex.ExpandString(value.B[:0], prc.Replacement, label.Name, match)
labelName := string(value.B)
relabelBufPool.Put(value)
labels = setLabelValue(labels, labelsOffset, labelName, label.Value)
}
return labels
case "labelmap_all":
for i := range src {
label := &src[i]
if prefix, complete := prc.Regex.LiteralPrefix(); complete && !prc.hasCaptureGroupInReplacement {
// Fast path - replace without regexp
label.Name = strings.ReplaceAll(label.Name, prefix, prc.Replacement)
} else {
// Slow path - replace with regexp.
if !prc.Regex.MatchString(label.Name) {
continue
}
label.Name = prc.Regex.ReplaceAllString(label.Name, prc.Replacement)
}
label.Name, _ = prc.replaceStringSubmatches(label.Name, prc.Replacement, prc.hasCaptureGroupInReplacement)
}
return labels
case "labeldrop":
keepSrc := true
for i := range src {
label := &src[i]
if prefix, complete := prc.Regex.LiteralPrefix(); complete {
if prefix == label.Name {
keepSrc = false
break
}
} else if prc.Regex.MatchString(label.Name) {
if prc.matchString(label.Name) {
keepSrc = false
break
}
@ -278,11 +239,7 @@ func applyRelabelConfig(labels []prompbmarshal.Label, labelsOffset int, prc *Par
dst := labels[:labelsOffset]
for i := range src {
label := &src[i]
if prefix, complete := prc.Regex.LiteralPrefix(); complete {
if prefix != label.Name {
dst = append(dst, *label)
}
} else if !prc.Regex.MatchString(label.Name) {
if !prc.matchString(label.Name) {
dst = append(dst, *label)
}
}
@ -291,12 +248,7 @@ func applyRelabelConfig(labels []prompbmarshal.Label, labelsOffset int, prc *Par
keepSrc := true
for i := range src {
label := &src[i]
if prefix, complete := prc.Regex.LiteralPrefix(); complete {
if prefix != label.Name {
keepSrc = false
break
}
} else if !prc.Regex.MatchString(src[i].Name) {
if !prc.matchString(label.Name) {
keepSrc = false
break
}
@ -307,11 +259,7 @@ func applyRelabelConfig(labels []prompbmarshal.Label, labelsOffset int, prc *Par
dst := labels[:labelsOffset]
for i := range src {
label := &src[i]
if prefix, complete := prc.Regex.LiteralPrefix(); complete {
if prefix == label.Name {
dst = append(dst, *label)
}
} else if prc.Regex.MatchString(label.Name) {
if prc.matchString(label.Name) {
dst = append(dst, *label)
}
}
@ -322,7 +270,74 @@ func applyRelabelConfig(labels []prompbmarshal.Label, labelsOffset int, prc *Par
}
}
func (prc *ParsedRelabelConfig) expandCaptureGroups(template, source string, match []int) string {
func (prc *parsedRelabelConfig) replaceFullString(s, replacement string, hasCaptureGroupInReplacement bool) (string, bool) {
prefix, complete := prc.regexOriginal.LiteralPrefix()
if complete && !hasCaptureGroupInReplacement {
if s == prefix {
return replacement, true
}
return s, false
}
if !strings.HasPrefix(s, prefix) {
return s, false
}
if replacement == "$1" {
// Fast path for commonly used rule for deleting label prefixes such as:
//
// - action: labelmap
// regex: __meta_kubernetes_node_label_(.+)
//
reStr := prc.regexOriginal.String()
if strings.HasPrefix(reStr, prefix) {
suffix := s[len(prefix):]
reSuffix := reStr[len(prefix):]
switch reSuffix {
case "(.*)":
return suffix, true
case "(.+)":
if len(suffix) > 0 {
return suffix, true
}
return s, false
}
}
}
// Slow path - regexp processing
match := prc.Regex.FindStringSubmatchIndex(s)
if match == nil {
return s, false
}
bb := relabelBufPool.Get()
bb.B = prc.Regex.ExpandString(bb.B[:0], replacement, s, match)
result := string(bb.B)
relabelBufPool.Put(bb)
return result, true
}
func (prc *parsedRelabelConfig) replaceStringSubmatches(s, replacement string, hasCaptureGroupInReplacement bool) (string, bool) {
re := prc.regexOriginal
prefix, complete := re.LiteralPrefix()
if complete && !hasCaptureGroupInReplacement {
if !strings.Contains(s, prefix) {
return s, false
}
return strings.ReplaceAll(s, prefix, replacement), true
}
if !re.MatchString(s) {
return s, false
}
return re.ReplaceAllString(s, replacement), true
}
func (prc *parsedRelabelConfig) matchString(s string) bool {
prefix, complete := prc.regexOriginal.LiteralPrefix()
if complete {
return prefix == s
}
return strings.HasPrefix(s, prefix) && prc.Regex.MatchString(s)
}
func (prc *parsedRelabelConfig) expandCaptureGroups(template, source string, match []int) string {
bb := relabelBufPool.Get()
bb.B = prc.Regex.ExpandString(bb.B[:0], template, source, match)
s := string(bb.B)

View file

@ -2,24 +2,27 @@ package promrelabel
import (
"reflect"
"regexp"
"testing"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
)
func TestApplyRelabelConfigs(t *testing.T) {
f := func(prcs []ParsedRelabelConfig, labels []prompbmarshal.Label, isFinalize bool, resultExpected []prompbmarshal.Label) {
f := func(config string, labels []prompbmarshal.Label, isFinalize bool, resultExpected []prompbmarshal.Label) {
t.Helper()
result := ApplyRelabelConfigs(labels, 0, prcs, isFinalize)
pcs, err := ParseRelabelConfigsData([]byte(config))
if err != nil {
t.Fatalf("cannot parse %q: %s", config, err)
}
result := pcs.Apply(labels, 0, isFinalize)
if !reflect.DeepEqual(result, resultExpected) {
t.Fatalf("unexpected result; got\n%v\nwant\n%v", result, resultExpected)
}
}
t.Run("empty_relabel_configs", func(t *testing.T) {
f(nil, nil, false, nil)
f(nil, nil, true, nil)
f(nil, []prompbmarshal.Label{
f("", nil, false, nil)
f("", nil, true, nil)
f("", []prompbmarshal.Label{
{
Name: "foo",
Value: "bar",
@ -30,7 +33,7 @@ func TestApplyRelabelConfigs(t *testing.T) {
Value: "bar",
},
})
f(nil, []prompbmarshal.Label{
f("", []prompbmarshal.Label{
{
Name: "foo",
Value: "bar",
@ -55,35 +58,20 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("replace-miss", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "replace",
TargetLabel: "bar",
Regex: defaultRegexForRelabelConfig,
Replacement: "$1",
hasCaptureGroupInReplacement: true,
},
}, nil, false, []prompbmarshal.Label{})
f([]ParsedRelabelConfig{
{
Action: "replace",
SourceLabels: []string{"foo"},
TargetLabel: "bar",
Regex: defaultRegexForRelabelConfig,
Replacement: "$1",
hasCaptureGroupInReplacement: true,
},
}, nil, false, []prompbmarshal.Label{})
f([]ParsedRelabelConfig{
{
Action: "replace",
SourceLabels: []string{"foo"},
TargetLabel: "bar",
Regex: defaultRegexForRelabelConfig,
Replacement: "$1",
hasCaptureGroupInReplacement: true,
},
}, []prompbmarshal.Label{
f(`
- action: replace
target_label: bar
`, nil, false, []prompbmarshal.Label{})
f(`
- action: replace
source_labels: ["foo"]
target_label: bar
`, nil, false, []prompbmarshal.Label{})
f(`
- action: replace
source_labels: ["foo"]
target_label: "bar"
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "yyy",
@ -94,16 +82,12 @@ func TestApplyRelabelConfigs(t *testing.T) {
Value: "yyy",
},
})
f([]ParsedRelabelConfig{
{
Action: "replace",
SourceLabels: []string{"foo"},
TargetLabel: "bar",
Regex: regexp.MustCompile(".+"),
Replacement: "$1",
hasCaptureGroupInReplacement: true,
},
}, []prompbmarshal.Label{
f(`
- action: replace
source_labels: ["foo"]
target_label: "bar"
regex: ".+"
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "yyy",
@ -116,17 +100,12 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("replace-hit", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "replace",
SourceLabels: []string{"xxx", "foo"},
Separator: ";",
TargetLabel: "bar",
Regex: defaultRegexForRelabelConfig,
Replacement: "a-$1-b",
hasCaptureGroupInReplacement: true,
},
}, []prompbmarshal.Label{
f(`
- action: replace
source_labels: ["xxx", "foo"]
target_label: "bar"
replacement: "a-$1-b"
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "yyy",
@ -143,18 +122,12 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("replace-hit-target-label-with-capture-group", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "replace",
SourceLabels: []string{"xxx", "foo"},
Separator: ";",
TargetLabel: "bar-$1",
Regex: defaultRegexForRelabelConfig,
Replacement: "a-$1-b",
hasCaptureGroupInTargetLabel: true,
hasCaptureGroupInReplacement: true,
},
}, []prompbmarshal.Label{
f(`
- action: replace
source_labels: ["xxx", "foo"]
target_label: "bar-$1"
replacement: "a-$1-b"
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "yyy",
@ -171,35 +144,21 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("replace_all-miss", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "replace_all",
TargetLabel: "bar",
Regex: defaultRegexForRelabelConfig,
Replacement: "$1",
hasCaptureGroupInReplacement: true,
},
}, nil, false, []prompbmarshal.Label{})
f([]ParsedRelabelConfig{
{
Action: "replace_all",
SourceLabels: []string{"foo"},
TargetLabel: "bar",
Regex: defaultRegexForRelabelConfig,
Replacement: "$1",
hasCaptureGroupInReplacement: true,
},
}, nil, false, []prompbmarshal.Label{})
f([]ParsedRelabelConfig{
{
Action: "replace_all",
SourceLabels: []string{"foo"},
TargetLabel: "bar",
Regex: defaultRegexForRelabelConfig,
Replacement: "$1",
hasCaptureGroupInReplacement: true,
},
}, []prompbmarshal.Label{
f(`
- action: replace_all
source_labels: [foo]
target_label: "bar"
`, nil, false, []prompbmarshal.Label{})
f(`
- action: replace_all
source_labels: ["foo"]
target_label: "bar"
`, nil, false, []prompbmarshal.Label{})
f(`
- action: replace_all
source_labels: ["foo"]
target_label: "bar"
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "yyy",
@ -210,16 +169,12 @@ func TestApplyRelabelConfigs(t *testing.T) {
Value: "yyy",
},
})
f([]ParsedRelabelConfig{
{
Action: "replace_all",
SourceLabels: []string{"foo"},
TargetLabel: "bar",
Regex: regexp.MustCompile(".+"),
Replacement: "$1",
hasCaptureGroupInReplacement: true,
},
}, []prompbmarshal.Label{
f(`
- action: replace_all
source_labels: ["foo"]
target_label: "bar"
regex: ".+"
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "yyy",
@ -232,16 +187,13 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("replace_all-hit", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "replace_all",
SourceLabels: []string{"xxx"},
Separator: ";",
TargetLabel: "xxx",
Regex: regexp.MustCompile("-"),
Replacement: ".",
},
}, []prompbmarshal.Label{
f(`
- action: replace_all
source_labels: ["xxx"]
target_label: "xxx"
regex: "-"
replacement: "."
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "a-b-c",
@ -254,17 +206,13 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("replace_all-regex-hit", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "replace_all",
SourceLabels: []string{"xxx", "foo"},
Separator: ";",
TargetLabel: "xxx",
Regex: regexp.MustCompile("(;)"),
Replacement: "-$1-",
hasCaptureGroupInReplacement: true,
},
}, []prompbmarshal.Label{
f(`
- action: replace_all
source_labels: ["xxx", "foo"]
target_label: "xxx"
regex: "(;)"
replacement: "-$1-"
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "y;y",
@ -277,24 +225,16 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("replace-add-multi-labels", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "replace",
SourceLabels: []string{"xxx"},
TargetLabel: "bar",
Regex: defaultRegexForRelabelConfig,
Replacement: "a-$1",
hasCaptureGroupInReplacement: true,
},
{
Action: "replace",
SourceLabels: []string{"bar"},
TargetLabel: "zar",
Regex: defaultRegexForRelabelConfig,
Replacement: "b-$1",
hasCaptureGroupInReplacement: true,
},
}, []prompbmarshal.Label{
f(`
- action: replace
source_labels: ["xxx"]
target_label: "bar"
replacement: "a-$1"
- action: replace
source_labels: ["bar"]
target_label: "zar"
replacement: "b-$1"
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "yyy",
@ -323,16 +263,12 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("replace-self", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "replace",
SourceLabels: []string{"foo"},
TargetLabel: "foo",
Regex: defaultRegexForRelabelConfig,
Replacement: "a-$1",
hasCaptureGroupInReplacement: true,
},
}, []prompbmarshal.Label{
f(`
- action: replace
source_labels: ["foo"]
target_label: "foo"
replacement: "a-$1"
`, []prompbmarshal.Label{
{
Name: "foo",
Value: "aaxx",
@ -345,14 +281,11 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("replace-missing-source", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "replace",
TargetLabel: "foo",
Regex: defaultRegexForRelabelConfig,
Replacement: "foobar",
},
}, []prompbmarshal.Label{}, true, []prompbmarshal.Label{
f(`
- action: replace
target_label: foo
replacement: "foobar"
`, []prompbmarshal.Label{}, true, []prompbmarshal.Label{
{
Name: "foo",
Value: "foobar",
@ -360,18 +293,14 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("keep_if_equal-miss", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "keep_if_equal",
SourceLabels: []string{"foo", "bar"},
},
}, nil, true, nil)
f([]ParsedRelabelConfig{
{
Action: "keep_if_equal",
SourceLabels: []string{"xxx", "bar"},
},
}, []prompbmarshal.Label{
f(`
- action: keep_if_equal
source_labels: ["foo", "bar"]
`, nil, true, nil)
f(`
- action: keep_if_equal
source_labels: ["xxx", "bar"]
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "yyy",
@ -379,12 +308,10 @@ func TestApplyRelabelConfigs(t *testing.T) {
}, true, []prompbmarshal.Label{})
})
t.Run("keep_if_equal-hit", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "keep_if_equal",
SourceLabels: []string{"xxx", "bar"},
},
}, []prompbmarshal.Label{
f(`
- action: keep_if_equal
source_labels: ["xxx", "bar"]
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "yyy",
@ -405,18 +332,14 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("drop_if_equal-miss", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "drop_if_equal",
SourceLabels: []string{"foo", "bar"},
},
}, nil, true, nil)
f([]ParsedRelabelConfig{
{
Action: "drop_if_equal",
SourceLabels: []string{"xxx", "bar"},
},
}, []prompbmarshal.Label{
f(`
- action: drop_if_equal
source_labels: ["foo", "bar"]
`, nil, true, nil)
f(`
- action: drop_if_equal
source_labels: ["xxx", "bar"]
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "yyy",
@ -429,12 +352,10 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("drop_if_equal-hit", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "drop_if_equal",
SourceLabels: []string{"xxx", "bar"},
},
}, []prompbmarshal.Label{
f(`
- action: drop_if_equal
source_labels: [xxx, bar]
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "yyy",
@ -446,20 +367,16 @@ func TestApplyRelabelConfigs(t *testing.T) {
}, true, []prompbmarshal.Label{})
})
t.Run("keep-miss", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "keep",
SourceLabels: []string{"foo"},
Regex: regexp.MustCompile(".+"),
},
}, nil, true, nil)
f([]ParsedRelabelConfig{
{
Action: "keep",
SourceLabels: []string{"foo"},
Regex: regexp.MustCompile(".+"),
},
}, []prompbmarshal.Label{
f(`
- action: keep
source_labels: [foo]
regex: ".+"
`, nil, true, nil)
f(`
- action: keep
source_labels: [foo]
regex: ".+"
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "yyy",
@ -467,13 +384,11 @@ func TestApplyRelabelConfigs(t *testing.T) {
}, true, []prompbmarshal.Label{})
})
t.Run("keep-hit", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "keep",
SourceLabels: []string{"foo"},
Regex: regexp.MustCompile("yyy"),
},
}, []prompbmarshal.Label{
f(`
- action: keep
source_labels: [foo]
regex: "yyy"
`, []prompbmarshal.Label{
{
Name: "foo",
Value: "yyy",
@ -486,13 +401,11 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("keep-hit-regexp", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "keep",
SourceLabels: []string{"foo"},
Regex: regexp.MustCompile(".+"),
},
}, []prompbmarshal.Label{
f(`
- action: keep
source_labels: ["foo"]
regex: ".+"
`, []prompbmarshal.Label{
{
Name: "foo",
Value: "yyy",
@ -505,20 +418,16 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("drop-miss", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "drop",
SourceLabels: []string{"foo"},
Regex: regexp.MustCompile(".+"),
},
}, nil, false, nil)
f([]ParsedRelabelConfig{
{
Action: "drop",
SourceLabels: []string{"foo"},
Regex: regexp.MustCompile(".+"),
},
}, []prompbmarshal.Label{
f(`
- action: drop
source_labels: [foo]
regex: ".+"
`, nil, false, nil)
f(`
- action: drop
source_labels: [foo]
regex: ".+"
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "yyy",
@ -531,13 +440,11 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("drop-hit", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "drop",
SourceLabels: []string{"foo"},
Regex: regexp.MustCompile("yyy"),
},
}, []prompbmarshal.Label{
f(`
- action: drop
source_labels: [foo]
regex: yyy
`, []prompbmarshal.Label{
{
Name: "foo",
Value: "yyy",
@ -545,13 +452,11 @@ func TestApplyRelabelConfigs(t *testing.T) {
}, true, []prompbmarshal.Label{})
})
t.Run("drop-hit-regexp", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "drop",
SourceLabels: []string{"foo"},
Regex: regexp.MustCompile(".+"),
},
}, []prompbmarshal.Label{
f(`
- action: drop
source_labels: [foo]
regex: ".+"
`, []prompbmarshal.Label{
{
Name: "foo",
Value: "yyy",
@ -559,14 +464,12 @@ func TestApplyRelabelConfigs(t *testing.T) {
}, true, []prompbmarshal.Label{})
})
t.Run("hashmod-miss", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "hashmod",
SourceLabels: []string{"foo"},
TargetLabel: "aaa",
Modulus: 123,
},
}, []prompbmarshal.Label{
f(`
- action: hashmod
source_labels: [foo]
target_label: aaa
modulus: 123
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "yyy",
@ -583,14 +486,12 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("hashmod-hit", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "hashmod",
SourceLabels: []string{"foo"},
TargetLabel: "aaa",
Modulus: 123,
},
}, []prompbmarshal.Label{
f(`
- action: hashmod
source_labels: [foo]
target_label: aaa
modulus: 123
`, []prompbmarshal.Label{
{
Name: "foo",
Value: "yyy",
@ -606,14 +507,97 @@ func TestApplyRelabelConfigs(t *testing.T) {
},
})
})
t.Run("labelmap", func(t *testing.T) {
f([]ParsedRelabelConfig{
t.Run("labelmap-copy-label", func(t *testing.T) {
f(`
- action: labelmap
regex: "foo"
replacement: "bar"
`, []prompbmarshal.Label{
{
Action: "labelmap",
Regex: regexp.MustCompile("foo(.+)"),
Replacement: "$1-x",
Name: "foo",
Value: "yyy",
},
}, []prompbmarshal.Label{
{
Name: "foobar",
Value: "aaa",
},
}, true, []prompbmarshal.Label{
{
Name: "bar",
Value: "yyy",
},
{
Name: "foo",
Value: "yyy",
},
{
Name: "foobar",
Value: "aaa",
},
})
})
t.Run("labelmap-remove-prefix-dot-star", func(t *testing.T) {
f(`
- action: labelmap
regex: "foo(.*)"
`, []prompbmarshal.Label{
{
Name: "xoo",
Value: "yyy",
},
{
Name: "foobar",
Value: "aaa",
},
}, true, []prompbmarshal.Label{
{
Name: "bar",
Value: "aaa",
},
{
Name: "foobar",
Value: "aaa",
},
{
Name: "xoo",
Value: "yyy",
},
})
})
t.Run("labelmap-remove-prefix-dot-plus", func(t *testing.T) {
f(`
- action: labelmap
regex: "foo(.+)"
`, []prompbmarshal.Label{
{
Name: "foo",
Value: "yyy",
},
{
Name: "foobar",
Value: "aaa",
},
}, true, []prompbmarshal.Label{
{
Name: "bar",
Value: "aaa",
},
{
Name: "foo",
Value: "yyy",
},
{
Name: "foobar",
Value: "aaa",
},
})
})
t.Run("labelmap-regex", func(t *testing.T) {
f(`
- action: labelmap
regex: "foo(.+)"
replacement: "$1-x"
`, []prompbmarshal.Label{
{
Name: "foo",
Value: "yyy",
@ -638,13 +622,11 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("labelmap_all", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "labelmap_all",
Regex: regexp.MustCompile(`\.`),
Replacement: "-",
},
}, []prompbmarshal.Label{
f(`
- action: labelmap_all
regex: "\\."
replacement: "-"
`, []prompbmarshal.Label{
{
Name: "foo.bar.baz",
Value: "yyy",
@ -665,13 +647,11 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("labelmap_all-regexp", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "labelmap_all",
Regex: regexp.MustCompile(`ba(.)`),
Replacement: "${1}ss",
},
}, []prompbmarshal.Label{
f(`
- action: labelmap_all
regex: "ba(.)"
replacement: "${1}ss"
`, []prompbmarshal.Label{
{
Name: "foo.bar.baz",
Value: "yyy",
@ -692,12 +672,10 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("labeldrop", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "labeldrop",
Regex: regexp.MustCompile("dropme"),
},
}, []prompbmarshal.Label{
f(`
- action: labeldrop
regex: dropme
`, []prompbmarshal.Label{
{
Name: "aaa",
Value: "bbb",
@ -708,12 +686,10 @@ func TestApplyRelabelConfigs(t *testing.T) {
Value: "bbb",
},
})
f([]ParsedRelabelConfig{
{
Action: "labeldrop",
Regex: regexp.MustCompile("dropme"),
},
}, []prompbmarshal.Label{
f(`
- action: labeldrop
regex: dropme
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "yyy",
@ -738,12 +714,10 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("labeldrop-regexp", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "labeldrop",
Regex: regexp.MustCompile("dropme.*"),
},
}, []prompbmarshal.Label{
f(`
- action: labeldrop
regex: "dropme.*"
`, []prompbmarshal.Label{
{
Name: "aaa",
Value: "bbb",
@ -754,12 +728,10 @@ func TestApplyRelabelConfigs(t *testing.T) {
Value: "bbb",
},
})
f([]ParsedRelabelConfig{
{
Action: "labeldrop",
Regex: regexp.MustCompile("dropme.*"),
},
}, []prompbmarshal.Label{
f(`
- action: labeldrop
regex: "dropme.*"
`, []prompbmarshal.Label{
{
Name: "xxx",
Value: "yyy",
@ -784,12 +756,10 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("labelkeep", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "labelkeep",
Regex: regexp.MustCompile("keepme"),
},
}, []prompbmarshal.Label{
f(`
- action: labelkeep
regex: "keepme"
`, []prompbmarshal.Label{
{
Name: "keepme",
Value: "aaa",
@ -800,12 +770,10 @@ func TestApplyRelabelConfigs(t *testing.T) {
Value: "aaa",
},
})
f([]ParsedRelabelConfig{
{
Action: "labelkeep",
Regex: regexp.MustCompile("keepme"),
},
}, []prompbmarshal.Label{
f(`
- action: labelkeep
regex: keepme
`, []prompbmarshal.Label{
{
Name: "keepme",
Value: "aaa",
@ -826,12 +794,10 @@ func TestApplyRelabelConfigs(t *testing.T) {
})
})
t.Run("labelkeep-regexp", func(t *testing.T) {
f([]ParsedRelabelConfig{
{
Action: "labelkeep",
Regex: regexp.MustCompile("keepme.*"),
},
}, []prompbmarshal.Label{
f(`
- action: labelkeep
regex: "keepme.*"
`, []prompbmarshal.Label{
{
Name: "keepme",
Value: "aaa",
@ -842,12 +808,10 @@ func TestApplyRelabelConfigs(t *testing.T) {
Value: "aaa",
},
})
f([]ParsedRelabelConfig{
{
Action: "labelkeep",
Regex: regexp.MustCompile("keepme.*"),
},
}, []prompbmarshal.Label{
f(`
- action: labelkeep
regex: "keepme.*"
`, []prompbmarshal.Label{
{
Name: "keepme",
Value: "aaa",

View file

@ -2,7 +2,6 @@ package promrelabel
import (
"fmt"
"regexp"
"testing"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
@ -10,15 +9,11 @@ import (
func BenchmarkApplyRelabelConfigs(b *testing.B) {
b.Run("replace-label-copy", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "replace",
SourceLabels: []string{"id"},
TargetLabel: "__name__",
Regex: defaultRegexForRelabelConfig,
Replacement: "$1",
},
}
pcs := mustParseRelabelConfigs(`
- action: replace
source_labels: [id]
target_label: __name__
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -35,7 +30,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels))
}
@ -55,14 +50,11 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
})
})
b.Run("replace-set-label", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "replace",
TargetLabel: "__name__",
Regex: defaultRegexForRelabelConfig,
Replacement: "foobar",
},
}
pcs := mustParseRelabelConfigs(`
- action: replace
target_label: __name__
replacement: foobar
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -79,7 +71,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels))
}
@ -99,14 +91,11 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
})
})
b.Run("replace-add-label", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "replace",
TargetLabel: "aaa",
Regex: defaultRegexForRelabelConfig,
Replacement: "foobar",
},
}
pcs := mustParseRelabelConfigs(`
- action: replace
target_label: aaa
replacement: foobar
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -119,7 +108,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != 2 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 2, labels))
}
@ -139,15 +128,12 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
})
})
b.Run("replace-mismatch", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "replace",
SourceLabels: []string{"non-existing-label"},
TargetLabel: "id",
Regex: regexp.MustCompile("(foobar)-.*"),
Replacement: "$1",
},
}
pcs := mustParseRelabelConfigs(`
- action: replace
source_labels: ["non-existing-label"]
target_label: id
regex: "(foobar)-.*"
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -164,7 +150,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels))
}
@ -184,15 +170,12 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
})
})
b.Run("replace-match-regex", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "replace",
SourceLabels: []string{"id"},
TargetLabel: "id",
Regex: regexp.MustCompile("(foobar)-.*"),
Replacement: "$1",
},
}
pcs := mustParseRelabelConfigs(`
- action: replace
source_labels: [id]
target_label: id
regex: "(foobar)-.*"
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -209,7 +192,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels))
}
@ -229,13 +212,11 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
})
})
b.Run("drop-mismatch", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "drop",
SourceLabels: []string{"non-existing-label"},
Regex: regexp.MustCompile("(foobar)-.*"),
},
}
pcs := mustParseRelabelConfigs(`
- action: drop
source_labels: ["non-existing-label"]
regex: "(foobar)-.*"
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -252,7 +233,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels))
}
@ -272,13 +253,11 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
})
})
b.Run("drop-match", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "drop",
SourceLabels: []string{"id"},
Regex: regexp.MustCompile("yes"),
},
}
pcs := mustParseRelabelConfigs(`
- action: drop
source_labels: [id]
regex: yes
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -295,7 +274,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != 0 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 0, labels))
}
@ -303,13 +282,11 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
})
})
b.Run("drop-match-regexp", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "drop",
SourceLabels: []string{"id"},
Regex: regexp.MustCompile("(foobar)-.*"),
},
}
pcs := mustParseRelabelConfigs(`
- action: drop
source_labels: [id]
regex: "(foobar)-.*"
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -326,7 +303,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != 0 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 0, labels))
}
@ -334,13 +311,11 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
})
})
b.Run("keep-mismatch", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "keep",
SourceLabels: []string{"non-existing-label"},
Regex: regexp.MustCompile("(foobar)-.*"),
},
}
pcs := mustParseRelabelConfigs(`
- action: keep
source_labels: ["non-existing-label"]
regex: "(foobar)-.*"
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -357,7 +332,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != 0 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 0, labels))
}
@ -365,13 +340,11 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
})
})
b.Run("keep-match", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "keep",
SourceLabels: []string{"id"},
Regex: regexp.MustCompile("yes"),
},
}
pcs := mustParseRelabelConfigs(`
- action: keep
source_labels: [id]
regex: yes
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -388,7 +361,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels))
}
@ -408,13 +381,11 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
})
})
b.Run("keep-match-regexp", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "keep",
SourceLabels: []string{"id"},
Regex: regexp.MustCompile("(foobar)-.*"),
},
}
pcs := mustParseRelabelConfigs(`
- action: keep
source_labels: [id]
regex: "(foobar)-.*"
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -431,7 +402,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels))
}
@ -451,12 +422,10 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
})
})
b.Run("labeldrop-mismatch", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "labeldrop",
Regex: regexp.MustCompile("non-existing-label"),
},
}
pcs := mustParseRelabelConfigs(`
- action: labeldrop
regex: "non-existing-label"
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -473,7 +442,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels))
}
@ -493,12 +462,10 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
})
})
b.Run("labeldrop-match", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "labeldrop",
Regex: regexp.MustCompile("id"),
},
}
pcs := mustParseRelabelConfigs(`
- action: labeldrop
regex: id
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -515,7 +482,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != 1 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 1, labels))
}
@ -529,12 +496,10 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
})
})
b.Run("labeldrop-match-regexp", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "labeldrop",
Regex: regexp.MustCompile("id.*"),
},
}
pcs := mustParseRelabelConfigs(`
- action: labeldrop
regex: "id.*"
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -551,7 +516,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != 1 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 1, labels))
}
@ -565,12 +530,10 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
})
})
b.Run("labelkeep-mismatch", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "labelkeep",
Regex: regexp.MustCompile("non-existing-label"),
},
}
pcs := mustParseRelabelConfigs(`
- action: labelkeep
regex: "non-existing-label"
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -587,7 +550,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != 0 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 0, labels))
}
@ -595,12 +558,10 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
})
})
b.Run("labelkeep-match", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "labelkeep",
Regex: regexp.MustCompile("id"),
},
}
pcs := mustParseRelabelConfigs(`
- action: labelkeep
regex: id
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -617,7 +578,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != 1 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 1, labels))
}
@ -631,12 +592,10 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
})
})
b.Run("labelkeep-match-regexp", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "labelkeep",
Regex: regexp.MustCompile("id.*"),
},
}
pcs := mustParseRelabelConfigs(`
- action: labelkeep
regex: "id.*"
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -653,7 +612,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != 1 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 1, labels))
}
@ -666,19 +625,12 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
}
})
})
b.Run("labelmap", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "labelmap",
Regex: regexp.MustCompile("a(.*)"),
Replacement: "$1",
},
}
b.Run("labelmap-mismatch", func(b *testing.B) {
pcs := mustParseRelabelConfigs(`
- action: labelmap
regex: "a(.*)"
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "aabc",
Value: "foobar-random-string-here",
},
{
Name: "foo",
Value: "bar",
@ -690,8 +642,38 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
if len(labels) != 3 {
labels = pcs.Apply(labels, 0, true)
if len(labels) != 1 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 3, labels))
}
if labels[0].Name != "foo" {
panic(fmt.Errorf("unexpected label name; got %q; want %q", labels[0].Name, "foo"))
}
if labels[0].Value != "bar" {
panic(fmt.Errorf("unexpected label value; got %q; want %q", labels[0].Value, "bar"))
}
}
})
})
b.Run("labelmap-match-remove-prefix", func(b *testing.B) {
pcs := mustParseRelabelConfigs(`
- action: labelmap
regex: "a(.*)"
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "aabc",
Value: "foobar-random-string-here",
},
}
b.ReportAllocs()
b.SetBytes(1)
b.RunParallel(func(pb *testing.PB) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = pcs.Apply(labels, 0, true)
if len(labels) != 2 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 3, labels))
}
if labels[0].Name != "aabc" {
@ -706,24 +688,52 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
if labels[1].Value != "foobar-random-string-here" {
panic(fmt.Errorf("unexpected label value; got %q; want %q", labels[1].Value, "foobar-random-string-here"))
}
if labels[2].Name != "foo" {
panic(fmt.Errorf("unexpected label name; got %q; want %q", labels[2].Name, "foo"))
}
})
})
b.Run("labelmap-match-regexp", func(b *testing.B) {
pcs := mustParseRelabelConfigs(`
- action: labelmap
regex: "(.*)bc"
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "aabc",
Value: "foobar-random-string-here",
},
}
b.ReportAllocs()
b.SetBytes(1)
b.RunParallel(func(pb *testing.PB) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = pcs.Apply(labels, 0, true)
if len(labels) != 2 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 3, labels))
}
if labels[2].Value != "bar" {
panic(fmt.Errorf("unexpected label value; got %q; want %q", labels[2].Value, "bar"))
if labels[0].Name != "aa" {
panic(fmt.Errorf("unexpected label name; got %q; want %q", labels[0].Name, "aa"))
}
if labels[0].Value != "foobar-random-string-here" {
panic(fmt.Errorf("unexpected label value; got %q; want %q", labels[0].Value, "foobar-random-string-here"))
}
if labels[1].Name != "aabc" {
panic(fmt.Errorf("unexpected label name; got %q; want %q", labels[1].Name, "aabc"))
}
if labels[1].Value != "foobar-random-string-here" {
panic(fmt.Errorf("unexpected label value; got %q; want %q", labels[1].Value, "foobar-random-string-here"))
}
}
})
})
b.Run("hashmod", func(b *testing.B) {
prcs := []ParsedRelabelConfig{
{
Action: "hashmod",
SourceLabels: []string{"id"},
TargetLabel: "id",
Modulus: 23,
},
}
pcs := mustParseRelabelConfigs(`
- action: hashmod
source_labels: [id]
target_label: id
modulus: 23
`)
labelsOrig := []prompbmarshal.Label{
{
Name: "__name__",
@ -740,7 +750,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label
for pb.Next() {
labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true)
labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels))
}
@ -760,3 +770,11 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
})
})
}
func mustParseRelabelConfigs(config string) *ParsedConfigs {
pcs, err := ParseRelabelConfigsData([]byte(config))
if err != nil {
panic(fmt.Errorf("unexpected error: %w", err))
}
return pcs
}

View file

@ -482,13 +482,11 @@ func getScrapeWorkConfig(sc *ScrapeConfig, baseDir string, globalCfg *GlobalConf
if err != nil {
return nil, fmt.Errorf("cannot parse auth config for `job_name` %q: %w", jobName, err)
}
var relabelConfigs []promrelabel.ParsedRelabelConfig
relabelConfigs, err = promrelabel.ParseRelabelConfigs(relabelConfigs[:0], sc.RelabelConfigs)
relabelConfigs, err := promrelabel.ParseRelabelConfigs(sc.RelabelConfigs)
if err != nil {
return nil, fmt.Errorf("cannot parse `relabel_configs` for `job_name` %q: %w", jobName, err)
}
var metricRelabelConfigs []promrelabel.ParsedRelabelConfig
metricRelabelConfigs, err = promrelabel.ParseRelabelConfigs(metricRelabelConfigs[:0], sc.MetricRelabelConfigs)
metricRelabelConfigs, err := promrelabel.ParseRelabelConfigs(sc.MetricRelabelConfigs)
if err != nil {
return nil, fmt.Errorf("cannot parse `metric_relabel_configs` for `job_name` %q: %w", jobName, err)
}
@ -527,8 +525,8 @@ type scrapeWorkConfig struct {
honorLabels bool
honorTimestamps bool
externalLabels map[string]string
relabelConfigs []promrelabel.ParsedRelabelConfig
metricRelabelConfigs []promrelabel.ParsedRelabelConfig
relabelConfigs *promrelabel.ParsedConfigs
metricRelabelConfigs *promrelabel.ParsedConfigs
sampleLimit int
disableCompression bool
disableKeepAlive bool
@ -695,7 +693,7 @@ func appendScrapeWork(dst []*ScrapeWork, swc *scrapeWorkConfig, target string, e
// Reduce memory usage by interning all the strings in originalLabels.
internLabelStrings(originalLabels)
}
labels = promrelabel.ApplyRelabelConfigs(labels, 0, swc.relabelConfigs, false)
labels = swc.relabelConfigs.Apply(labels, 0, false)
labels = promrelabel.RemoveMetaLabels(labels[:0], labels)
// Remove references to already deleted labels, so GC could clean strings for label name and label value past len(labels).
// This should reduce memory usage when relabeling creates big number of temporary labels with long names and/or values.

View file

@ -4,13 +4,11 @@ import (
"crypto/tls"
"fmt"
"reflect"
"regexp"
"testing"
"time"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel"
)
func TestLoadStaticConfigs(t *testing.T) {
@ -1034,13 +1032,6 @@ scrape_configs:
},
})
prcs, err := promrelabel.ParseRelabelConfigs(nil, []promrelabel.RelabelConfig{{
SourceLabels: []string{"foo"},
TargetLabel: "abc",
}})
if err != nil {
t.Fatalf("unexpected error when parsing relabel configs: %s", err)
}
f(`
scrape_configs:
- job_name: foo
@ -1076,9 +1067,12 @@ scrape_configs:
Value: "foo",
},
},
AuthConfig: &promauth.Config{},
MetricRelabelConfigs: prcs,
jobNameOriginal: "foo",
AuthConfig: &promauth.Config{},
MetricRelabelConfigs: mustParseRelabelConfigs(`
- source_labels: [foo]
target_label: abc
`),
jobNameOriginal: "foo",
},
})
f(`
@ -1374,8 +1368,6 @@ scrape_configs:
})
}
var defaultRegexForRelabelConfig = regexp.MustCompile("^(.*)$")
func equalStaticConfigForScrapeWorks(a, b []*ScrapeWork) bool {
if len(a) != len(b) {
return false

View file

@ -6,7 +6,6 @@ import (
"math"
"math/bits"
"strconv"
"strings"
"sync"
"time"
@ -76,7 +75,7 @@ type ScrapeWork struct {
ProxyURL proxy.URL
// Optional `metric_relabel_configs`.
MetricRelabelConfigs []promrelabel.ParsedRelabelConfig
MetricRelabelConfigs *promrelabel.ParsedConfigs
// The maximum number of metrics to scrape after relabeling.
SampleLimit int
@ -105,18 +104,10 @@ func (sw *ScrapeWork) key() string {
key := fmt.Sprintf("ScrapeURL=%s, ScrapeInterval=%s, ScrapeTimeout=%s, HonorLabels=%v, HonorTimestamps=%v, Labels=%s, "+
"AuthConfig=%s, MetricRelabelConfigs=%s, SampleLimit=%d, DisableCompression=%v, DisableKeepAlive=%v, StreamParse=%v, ScrapeAlignInterval=%s",
sw.ScrapeURL, sw.ScrapeInterval, sw.ScrapeTimeout, sw.HonorLabels, sw.HonorTimestamps, sw.LabelsString(),
sw.AuthConfig.String(), sw.metricRelabelConfigsString(), sw.SampleLimit, sw.DisableCompression, sw.DisableKeepAlive, sw.StreamParse, sw.ScrapeAlignInterval)
sw.AuthConfig.String(), sw.MetricRelabelConfigs.String(), sw.SampleLimit, sw.DisableCompression, sw.DisableKeepAlive, sw.StreamParse, sw.ScrapeAlignInterval)
return key
}
func (sw *ScrapeWork) metricRelabelConfigsString() string {
var sb strings.Builder
for _, prc := range sw.MetricRelabelConfigs {
fmt.Fprintf(&sb, "%s", prc.String())
}
return sb.String()
}
// Job returns job for the ScrapeWork
func (sw *ScrapeWork) Job() string {
return promrelabel.GetLabelValueByName(sw.Labels, "job")
@ -503,7 +494,7 @@ func (sw *scrapeWork) addRowToTimeseries(wc *writeRequestCtx, r *parser.Row, tim
labelsLen := len(wc.labels)
wc.labels = appendLabels(wc.labels, r.Metric, r.Tags, sw.Config.Labels, sw.Config.HonorLabels)
if needRelabel {
wc.labels = promrelabel.ApplyRelabelConfigs(wc.labels, labelsLen, sw.Config.MetricRelabelConfigs, true)
wc.labels = sw.Config.MetricRelabelConfigs.Apply(wc.labels, labelsLen, true)
} else {
wc.labels = promrelabel.FinalizeLabels(wc.labels[:labelsLen], wc.labels[labelsLen:])
promrelabel.SortLabels(wc.labels[labelsLen:])

View file

@ -2,7 +2,6 @@ package promscrape
import (
"fmt"
"regexp"
"strings"
"testing"
@ -102,7 +101,8 @@ func TestScrapeWorkScrapeInternalSuccess(t *testing.T) {
sw.PushData = func(wr *prompbmarshal.WriteRequest) {
pushDataCalls++
if len(wr.Timeseries) > len(timeseriesExpected) {
pushDataErr = fmt.Errorf("too many time series obtained; got %d; want %d", len(wr.Timeseries), len(timeseriesExpected))
pushDataErr = fmt.Errorf("too many time series obtained; got %d; want %d\ngot\n%+v\nwant\n%+v",
len(wr.Timeseries), len(timeseriesExpected), wr.Timeseries, timeseriesExpected)
return
}
tsExpected := timeseriesExpected[:len(wr.Timeseries)]
@ -271,20 +271,14 @@ func TestScrapeWorkScrapeInternalSuccess(t *testing.T) {
Value: "foo.com",
},
},
MetricRelabelConfigs: []promrelabel.ParsedRelabelConfig{
{
SourceLabels: []string{"__address__", "job"},
Separator: "/",
TargetLabel: "instance",
Regex: defaultRegexForRelabelConfig,
Replacement: "$1",
Action: "replace",
},
{
Action: "labeldrop",
Regex: regexp.MustCompile("^c$"),
},
},
MetricRelabelConfigs: mustParseRelabelConfigs(`
- action: replace
source_labels: ["__address__", "job"]
separator: "/"
target_label: "instance"
- action: labeldrop
regex: c
`),
}, `
foo{bar="baz",job="xx",instance="foo.com/xx"} 34.44 123
bar{a="b",job="xx",instance="foo.com/xx"} -3e4 123
@ -311,18 +305,15 @@ func TestScrapeWorkScrapeInternalSuccess(t *testing.T) {
Value: "foo.com",
},
},
MetricRelabelConfigs: []promrelabel.ParsedRelabelConfig{
{
Action: "drop",
SourceLabels: []string{"a", "c"},
Regex: regexp.MustCompile("^bd$"),
},
{
Action: "drop",
SourceLabels: []string{"__name__"},
Regex: regexp.MustCompile("^(dropme|up)$"),
},
},
MetricRelabelConfigs: mustParseRelabelConfigs(`
- action: drop
separator: ""
source_labels: [a, c]
regex: "^bd$"
- action: drop
source_labels: [__name__]
regex: "dropme|up"
`),
}, `
foo{bar="baz",job="xx",instance="foo.com"} 34.44 123
up{job="xx",instance="foo.com"} 1 123
@ -440,3 +431,11 @@ func timeseriesToString(ts *prompbmarshal.TimeSeries) string {
fmt.Fprintf(&sb, "%g %d", s.Value, s.Timestamp)
return sb.String()
}
func mustParseRelabelConfigs(config string) *promrelabel.ParsedConfigs {
pcs, err := promrelabel.ParseRelabelConfigsData([]byte(config))
if err != nil {
panic(fmt.Errorf("cannot parse %q: %w", config, err))
}
return pcs
}