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", 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)) len(*relabelConfigPaths), len(*remoteWriteURLs))
} }
rcs.perURL = make([][]promrelabel.ParsedRelabelConfig, len(*remoteWriteURLs)) rcs.perURL = make([]*promrelabel.ParsedConfigs, len(*remoteWriteURLs))
for i, path := range *relabelConfigPaths { for i, path := range *relabelConfigPaths {
if len(path) == 0 { if len(path) == 0 {
// Skip empty relabel config. // Skip empty relabel config.
@ -57,8 +57,8 @@ func loadRelabelConfigs() (*relabelConfigs, error) {
} }
type relabelConfigs struct { type relabelConfigs struct {
global []promrelabel.ParsedRelabelConfig global *promrelabel.ParsedConfigs
perURL [][]promrelabel.ParsedRelabelConfig perURL []*promrelabel.ParsedConfigs
} }
// initLabelsGlobal must be called after parsing command-line flags. // 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 { func (rctx *relabelCtx) applyRelabeling(tss []prompbmarshal.TimeSeries, extraLabels []prompbmarshal.Label, pcs *promrelabel.ParsedConfigs) []prompbmarshal.TimeSeries {
if len(extraLabels) == 0 && len(prcs) == 0 { if len(extraLabels) == 0 && pcs.Len() == 0 {
// Nothing to change. // Nothing to change.
return tss return tss
} }
@ -100,7 +100,7 @@ func (rctx *relabelCtx) applyRelabeling(tss []prompbmarshal.TimeSeries, extraLab
labels = append(labels, *extraLabel) labels = append(labels, *extraLabel)
} }
} }
labels = promrelabel.ApplyRelabelConfigs(labels, labelsLen, prcs, true) labels = pcs.Apply(labels, labelsLen, true)
if len(labels) == labelsLen { if len(labels) == labelsLen {
// Drop the current time series, since relabeling removed all the labels. // Drop the current time series, since relabeling removed all the labels.
continue continue

View file

@ -142,8 +142,8 @@ func Stop() {
func Push(wr *prompbmarshal.WriteRequest) { func Push(wr *prompbmarshal.WriteRequest) {
var rctx *relabelCtx var rctx *relabelCtx
rcs := allRelabelConfigs.Load().(*relabelConfigs) rcs := allRelabelConfigs.Load().(*relabelConfigs)
prcsGlobal := rcs.global pcsGlobal := rcs.global
if len(prcsGlobal) > 0 || len(labelsGlobal) > 0 { if pcsGlobal.Len() > 0 || len(labelsGlobal) > 0 {
rctx = getRelabelCtx() rctx = getRelabelCtx()
} }
tss := wr.Timeseries tss := wr.Timeseries
@ -167,7 +167,7 @@ func Push(wr *prompbmarshal.WriteRequest) {
} }
if rctx != nil { if rctx != nil {
tssBlockLen := len(tssBlock) tssBlockLen := len(tssBlock)
tssBlock = rctx.applyRelabeling(tssBlock, labelsGlobal, prcsGlobal) tssBlock = rctx.applyRelabeling(tssBlock, labelsGlobal, pcsGlobal)
globalRelabelMetricsDropped.Add(tssBlockLen - len(tssBlock)) globalRelabelMetricsDropped.Add(tssBlockLen - len(tssBlock))
} }
for _, rwctx := range rwctxs { for _, rwctx := range rwctxs {
@ -240,8 +240,8 @@ func (rwctx *remoteWriteCtx) Push(tss []prompbmarshal.TimeSeries) {
var rctx *relabelCtx var rctx *relabelCtx
var v *[]prompbmarshal.TimeSeries var v *[]prompbmarshal.TimeSeries
rcs := allRelabelConfigs.Load().(*relabelConfigs) rcs := allRelabelConfigs.Load().(*relabelConfigs)
prcs := rcs.perURL[rwctx.idx] pcs := rcs.perURL[rwctx.idx]
if len(prcs) > 0 { if pcs.Len() > 0 {
rctx = getRelabelCtx() rctx = getRelabelCtx()
// Make a copy of tss before applying relabeling in order to prevent // Make a copy of tss before applying relabeling in order to prevent
// from affecting time series for other remoteWrite.url configs. // 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) v = tssRelabelPool.Get().(*[]prompbmarshal.TimeSeries)
tss = append(*v, tss...) tss = append(*v, tss...)
tssLen := len(tss) tssLen := len(tss)
tss = rctx.applyRelabeling(tss, nil, prcs) tss = rctx.applyRelabeling(tss, nil, pcs)
rwctx.relabelMetricsDropped.Add(tssLen - len(tss)) rwctx.relabelMetricsDropped.Add(tssLen - len(tss))
} }
pss := rwctx.pss 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. // Init must be called after flag.Parse and before using the relabel package.
func Init() { func Init() {
prcs, err := loadRelabelConfig() pcs, err := loadRelabelConfig()
if err != nil { if err != nil {
logger.Fatalf("cannot load relabelConfig: %s", err) logger.Fatalf("cannot load relabelConfig: %s", err)
} }
prcsGlobal.Store(&prcs) pcsGlobal.Store(pcs)
if len(*relabelConfig) == 0 { if len(*relabelConfig) == 0 {
return return
} }
@ -31,34 +31,34 @@ func Init() {
go func() { go func() {
for range sighupCh { for range sighupCh {
logger.Infof("received SIGHUP; reloading -relabelConfig=%q...", *relabelConfig) logger.Infof("received SIGHUP; reloading -relabelConfig=%q...", *relabelConfig)
prcs, err := loadRelabelConfig() pcs, err := loadRelabelConfig()
if err != nil { if err != nil {
logger.Errorf("cannot load the updated relabelConfig: %s; preserving the previous config", err) logger.Errorf("cannot load the updated relabelConfig: %s; preserving the previous config", err)
continue continue
} }
prcsGlobal.Store(&prcs) pcsGlobal.Store(pcs)
logger.Infof("successfully reloaded -relabelConfig=%q", *relabelConfig) 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 { if len(*relabelConfig) == 0 {
return nil, nil return nil, nil
} }
prcs, err := promrelabel.LoadRelabelConfigs(*relabelConfig) pcs, err := promrelabel.LoadRelabelConfigs(*relabelConfig)
if err != nil { if err != nil {
return nil, fmt.Errorf("error when reading -relabelConfig=%q: %w", *relabelConfig, err) 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. // HasRelabeling returns true if there is global relabeling.
func HasRelabeling() bool { func HasRelabeling() bool {
prcs := prcsGlobal.Load().(*[]promrelabel.ParsedRelabelConfig) pcs := pcsGlobal.Load().(*promrelabel.ParsedConfigs)
return len(*prcs) > 0 return pcs.Len() > 0
} }
// Ctx holds relabeling context. // Ctx holds relabeling context.
@ -77,8 +77,8 @@ func (ctx *Ctx) Reset() {
// //
// The returned labels are valid until the next call to ApplyRelabeling. // The returned labels are valid until the next call to ApplyRelabeling.
func (ctx *Ctx) ApplyRelabeling(labels []prompb.Label) []prompb.Label { func (ctx *Ctx) ApplyRelabeling(labels []prompb.Label) []prompb.Label {
prcs := prcsGlobal.Load().(*[]promrelabel.ParsedRelabelConfig) pcs := pcsGlobal.Load().(*promrelabel.ParsedConfigs)
if len(*prcs) == 0 { if pcs.Len() == 0 {
// There are no relabeling rules. // There are no relabeling rules.
return labels return labels
} }
@ -97,7 +97,7 @@ func (ctx *Ctx) ApplyRelabeling(labels []prompb.Label) []prompb.Label {
} }
// Apply relabeling // Apply relabeling
tmpLabels = promrelabel.ApplyRelabelConfigs(tmpLabels, 0, *prcs, true) tmpLabels = pcs.Apply(tmpLabels, 0, true)
ctx.tmpLabels = tmpLabels ctx.tmpLabels = tmpLabels
if len(tmpLabels) == 0 { if len(tmpLabels) == 0 {
metricsDropped.Inc() metricsDropped.Inc()

View file

@ -23,38 +23,78 @@ type RelabelConfig struct {
Action string `yaml:"action,omitempty"` 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. // 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) data, err := ioutil.ReadFile(path)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot read `relabel_configs` from %q: %w", path, err) return nil, fmt.Errorf("cannot read `relabel_configs` from %q: %w", path, err)
} }
data = envtemplate.Replace(data) data = envtemplate.Replace(data)
var rcs []RelabelConfig pcs, err := ParseRelabelConfigsData(data)
if err := yaml.UnmarshalStrict(data, &rcs); err != nil { if err != nil {
return nil, fmt.Errorf("cannot unmarshal `relabel_configs` from %q: %w", path, err) 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. // ParseRelabelConfigs parses rcs to dst.
func ParseRelabelConfigs(dst []ParsedRelabelConfig, rcs []RelabelConfig) ([]ParsedRelabelConfig, error) { func ParseRelabelConfigs(rcs []RelabelConfig) (*ParsedConfigs, error) {
if len(rcs) == 0 { if len(rcs) == 0 {
return dst, nil return nil, nil
} }
prcs := make([]*parsedRelabelConfig, len(rcs))
for i := range rcs { for i := range rcs {
var err error prc, err := parseRelabelConfig(&rcs[i])
dst, err = parseRelabelConfig(dst, &rcs[i])
if err != nil { 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 sourceLabels := rc.SourceLabels
separator := ";" separator := ";"
if rc.Separator != nil { if rc.Separator != nil {
@ -62,6 +102,7 @@ func parseRelabelConfig(dst []ParsedRelabelConfig, rc *RelabelConfig) ([]ParsedR
} }
targetLabel := rc.TargetLabel targetLabel := rc.TargetLabel
regexCompiled := defaultRegexForRelabelConfig regexCompiled := defaultRegexForRelabelConfig
regexOriginalCompiled := defaultOriginalRegexForRelabelConfig
if rc.Regex != nil { if rc.Regex != nil {
regex := *rc.Regex regex := *rc.Regex
if rc.Action != "replace_all" && rc.Action != "labelmap_all" { 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) re, err := regexp.Compile(regex)
if err != nil { 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 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 modulus := rc.Modulus
replacement := "$1" replacement := "$1"
@ -85,49 +131,49 @@ func parseRelabelConfig(dst []ParsedRelabelConfig, rc *RelabelConfig) ([]ParsedR
switch action { switch action {
case "replace": case "replace":
if targetLabel == "" { 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": case "replace_all":
if len(sourceLabels) == 0 { 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 == "" { 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": case "keep_if_equal":
if len(sourceLabels) < 2 { 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": case "drop_if_equal":
if len(sourceLabels) < 2 { 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": case "keep":
if len(sourceLabels) == 0 { 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": case "drop":
if len(sourceLabels) == 0 { 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": case "hashmod":
if len(sourceLabels) == 0 { 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 == "" { 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 { 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":
case "labelmap_all": case "labelmap_all":
case "labeldrop": case "labeldrop":
case "labelkeep": case "labelkeep":
default: 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, SourceLabels: sourceLabels,
Separator: separator, Separator: separator,
TargetLabel: targetLabel, TargetLabel: targetLabel,
@ -136,8 +182,8 @@ func parseRelabelConfig(dst []ParsedRelabelConfig, rc *RelabelConfig) ([]ParsedR
Replacement: replacement, Replacement: replacement,
Action: action, Action: action,
regexOriginal: regexOriginalCompiled,
hasCaptureGroupInTargetLabel: strings.Contains(targetLabel, "$"), hasCaptureGroupInTargetLabel: strings.Contains(targetLabel, "$"),
hasCaptureGroupInReplacement: strings.Contains(replacement, "$"), hasCaptureGroupInReplacement: strings.Contains(replacement, "$"),
}) }, nil
return dst, nil
} }

View file

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

View file

@ -12,10 +12,10 @@ import (
xxhash "github.com/cespare/xxhash/v2" 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 // 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
@ -24,29 +24,32 @@ type ParsedRelabelConfig struct {
Replacement string Replacement string
Action string Action string
regexOriginal *regexp.Regexp
hasCaptureGroupInTargetLabel bool hasCaptureGroupInTargetLabel bool
hasCaptureGroupInReplacement bool hasCaptureGroupInReplacement bool
} }
// 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", 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) 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:]. // If isFinalize is set, then FinalizeLabels is called on the labels[labelsOffset:].
// //
// The returned labels at labels[labelsOffset:] are sorted. // The returned labels at labels[labelsOffset:] are sorted.
func ApplyRelabelConfigs(labels []prompbmarshal.Label, labelsOffset int, prcs []ParsedRelabelConfig, isFinalize bool) []prompbmarshal.Label { func (pcs *ParsedConfigs) Apply(labels []prompbmarshal.Label, labelsOffset int, isFinalize bool) []prompbmarshal.Label {
for i := range prcs { if pcs != nil {
tmp := applyRelabelConfig(labels, labelsOffset, &prcs[i]) for _, prc := range pcs.prcs {
if len(tmp) == labelsOffset { tmp := prc.apply(labels, labelsOffset)
// All the labels have been removed. if len(tmp) == labelsOffset {
return tmp // All the labels have been removed.
return tmp
}
labels = tmp
} }
labels = tmp
} }
labels = removeEmptyLabels(labels, labelsOffset) labels = removeEmptyLabels(labels, labelsOffset)
if isFinalize { if isFinalize {
@ -106,10 +109,10 @@ func FinalizeLabels(dst, src []prompbmarshal.Label) []prompbmarshal.Label {
return dst 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 // 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:] src := labels[labelsOffset:]
switch prc.Action { switch prc.Action {
case "replace": case "replace":
@ -150,22 +153,13 @@ func applyRelabelConfig(labels []prompbmarshal.Label, labelsOffset int, prc *Par
case "replace_all": case "replace_all":
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)
if prefix, complete := prc.Regex.LiteralPrefix(); complete && !prc.hasCaptureGroupInReplacement { sourceStr := string(bb.B)
// 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
relabelBufPool.Put(bb) relabelBufPool.Put(bb)
valueStr := prc.Regex.ReplaceAllString(sourceStr, prc.Replacement) valueStr, ok := prc.replaceStringSubmatches(sourceStr, prc.Replacement, prc.hasCaptureGroupInReplacement)
return setLabelValue(labels, labelsOffset, prc.TargetLabel, valueStr) if ok {
labels = setLabelValue(labels, labelsOffset, prc.TargetLabel, valueStr)
}
return labels
case "keep_if_equal": case "keep_if_equal":
// Keep the entry if all the label values in source_labels are equal. // Keep the entry if all the label values in source_labels are equal.
// For example: // For example:
@ -193,14 +187,7 @@ func applyRelabelConfig(labels []prompbmarshal.Label, labelsOffset int, prc *Par
case "keep": case "keep":
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 := false keep := prc.matchString(bytesutil.ToUnsafeString(bb.B))
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)
}
relabelBufPool.Put(bb) relabelBufPool.Put(bb)
if !keep { if !keep {
return labels[:labelsOffset] return labels[:labelsOffset]
@ -209,14 +196,7 @@ func applyRelabelConfig(labels []prompbmarshal.Label, labelsOffset int, prc *Par
case "drop": case "drop":
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 := false drop := prc.matchString(bytesutil.ToUnsafeString(bb.B))
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)
}
relabelBufPool.Put(bb) relabelBufPool.Put(bb)
if drop { if drop {
return labels[:labelsOffset] return labels[:labelsOffset]
@ -232,42 +212,23 @@ func applyRelabelConfig(labels []prompbmarshal.Label, labelsOffset int, prc *Par
case "labelmap": case "labelmap":
for i := range src { for i := range src {
label := &src[i] label := &src[i]
match := prc.Regex.FindStringSubmatchIndex(label.Name) labelName, ok := prc.replaceFullString(label.Name, prc.Replacement, prc.hasCaptureGroupInReplacement)
if match == nil { if ok {
continue 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 return labels
case "labelmap_all": case "labelmap_all":
for i := range src { for i := range src {
label := &src[i] label := &src[i]
if prefix, complete := prc.Regex.LiteralPrefix(); complete && !prc.hasCaptureGroupInReplacement { label.Name, _ = prc.replaceStringSubmatches(label.Name, prc.Replacement, 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)
}
} }
return labels return labels
case "labeldrop": case "labeldrop":
keepSrc := true keepSrc := true
for i := range src { for i := range src {
label := &src[i] label := &src[i]
if prefix, complete := prc.Regex.LiteralPrefix(); complete { if prc.matchString(label.Name) {
if prefix == label.Name {
keepSrc = false
break
}
} else if prc.Regex.MatchString(label.Name) {
keepSrc = false keepSrc = false
break break
} }
@ -278,11 +239,7 @@ func applyRelabelConfig(labels []prompbmarshal.Label, labelsOffset int, prc *Par
dst := labels[:labelsOffset] dst := labels[:labelsOffset]
for i := range src { for i := range src {
label := &src[i] label := &src[i]
if prefix, complete := prc.Regex.LiteralPrefix(); complete { if !prc.matchString(label.Name) {
if prefix != label.Name {
dst = append(dst, *label)
}
} else if !prc.Regex.MatchString(label.Name) {
dst = append(dst, *label) dst = append(dst, *label)
} }
} }
@ -291,12 +248,7 @@ func applyRelabelConfig(labels []prompbmarshal.Label, labelsOffset int, prc *Par
keepSrc := true keepSrc := true
for i := range src { for i := range src {
label := &src[i] label := &src[i]
if prefix, complete := prc.Regex.LiteralPrefix(); complete { if !prc.matchString(label.Name) {
if prefix != label.Name {
keepSrc = false
break
}
} else if !prc.Regex.MatchString(src[i].Name) {
keepSrc = false keepSrc = false
break break
} }
@ -307,11 +259,7 @@ func applyRelabelConfig(labels []prompbmarshal.Label, labelsOffset int, prc *Par
dst := labels[:labelsOffset] dst := labels[:labelsOffset]
for i := range src { for i := range src {
label := &src[i] label := &src[i]
if prefix, complete := prc.Regex.LiteralPrefix(); complete { if prc.matchString(label.Name) {
if prefix == label.Name {
dst = append(dst, *label)
}
} else if prc.Regex.MatchString(label.Name) {
dst = append(dst, *label) 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 := relabelBufPool.Get()
bb.B = prc.Regex.ExpandString(bb.B[:0], template, source, match) bb.B = prc.Regex.ExpandString(bb.B[:0], template, source, match)
s := string(bb.B) s := string(bb.B)

View file

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

View file

@ -2,7 +2,6 @@ package promrelabel
import ( import (
"fmt" "fmt"
"regexp"
"testing" "testing"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal" "github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
@ -10,15 +9,11 @@ import (
func BenchmarkApplyRelabelConfigs(b *testing.B) { func BenchmarkApplyRelabelConfigs(b *testing.B) {
b.Run("replace-label-copy", func(b *testing.B) { b.Run("replace-label-copy", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: replace
Action: "replace", source_labels: [id]
SourceLabels: []string{"id"}, target_label: __name__
TargetLabel: "__name__", `)
Regex: defaultRegexForRelabelConfig,
Replacement: "$1",
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -35,7 +30,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) { if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels)) 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) { b.Run("replace-set-label", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: replace
Action: "replace", target_label: __name__
TargetLabel: "__name__", replacement: foobar
Regex: defaultRegexForRelabelConfig, `)
Replacement: "foobar",
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -79,7 +71,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) { if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels)) 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) { b.Run("replace-add-label", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: replace
Action: "replace", target_label: aaa
TargetLabel: "aaa", replacement: foobar
Regex: defaultRegexForRelabelConfig, `)
Replacement: "foobar",
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -119,7 +108,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != 2 { if len(labels) != 2 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 2, labels)) 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) { b.Run("replace-mismatch", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: replace
Action: "replace", source_labels: ["non-existing-label"]
SourceLabels: []string{"non-existing-label"}, target_label: id
TargetLabel: "id", regex: "(foobar)-.*"
Regex: regexp.MustCompile("(foobar)-.*"), `)
Replacement: "$1",
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -164,7 +150,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) { if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels)) 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) { b.Run("replace-match-regex", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: replace
Action: "replace", source_labels: [id]
SourceLabels: []string{"id"}, target_label: id
TargetLabel: "id", regex: "(foobar)-.*"
Regex: regexp.MustCompile("(foobar)-.*"), `)
Replacement: "$1",
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -209,7 +192,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) { if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels)) 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) { b.Run("drop-mismatch", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: drop
Action: "drop", source_labels: ["non-existing-label"]
SourceLabels: []string{"non-existing-label"}, regex: "(foobar)-.*"
Regex: regexp.MustCompile("(foobar)-.*"), `)
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -252,7 +233,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) { if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels)) 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) { b.Run("drop-match", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: drop
Action: "drop", source_labels: [id]
SourceLabels: []string{"id"}, regex: yes
Regex: regexp.MustCompile("yes"), `)
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -295,7 +274,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != 0 { if len(labels) != 0 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 0, labels)) 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) { b.Run("drop-match-regexp", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: drop
Action: "drop", source_labels: [id]
SourceLabels: []string{"id"}, regex: "(foobar)-.*"
Regex: regexp.MustCompile("(foobar)-.*"), `)
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -326,7 +303,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != 0 { if len(labels) != 0 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 0, labels)) 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) { b.Run("keep-mismatch", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: keep
Action: "keep", source_labels: ["non-existing-label"]
SourceLabels: []string{"non-existing-label"}, regex: "(foobar)-.*"
Regex: regexp.MustCompile("(foobar)-.*"), `)
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -357,7 +332,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != 0 { if len(labels) != 0 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 0, labels)) 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) { b.Run("keep-match", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: keep
Action: "keep", source_labels: [id]
SourceLabels: []string{"id"}, regex: yes
Regex: regexp.MustCompile("yes"), `)
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -388,7 +361,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) { if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels)) 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) { b.Run("keep-match-regexp", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: keep
Action: "keep", source_labels: [id]
SourceLabels: []string{"id"}, regex: "(foobar)-.*"
Regex: regexp.MustCompile("(foobar)-.*"), `)
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -431,7 +402,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) { if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels)) 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) { b.Run("labeldrop-mismatch", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: labeldrop
Action: "labeldrop", regex: "non-existing-label"
Regex: regexp.MustCompile("non-existing-label"), `)
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -473,7 +442,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) { if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels)) 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) { b.Run("labeldrop-match", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: labeldrop
Action: "labeldrop", regex: id
Regex: regexp.MustCompile("id"), `)
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -515,7 +482,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != 1 { if len(labels) != 1 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 1, labels)) 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) { b.Run("labeldrop-match-regexp", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: labeldrop
Action: "labeldrop", regex: "id.*"
Regex: regexp.MustCompile("id.*"), `)
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -551,7 +516,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != 1 { if len(labels) != 1 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 1, labels)) 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) { b.Run("labelkeep-mismatch", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: labelkeep
Action: "labelkeep", regex: "non-existing-label"
Regex: regexp.MustCompile("non-existing-label"), `)
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -587,7 +550,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != 0 { if len(labels) != 0 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 0, labels)) 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) { b.Run("labelkeep-match", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: labelkeep
Action: "labelkeep", regex: id
Regex: regexp.MustCompile("id"), `)
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -617,7 +578,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != 1 { if len(labels) != 1 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 1, labels)) 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) { b.Run("labelkeep-match-regexp", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: labelkeep
Action: "labelkeep", regex: "id.*"
Regex: regexp.MustCompile("id.*"), `)
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -653,7 +612,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != 1 { if len(labels) != 1 {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 1, labels)) 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) { b.Run("labelmap-mismatch", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: labelmap
Action: "labelmap", regex: "a(.*)"
Regex: regexp.MustCompile("a(.*)"), `)
Replacement: "$1",
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{
Name: "aabc",
Value: "foobar-random-string-here",
},
{ {
Name: "foo", Name: "foo",
Value: "bar", Value: "bar",
@ -690,8 +642,38 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != 3 { 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)) panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), 3, labels))
} }
if labels[0].Name != "aabc" { if labels[0].Name != "aabc" {
@ -706,24 +688,52 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
if labels[1].Value != "foobar-random-string-here" { 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")) 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" { if labels[0].Name != "aa" {
panic(fmt.Errorf("unexpected label value; got %q; want %q", labels[2].Value, "bar")) 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) { b.Run("hashmod", func(b *testing.B) {
prcs := []ParsedRelabelConfig{ pcs := mustParseRelabelConfigs(`
{ - action: hashmod
Action: "hashmod", source_labels: [id]
SourceLabels: []string{"id"}, target_label: id
TargetLabel: "id", modulus: 23
Modulus: 23, `)
},
}
labelsOrig := []prompbmarshal.Label{ labelsOrig := []prompbmarshal.Label{
{ {
Name: "__name__", Name: "__name__",
@ -740,7 +750,7 @@ func BenchmarkApplyRelabelConfigs(b *testing.B) {
var labels []prompbmarshal.Label var labels []prompbmarshal.Label
for pb.Next() { for pb.Next() {
labels = append(labels[:0], labelsOrig...) labels = append(labels[:0], labelsOrig...)
labels = ApplyRelabelConfigs(labels, 0, prcs, true) labels = pcs.Apply(labels, 0, true)
if len(labels) != len(labelsOrig) { if len(labels) != len(labelsOrig) {
panic(fmt.Errorf("unexpected number of labels; got %d; want %d; labels:\n%#v", len(labels), len(labelsOrig), labels)) 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 { if err != nil {
return nil, fmt.Errorf("cannot parse auth config for `job_name` %q: %w", jobName, err) return nil, fmt.Errorf("cannot parse auth config for `job_name` %q: %w", jobName, err)
} }
var relabelConfigs []promrelabel.ParsedRelabelConfig relabelConfigs, err := promrelabel.ParseRelabelConfigs(sc.RelabelConfigs)
relabelConfigs, err = promrelabel.ParseRelabelConfigs(relabelConfigs[:0], sc.RelabelConfigs)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot parse `relabel_configs` for `job_name` %q: %w", jobName, err) return nil, fmt.Errorf("cannot parse `relabel_configs` for `job_name` %q: %w", jobName, err)
} }
var metricRelabelConfigs []promrelabel.ParsedRelabelConfig metricRelabelConfigs, err := promrelabel.ParseRelabelConfigs(sc.MetricRelabelConfigs)
metricRelabelConfigs, err = promrelabel.ParseRelabelConfigs(metricRelabelConfigs[:0], sc.MetricRelabelConfigs)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot parse `metric_relabel_configs` for `job_name` %q: %w", jobName, err) 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 honorLabels bool
honorTimestamps bool honorTimestamps bool
externalLabels map[string]string externalLabels map[string]string
relabelConfigs []promrelabel.ParsedRelabelConfig relabelConfigs *promrelabel.ParsedConfigs
metricRelabelConfigs []promrelabel.ParsedRelabelConfig metricRelabelConfigs *promrelabel.ParsedConfigs
sampleLimit int sampleLimit int
disableCompression bool disableCompression bool
disableKeepAlive 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. // Reduce memory usage by interning all the strings in originalLabels.
internLabelStrings(originalLabels) internLabelStrings(originalLabels)
} }
labels = promrelabel.ApplyRelabelConfigs(labels, 0, swc.relabelConfigs, false) labels = swc.relabelConfigs.Apply(labels, 0, false)
labels = promrelabel.RemoveMetaLabels(labels[:0], labels) 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). // 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. // 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" "crypto/tls"
"fmt" "fmt"
"reflect" "reflect"
"regexp"
"testing" "testing"
"time" "time"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth" "github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal" "github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel"
) )
func TestLoadStaticConfigs(t *testing.T) { 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(` f(`
scrape_configs: scrape_configs:
- job_name: foo - job_name: foo
@ -1076,9 +1067,12 @@ scrape_configs:
Value: "foo", Value: "foo",
}, },
}, },
AuthConfig: &promauth.Config{}, AuthConfig: &promauth.Config{},
MetricRelabelConfigs: prcs, MetricRelabelConfigs: mustParseRelabelConfigs(`
jobNameOriginal: "foo", - source_labels: [foo]
target_label: abc
`),
jobNameOriginal: "foo",
}, },
}) })
f(` f(`
@ -1374,8 +1368,6 @@ scrape_configs:
}) })
} }
var defaultRegexForRelabelConfig = regexp.MustCompile("^(.*)$")
func equalStaticConfigForScrapeWorks(a, b []*ScrapeWork) bool { func equalStaticConfigForScrapeWorks(a, b []*ScrapeWork) bool {
if len(a) != len(b) { if len(a) != len(b) {
return false return false

View file

@ -6,7 +6,6 @@ import (
"math" "math"
"math/bits" "math/bits"
"strconv" "strconv"
"strings"
"sync" "sync"
"time" "time"
@ -76,7 +75,7 @@ type ScrapeWork struct {
ProxyURL proxy.URL ProxyURL proxy.URL
// Optional `metric_relabel_configs`. // Optional `metric_relabel_configs`.
MetricRelabelConfigs []promrelabel.ParsedRelabelConfig MetricRelabelConfigs *promrelabel.ParsedConfigs
// The maximum number of metrics to scrape after relabeling. // The maximum number of metrics to scrape after relabeling.
SampleLimit int 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, "+ 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", "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.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 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 // Job returns job for the ScrapeWork
func (sw *ScrapeWork) Job() string { func (sw *ScrapeWork) Job() string {
return promrelabel.GetLabelValueByName(sw.Labels, "job") return promrelabel.GetLabelValueByName(sw.Labels, "job")
@ -503,7 +494,7 @@ func (sw *scrapeWork) addRowToTimeseries(wc *writeRequestCtx, r *parser.Row, tim
labelsLen := len(wc.labels) labelsLen := len(wc.labels)
wc.labels = appendLabels(wc.labels, r.Metric, r.Tags, sw.Config.Labels, sw.Config.HonorLabels) wc.labels = appendLabels(wc.labels, r.Metric, r.Tags, sw.Config.Labels, sw.Config.HonorLabels)
if needRelabel { if needRelabel {
wc.labels = promrelabel.ApplyRelabelConfigs(wc.labels, labelsLen, sw.Config.MetricRelabelConfigs, true) wc.labels = sw.Config.MetricRelabelConfigs.Apply(wc.labels, labelsLen, true)
} else { } else {
wc.labels = promrelabel.FinalizeLabels(wc.labels[:labelsLen], wc.labels[labelsLen:]) wc.labels = promrelabel.FinalizeLabels(wc.labels[:labelsLen], wc.labels[labelsLen:])
promrelabel.SortLabels(wc.labels[labelsLen:]) promrelabel.SortLabels(wc.labels[labelsLen:])

View file

@ -2,7 +2,6 @@ package promscrape
import ( import (
"fmt" "fmt"
"regexp"
"strings" "strings"
"testing" "testing"
@ -102,7 +101,8 @@ func TestScrapeWorkScrapeInternalSuccess(t *testing.T) {
sw.PushData = func(wr *prompbmarshal.WriteRequest) { sw.PushData = func(wr *prompbmarshal.WriteRequest) {
pushDataCalls++ pushDataCalls++
if len(wr.Timeseries) > len(timeseriesExpected) { 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 return
} }
tsExpected := timeseriesExpected[:len(wr.Timeseries)] tsExpected := timeseriesExpected[:len(wr.Timeseries)]
@ -271,20 +271,14 @@ func TestScrapeWorkScrapeInternalSuccess(t *testing.T) {
Value: "foo.com", Value: "foo.com",
}, },
}, },
MetricRelabelConfigs: []promrelabel.ParsedRelabelConfig{ MetricRelabelConfigs: mustParseRelabelConfigs(`
{ - action: replace
SourceLabels: []string{"__address__", "job"}, source_labels: ["__address__", "job"]
Separator: "/", separator: "/"
TargetLabel: "instance", target_label: "instance"
Regex: defaultRegexForRelabelConfig, - action: labeldrop
Replacement: "$1", regex: c
Action: "replace", `),
},
{
Action: "labeldrop",
Regex: regexp.MustCompile("^c$"),
},
},
}, ` }, `
foo{bar="baz",job="xx",instance="foo.com/xx"} 34.44 123 foo{bar="baz",job="xx",instance="foo.com/xx"} 34.44 123
bar{a="b",job="xx",instance="foo.com/xx"} -3e4 123 bar{a="b",job="xx",instance="foo.com/xx"} -3e4 123
@ -311,18 +305,15 @@ func TestScrapeWorkScrapeInternalSuccess(t *testing.T) {
Value: "foo.com", Value: "foo.com",
}, },
}, },
MetricRelabelConfigs: []promrelabel.ParsedRelabelConfig{ MetricRelabelConfigs: mustParseRelabelConfigs(`
{ - action: drop
Action: "drop", separator: ""
SourceLabels: []string{"a", "c"}, source_labels: [a, c]
Regex: regexp.MustCompile("^bd$"), regex: "^bd$"
}, - action: drop
{ source_labels: [__name__]
Action: "drop", regex: "dropme|up"
SourceLabels: []string{"__name__"}, `),
Regex: regexp.MustCompile("^(dropme|up)$"),
},
},
}, ` }, `
foo{bar="baz",job="xx",instance="foo.com"} 34.44 123 foo{bar="baz",job="xx",instance="foo.com"} 34.44 123
up{job="xx",instance="foo.com"} 1 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) fmt.Fprintf(&sb, "%g %d", s.Value, s.Timestamp)
return sb.String() 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
}