mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
lib/promrelabel: add support for keepequal
and dropequal
relabeling actions
These actions are supported by Prometheus starting from v2.41.0
See https://github.com/prometheus/prometheus/pull/11564 ,
https://github.com/prometheus/prometheus/issues/11556
and https://github.com/prometheus/prometheus/issues/3756
Side note:
It's a pity that Prometheus developers decided inventing `keepequal` and `dropequal`
relabeling actions instead of adding support for `keep_if_equal` and `drop_if_equal` relabeling
actions supported by VictoriaMetrics since June 2020 - see 2a39ba639d
.
This commit is contained in:
parent
6f17c1e866
commit
cc482b89a3
6 changed files with 180 additions and 2 deletions
|
@ -15,6 +15,8 @@ The following tip changes can be tested by building VictoriaMetrics components f
|
|||
|
||||
## tip
|
||||
|
||||
* FEATURE: [relabeling](https://docs.victoriametrics.com/vmagent.html#relabeling): add support for `keepequal` and `dropequal` relabeling actions, which are supported by Prometheus starting from [v2.41.0](https://github.com/prometheus/prometheus/releases/tag/v2.41.0). These relabeling actions are almost identical to `keep_if_equal` and `drop_if_equal` relabeling actions supported by VictoriaMetrics since `v1.38.0` - see [these docs](https://docs.victoriametrics.com/vmagent.html#relabeling-enhancements) - so it is recommended sticking to `keep_if_equal` and `drop_if_equal` actions instead of switching to `keepequal` and `dropequal`.
|
||||
|
||||
|
||||
## [v1.85.3](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.85.3)
|
||||
|
||||
|
|
|
@ -278,7 +278,7 @@ func parseRelabelConfig(rc *RelabelConfig) (*parsedRelabelConfig, error) {
|
|||
return nil, fmt.Errorf("`replacement` cannot be used with `action=graphite`; see https://docs.victoriametrics.com/vmagent.html#graphite-relabeling")
|
||||
}
|
||||
if rc.Regex != nil {
|
||||
return nil, fmt.Errorf("`regex` cannot be used with `action=graphite`; see https://docs.victoriametrics.com/vmagent.html#graphite-relabeling")
|
||||
return nil, fmt.Errorf("`regex` cannot be used for `action=graphite`; see https://docs.victoriametrics.com/vmagent.html#graphite-relabeling")
|
||||
}
|
||||
case "replace":
|
||||
if targetLabel == "" {
|
||||
|
@ -295,10 +295,36 @@ func parseRelabelConfig(rc *RelabelConfig) (*parsedRelabelConfig, error) {
|
|||
if len(sourceLabels) < 2 {
|
||||
return nil, fmt.Errorf("`source_labels` must contain at least two entries for `action=keep_if_equal`; got %q", sourceLabels)
|
||||
}
|
||||
if targetLabel != "" {
|
||||
return nil, fmt.Errorf("`target_label` cannot be used for `action=keep_if_equal`")
|
||||
}
|
||||
if rc.Regex != nil {
|
||||
return nil, fmt.Errorf("`regex` cannot be used for `action=keep_if_equal`")
|
||||
}
|
||||
case "drop_if_equal":
|
||||
if len(sourceLabels) < 2 {
|
||||
return nil, fmt.Errorf("`source_labels` must contain at least two entries for `action=drop_if_equal`; got %q", sourceLabels)
|
||||
}
|
||||
if targetLabel != "" {
|
||||
return nil, fmt.Errorf("`target_label` cannot be used for `action=drop_if_equal`")
|
||||
}
|
||||
if rc.Regex != nil {
|
||||
return nil, fmt.Errorf("`regex` cannot be used for `action=drop_if_equal`")
|
||||
}
|
||||
case "keepequal":
|
||||
if targetLabel == "" {
|
||||
return nil, fmt.Errorf("missing `target_label` for `action=keepequal`")
|
||||
}
|
||||
if rc.Regex != nil {
|
||||
return nil, fmt.Errorf("`regex` cannot be used for `action=keepequal`")
|
||||
}
|
||||
case "dropequal":
|
||||
if targetLabel == "" {
|
||||
return nil, fmt.Errorf("missing `target_label` for `action=dropequal`")
|
||||
}
|
||||
if rc.Regex != nil {
|
||||
return nil, fmt.Errorf("`regex` cannot be used for `action=dropequal`")
|
||||
}
|
||||
case "keep":
|
||||
if len(sourceLabels) == 0 && rc.If == nil {
|
||||
return nil, fmt.Errorf("missing `source_labels` for `action=keep`")
|
||||
|
|
|
@ -84,7 +84,7 @@ func TestLoadRelabelConfigsSuccess(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("cannot load relabel configs from %q: %s", path, err)
|
||||
}
|
||||
nExpected := 16
|
||||
nExpected := 18
|
||||
if n := pcs.Len(); n != nExpected {
|
||||
t.Fatalf("unexpected number of relabel configs loaded from %q; got %d; want %d", path, n, nExpected)
|
||||
}
|
||||
|
@ -266,6 +266,26 @@ func TestParseRelabelConfigsFailure(t *testing.T) {
|
|||
},
|
||||
})
|
||||
})
|
||||
t.Run("keep_if_equal-unused-target-label", func(t *testing.T) {
|
||||
f([]RelabelConfig{
|
||||
{
|
||||
Action: "keep_if_equal",
|
||||
SourceLabels: []string{"foo", "bar"},
|
||||
TargetLabel: "foo",
|
||||
},
|
||||
})
|
||||
})
|
||||
t.Run("keep_if_equal-unused-regex", func(t *testing.T) {
|
||||
f([]RelabelConfig{
|
||||
{
|
||||
Action: "keep_if_equal",
|
||||
SourceLabels: []string{"foo", "bar"},
|
||||
Regex: &MultiLineRegex{
|
||||
S: "bar",
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
t.Run("drop_if_equal-missing-source-labels", func(t *testing.T) {
|
||||
f([]RelabelConfig{
|
||||
{
|
||||
|
@ -281,6 +301,80 @@ func TestParseRelabelConfigsFailure(t *testing.T) {
|
|||
},
|
||||
})
|
||||
})
|
||||
t.Run("drop_if_equal-unused-target-label", func(t *testing.T) {
|
||||
f([]RelabelConfig{
|
||||
{
|
||||
Action: "drop_if_equal",
|
||||
SourceLabels: []string{"foo", "bar"},
|
||||
TargetLabel: "foo",
|
||||
},
|
||||
})
|
||||
})
|
||||
t.Run("drop_if_equal-unused-regex", func(t *testing.T) {
|
||||
f([]RelabelConfig{
|
||||
{
|
||||
Action: "drop_if_equal",
|
||||
SourceLabels: []string{"foo", "bar"},
|
||||
Regex: &MultiLineRegex{
|
||||
S: "bar",
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
t.Run("keepequal-missing-source-labels", func(t *testing.T) {
|
||||
f([]RelabelConfig{
|
||||
{
|
||||
Action: "keepequal",
|
||||
},
|
||||
})
|
||||
})
|
||||
t.Run("keepequal-missing-target-label", func(t *testing.T) {
|
||||
f([]RelabelConfig{
|
||||
{
|
||||
Action: "keepequal",
|
||||
SourceLabels: []string{"foo"},
|
||||
},
|
||||
})
|
||||
})
|
||||
t.Run("keepequal-unused-regex", func(t *testing.T) {
|
||||
f([]RelabelConfig{
|
||||
{
|
||||
Action: "keepequal",
|
||||
SourceLabels: []string{"foo"},
|
||||
TargetLabel: "foo",
|
||||
Regex: &MultiLineRegex{
|
||||
S: "bar",
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
t.Run("dropequal-missing-source-labels", func(t *testing.T) {
|
||||
f([]RelabelConfig{
|
||||
{
|
||||
Action: "dropequal",
|
||||
},
|
||||
})
|
||||
})
|
||||
t.Run("dropequal-missing-target-label", func(t *testing.T) {
|
||||
f([]RelabelConfig{
|
||||
{
|
||||
Action: "dropequal",
|
||||
SourceLabels: []string{"foo"},
|
||||
},
|
||||
})
|
||||
})
|
||||
t.Run("dropequal-unused-regex", func(t *testing.T) {
|
||||
f([]RelabelConfig{
|
||||
{
|
||||
Action: "dropequal",
|
||||
SourceLabels: []string{"foo"},
|
||||
TargetLabel: "foo",
|
||||
Regex: &MultiLineRegex{
|
||||
S: "bar",
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
t.Run("drop-missing-source-labels", func(t *testing.T) {
|
||||
f([]RelabelConfig{
|
||||
{
|
||||
|
|
|
@ -276,6 +276,28 @@ func (prc *parsedRelabelConfig) apply(labels []prompbmarshal.Label, labelsOffset
|
|||
return labels[:labelsOffset]
|
||||
}
|
||||
return labels
|
||||
case "keepequal":
|
||||
// Keep the entry if `source_labels` joined with `separator` matches `target_label`
|
||||
bb := relabelBufPool.Get()
|
||||
bb.B = concatLabelValues(bb.B[:0], src, prc.SourceLabels, prc.Separator)
|
||||
targetValue := getLabelValue(labels[labelsOffset:], prc.TargetLabel)
|
||||
keep := string(bb.B) == targetValue
|
||||
relabelBufPool.Put(bb)
|
||||
if keep {
|
||||
return labels
|
||||
}
|
||||
return labels[:labelsOffset]
|
||||
case "dropequal":
|
||||
// Drop the entry if `source_labels` joined with `separator` doesn't match `target_label`
|
||||
bb := relabelBufPool.Get()
|
||||
bb.B = concatLabelValues(bb.B[:0], src, prc.SourceLabels, prc.Separator)
|
||||
targetValue := getLabelValue(labels[labelsOffset:], prc.TargetLabel)
|
||||
drop := string(bb.B) == targetValue
|
||||
relabelBufPool.Put(bb)
|
||||
if !drop {
|
||||
return labels
|
||||
}
|
||||
return labels[:labelsOffset]
|
||||
case "keep":
|
||||
// Keep the target if `source_labels` joined with `separator` match the `regex`.
|
||||
if prc.RegexAnchored == defaultRegexForRelabelConfig {
|
||||
|
|
|
@ -399,6 +399,34 @@ func TestParsedRelabelConfigsApply(t *testing.T) {
|
|||
- action: drop_if_equal
|
||||
source_labels: [xxx, bar]
|
||||
`, `{xxx="yyy",bar="yyy"}`, true, `{}`)
|
||||
})
|
||||
t.Run("keepequal-hit", func(t *testing.T) {
|
||||
f(`
|
||||
- action: keepequal
|
||||
source_labels: [foo]
|
||||
target_label: bar
|
||||
`, `{foo="a",bar="a"}`, true, `{bar="a",foo="a"}`)
|
||||
})
|
||||
t.Run("keepequal-miss", func(t *testing.T) {
|
||||
f(`
|
||||
- action: keepequal
|
||||
source_labels: [foo]
|
||||
target_label: bar
|
||||
`, `{foo="a",bar="x"}`, true, `{}`)
|
||||
})
|
||||
t.Run("dropequal-hit", func(t *testing.T) {
|
||||
f(`
|
||||
- action: dropequal
|
||||
source_labels: [foo]
|
||||
target_label: bar
|
||||
`, `{foo="a",bar="a"}`, true, `{}`)
|
||||
})
|
||||
t.Run("dropequal-miss", func(t *testing.T) {
|
||||
f(`
|
||||
- action: dropequal
|
||||
source_labels: [foo]
|
||||
target_label: bar
|
||||
`, `{foo="a",bar="x"}`, true, `{bar="x",foo="a"}`)
|
||||
})
|
||||
t.Run("keep-miss", func(t *testing.T) {
|
||||
f(`
|
||||
|
|
|
@ -22,6 +22,12 @@
|
|||
source_labels: [foo, bar]
|
||||
- action: drop_if_equal
|
||||
source_labels: [foo, bar]
|
||||
- action: keepequal
|
||||
source_labels: [foo]
|
||||
target_label: bar
|
||||
- action: dropequal
|
||||
source_labels: [foo]
|
||||
target_label: bar
|
||||
- action: keep
|
||||
source_labels: [__name__]
|
||||
regex:
|
||||
|
|
Loading…
Reference in a new issue