mirror of https://github.com/prometheus/prometheus
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
480 lines
11 KiB
480 lines
11 KiB
// Copyright 2015 The Prometheus Authors |
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
|
// you may not use this file except in compliance with the License. |
|
// You may obtain a copy of the License at |
|
// |
|
// http://www.apache.org/licenses/LICENSE-2.0 |
|
// |
|
// Unless required by applicable law or agreed to in writing, software |
|
// distributed under the License is distributed on an "AS IS" BASIS, |
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
// See the License for the specific language governing permissions and |
|
// limitations under the License. |
|
|
|
package relabel |
|
|
|
import ( |
|
"testing" |
|
|
|
"github.com/prometheus/common/model" |
|
"github.com/stretchr/testify/require" |
|
|
|
"github.com/prometheus/prometheus/pkg/labels" |
|
) |
|
|
|
func TestRelabel(t *testing.T) { |
|
tests := []struct { |
|
input labels.Labels |
|
relabel []*Config |
|
output labels.Labels |
|
}{ |
|
{ |
|
input: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
"b": "bar", |
|
"c": "baz", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
SourceLabels: model.LabelNames{"a"}, |
|
Regex: MustNewRegexp("f(.*)"), |
|
TargetLabel: "d", |
|
Separator: ";", |
|
Replacement: "ch${1}-ch${1}", |
|
Action: Replace, |
|
}, |
|
}, |
|
output: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
"b": "bar", |
|
"c": "baz", |
|
"d": "choo-choo", |
|
}), |
|
}, |
|
{ |
|
input: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
"b": "bar", |
|
"c": "baz", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
SourceLabels: model.LabelNames{"a", "b"}, |
|
Regex: MustNewRegexp("f(.*);(.*)r"), |
|
TargetLabel: "a", |
|
Separator: ";", |
|
Replacement: "b${1}${2}m", // boobam |
|
Action: Replace, |
|
}, |
|
{ |
|
SourceLabels: model.LabelNames{"c", "a"}, |
|
Regex: MustNewRegexp("(b).*b(.*)ba(.*)"), |
|
TargetLabel: "d", |
|
Separator: ";", |
|
Replacement: "$1$2$2$3", |
|
Action: Replace, |
|
}, |
|
}, |
|
output: labels.FromMap(map[string]string{ |
|
"a": "boobam", |
|
"b": "bar", |
|
"c": "baz", |
|
"d": "boooom", |
|
}), |
|
}, |
|
{ |
|
input: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
SourceLabels: model.LabelNames{"a"}, |
|
Regex: MustNewRegexp(".*o.*"), |
|
Action: Drop, |
|
}, { |
|
SourceLabels: model.LabelNames{"a"}, |
|
Regex: MustNewRegexp("f(.*)"), |
|
TargetLabel: "d", |
|
Separator: ";", |
|
Replacement: "ch$1-ch$1", |
|
Action: Replace, |
|
}, |
|
}, |
|
output: nil, |
|
}, |
|
{ |
|
input: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
"b": "bar", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
SourceLabels: model.LabelNames{"a"}, |
|
Regex: MustNewRegexp(".*o.*"), |
|
Action: Drop, |
|
}, |
|
}, |
|
output: nil, |
|
}, |
|
{ |
|
input: labels.FromMap(map[string]string{ |
|
"a": "abc", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
SourceLabels: model.LabelNames{"a"}, |
|
Regex: MustNewRegexp(".*(b).*"), |
|
TargetLabel: "d", |
|
Separator: ";", |
|
Replacement: "$1", |
|
Action: Replace, |
|
}, |
|
}, |
|
output: labels.FromMap(map[string]string{ |
|
"a": "abc", |
|
"d": "b", |
|
}), |
|
}, |
|
{ |
|
input: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
SourceLabels: model.LabelNames{"a"}, |
|
Regex: MustNewRegexp("no-match"), |
|
Action: Drop, |
|
}, |
|
}, |
|
output: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
}), |
|
}, |
|
{ |
|
input: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
SourceLabels: model.LabelNames{"a"}, |
|
Regex: MustNewRegexp("f|o"), |
|
Action: Drop, |
|
}, |
|
}, |
|
output: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
}), |
|
}, |
|
{ |
|
input: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
SourceLabels: model.LabelNames{"a"}, |
|
Regex: MustNewRegexp("no-match"), |
|
Action: Keep, |
|
}, |
|
}, |
|
output: nil, |
|
}, |
|
{ |
|
input: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
SourceLabels: model.LabelNames{"a"}, |
|
Regex: MustNewRegexp("f.*"), |
|
Action: Keep, |
|
}, |
|
}, |
|
output: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
}), |
|
}, |
|
{ |
|
// No replacement must be applied if there is no match. |
|
input: labels.FromMap(map[string]string{ |
|
"a": "boo", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
SourceLabels: model.LabelNames{"a"}, |
|
Regex: MustNewRegexp("f"), |
|
TargetLabel: "b", |
|
Replacement: "bar", |
|
Action: Replace, |
|
}, |
|
}, |
|
output: labels.FromMap(map[string]string{ |
|
"a": "boo", |
|
}), |
|
}, |
|
{ |
|
input: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
"b": "bar", |
|
"c": "baz", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
SourceLabels: model.LabelNames{"c"}, |
|
TargetLabel: "d", |
|
Separator: ";", |
|
Action: HashMod, |
|
Modulus: 1000, |
|
}, |
|
}, |
|
output: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
"b": "bar", |
|
"c": "baz", |
|
"d": "976", |
|
}), |
|
}, |
|
{ |
|
input: labels.FromMap(map[string]string{ |
|
"a": "foo\nbar", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
SourceLabels: model.LabelNames{"a"}, |
|
TargetLabel: "b", |
|
Separator: ";", |
|
Action: HashMod, |
|
Modulus: 1000, |
|
}, |
|
}, |
|
output: labels.FromMap(map[string]string{ |
|
"a": "foo\nbar", |
|
"b": "734", |
|
}), |
|
}, |
|
{ |
|
input: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
"b1": "bar", |
|
"b2": "baz", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
Regex: MustNewRegexp("(b.*)"), |
|
Replacement: "bar_${1}", |
|
Action: LabelMap, |
|
}, |
|
}, |
|
output: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
"b1": "bar", |
|
"b2": "baz", |
|
"bar_b1": "bar", |
|
"bar_b2": "baz", |
|
}), |
|
}, |
|
{ |
|
input: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
"__meta_my_bar": "aaa", |
|
"__meta_my_baz": "bbb", |
|
"__meta_other": "ccc", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
Regex: MustNewRegexp("__meta_(my.*)"), |
|
Replacement: "${1}", |
|
Action: LabelMap, |
|
}, |
|
}, |
|
output: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
"__meta_my_bar": "aaa", |
|
"__meta_my_baz": "bbb", |
|
"__meta_other": "ccc", |
|
"my_bar": "aaa", |
|
"my_baz": "bbb", |
|
}), |
|
}, |
|
{ // valid case |
|
input: labels.FromMap(map[string]string{ |
|
"a": "some-name-value", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
SourceLabels: model.LabelNames{"a"}, |
|
Regex: MustNewRegexp("some-([^-]+)-([^,]+)"), |
|
Action: Replace, |
|
Replacement: "${2}", |
|
TargetLabel: "${1}", |
|
}, |
|
}, |
|
output: labels.FromMap(map[string]string{ |
|
"a": "some-name-value", |
|
"name": "value", |
|
}), |
|
}, |
|
{ // invalid replacement "" |
|
input: labels.FromMap(map[string]string{ |
|
"a": "some-name-value", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
SourceLabels: model.LabelNames{"a"}, |
|
Regex: MustNewRegexp("some-([^-]+)-([^,]+)"), |
|
Action: Replace, |
|
Replacement: "${3}", |
|
TargetLabel: "${1}", |
|
}, |
|
}, |
|
output: labels.FromMap(map[string]string{ |
|
"a": "some-name-value", |
|
}), |
|
}, |
|
{ // invalid target_labels |
|
input: labels.FromMap(map[string]string{ |
|
"a": "some-name-value", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
SourceLabels: model.LabelNames{"a"}, |
|
Regex: MustNewRegexp("some-([^-]+)-([^,]+)"), |
|
Action: Replace, |
|
Replacement: "${1}", |
|
TargetLabel: "${3}", |
|
}, |
|
{ |
|
SourceLabels: model.LabelNames{"a"}, |
|
Regex: MustNewRegexp("some-([^-]+)-([^,]+)"), |
|
Action: Replace, |
|
Replacement: "${1}", |
|
TargetLabel: "0${3}", |
|
}, |
|
{ |
|
SourceLabels: model.LabelNames{"a"}, |
|
Regex: MustNewRegexp("some-([^-]+)-([^,]+)"), |
|
Action: Replace, |
|
Replacement: "${1}", |
|
TargetLabel: "-${3}", |
|
}, |
|
}, |
|
output: labels.FromMap(map[string]string{ |
|
"a": "some-name-value", |
|
}), |
|
}, |
|
{ // more complex real-life like usecase |
|
input: labels.FromMap(map[string]string{ |
|
"__meta_sd_tags": "path:/secret,job:some-job,label:foo=bar", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
SourceLabels: model.LabelNames{"__meta_sd_tags"}, |
|
Regex: MustNewRegexp("(?:.+,|^)path:(/[^,]+).*"), |
|
Action: Replace, |
|
Replacement: "${1}", |
|
TargetLabel: "__metrics_path__", |
|
}, |
|
{ |
|
SourceLabels: model.LabelNames{"__meta_sd_tags"}, |
|
Regex: MustNewRegexp("(?:.+,|^)job:([^,]+).*"), |
|
Action: Replace, |
|
Replacement: "${1}", |
|
TargetLabel: "job", |
|
}, |
|
{ |
|
SourceLabels: model.LabelNames{"__meta_sd_tags"}, |
|
Regex: MustNewRegexp("(?:.+,|^)label:([^=]+)=([^,]+).*"), |
|
Action: Replace, |
|
Replacement: "${2}", |
|
TargetLabel: "${1}", |
|
}, |
|
}, |
|
output: labels.FromMap(map[string]string{ |
|
"__meta_sd_tags": "path:/secret,job:some-job,label:foo=bar", |
|
"__metrics_path__": "/secret", |
|
"job": "some-job", |
|
"foo": "bar", |
|
}), |
|
}, |
|
{ |
|
input: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
"b1": "bar", |
|
"b2": "baz", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
Regex: MustNewRegexp("(b.*)"), |
|
Action: LabelKeep, |
|
}, |
|
}, |
|
output: labels.FromMap(map[string]string{ |
|
"b1": "bar", |
|
"b2": "baz", |
|
}), |
|
}, |
|
{ |
|
input: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
"b1": "bar", |
|
"b2": "baz", |
|
}), |
|
relabel: []*Config{ |
|
{ |
|
Regex: MustNewRegexp("(b.*)"), |
|
Action: LabelDrop, |
|
}, |
|
}, |
|
output: labels.FromMap(map[string]string{ |
|
"a": "foo", |
|
}), |
|
}, |
|
} |
|
|
|
for _, test := range tests { |
|
// Setting default fields, mimicking the behaviour in Prometheus. |
|
for _, cfg := range test.relabel { |
|
if cfg.Action == "" { |
|
cfg.Action = DefaultRelabelConfig.Action |
|
} |
|
if cfg.Separator == "" { |
|
cfg.Separator = DefaultRelabelConfig.Separator |
|
} |
|
if cfg.Regex.original == "" { |
|
cfg.Regex = DefaultRelabelConfig.Regex |
|
} |
|
if cfg.Replacement == "" { |
|
cfg.Replacement = DefaultRelabelConfig.Replacement |
|
} |
|
} |
|
|
|
res := Process(test.input, test.relabel...) |
|
require.Equal(t, test.output, res) |
|
} |
|
} |
|
|
|
func TestTargetLabelValidity(t *testing.T) { |
|
tests := []struct { |
|
str string |
|
valid bool |
|
}{ |
|
{"-label", false}, |
|
{"label", true}, |
|
{"label${1}", true}, |
|
{"${1}label", true}, |
|
{"${1}", true}, |
|
{"${1}label", true}, |
|
{"${", false}, |
|
{"$", false}, |
|
{"${}", false}, |
|
{"foo${", false}, |
|
{"$1", true}, |
|
{"asd$2asd", true}, |
|
{"-foo${1}bar-", false}, |
|
{"_${1}_", true}, |
|
{"foo${bar}foo", true}, |
|
} |
|
for _, test := range tests { |
|
require.Equal(t, test.valid, relabelTarget.Match([]byte(test.str)), |
|
"Expected %q to be %v", test.str, test.valid) |
|
} |
|
}
|
|
|