Skip to content

Commit

Permalink
Add lowercase and uppercase relabel action (prometheus#10641)
Browse files Browse the repository at this point in the history
Signed-off-by: Julien Pivotto <roidelapluie@o11y.eu>
  • Loading branch information
roidelapluie committed Jun 22, 2022
1 parent 2dce1b4 commit cec685b
Show file tree
Hide file tree
Showing 11 changed files with 113 additions and 3 deletions.
35 changes: 35 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,17 @@ var expectedConf = &Config{
Scheme: DefaultScrapeConfig.Scheme,
HTTPClientConfig: config.DefaultHTTPClientConfig,

RelabelConfigs: []*relabel.Config{
{
Action: relabel.Uppercase,
Regex: relabel.DefaultRelabelConfig.Regex,
Replacement: relabel.DefaultRelabelConfig.Replacement,
Separator: relabel.DefaultRelabelConfig.Separator,
SourceLabels: model.LabelNames{"instance"},
TargetLabel: "instance",
},
},

ServiceDiscoveryConfigs: discovery.Configs{
&hetzner.SDConfig{
HTTPClientConfig: config.HTTPClientConfig{
Expand Down Expand Up @@ -1197,6 +1208,30 @@ var expectedErrors = []struct {
filename: "labelmap.bad.yml",
errMsg: "\"l-$1\" is invalid 'replacement' for labelmap action",
},
{
filename: "lowercase.bad.yml",
errMsg: "relabel configuration for lowercase action requires 'target_label' value",
},
{
filename: "lowercase2.bad.yml",
errMsg: "\"42lab\" is invalid 'target_label' for lowercase action",
},
{
filename: "lowercase3.bad.yml",
errMsg: "'replacement' can not be set for lowercase action",
},
{
filename: "uppercase.bad.yml",
errMsg: "relabel configuration for uppercase action requires 'target_label' value",
},
{
filename: "uppercase2.bad.yml",
errMsg: "\"42lab\" is invalid 'target_label' for uppercase action",
},
{
filename: "uppercase3.bad.yml",
errMsg: "'replacement' can not be set for uppercase action",
},
{
filename: "rules.bad.yml",
errMsg: "invalid rule file path",
Expand Down
4 changes: 4 additions & 0 deletions config/testdata/conf.good.yml
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,10 @@ scrape_configs:
key_file: valid_key_file

- job_name: hetzner
relabel_configs:
- action: uppercase
source_labels: [instance]
target_label: instance
hetzner_sd_configs:
- role: hcloud
authorization:
Expand Down
5 changes: 5 additions & 0 deletions config/testdata/lowercase.bad.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
scrape_configs:
- job_name: prometheus
relabel_configs:
- action: lowercase
source_labels: [__name__]
6 changes: 6 additions & 0 deletions config/testdata/lowercase2.bad.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
scrape_configs:
- job_name: prometheus
relabel_configs:
- action: lowercase
source_labels: [__name__]
target_label: 42lab
7 changes: 7 additions & 0 deletions config/testdata/lowercase3.bad.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
scrape_configs:
- job_name: prometheus
relabel_configs:
- action: lowercase
source_labels: [__name__]
target_label: __name__
replacement: bar
5 changes: 5 additions & 0 deletions config/testdata/uppercase.bad.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
scrape_configs:
- job_name: prometheus
relabel_configs:
- action: uppercase
source_labels: [__name__]
6 changes: 6 additions & 0 deletions config/testdata/uppercase2.bad.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
scrape_configs:
- job_name: prometheus
relabel_configs:
- action: uppercase
source_labels: [__name__]
target_label: 42lab
7 changes: 7 additions & 0 deletions config/testdata/uppercase3.bad.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
scrape_configs:
- job_name: prometheus
relabel_configs:
- action: uppercase
source_labels: [__name__]
target_label: __name__
replacement: bar
2 changes: 2 additions & 0 deletions docs/configuration/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2536,6 +2536,8 @@ anchored on both ends. To un-anchor the regex, use `.*<regex>.*`.
`target_label` to `replacement`, with match group references
(`${1}`, `${2}`, ...) in `replacement` substituted by their value. If `regex`
does not match, no replacement takes place.
* `lowercase`: Maps the concatenated `source_labels` to their lower case.
* `uppercase`: Maps the concatenated `source_labels` to their upper case.
* `keep`: Drop targets for which `regex` does not match the concatenated `source_labels`.
* `drop`: Drop targets for which `regex` matches the concatenated `source_labels`.
* `hashmod`: Set `target_label` to the `modulus` of a hash of the concatenated `source_labels`.
Expand Down
17 changes: 14 additions & 3 deletions model/relabel/relabel.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ const (
LabelDrop Action = "labeldrop"
// LabelKeep drops any label not matching the regex.
LabelKeep Action = "labelkeep"
// Lowercase maps input letters to their lower case.
Lowercase Action = "lowercase"
// Uppercase maps input letters to their upper case.
Uppercase Action = "uppercase"
)

// UnmarshalYAML implements the yaml.Unmarshaler interface.
Expand All @@ -63,7 +67,7 @@ func (a *Action) UnmarshalYAML(unmarshal func(interface{}) error) error {
return err
}
switch act := Action(strings.ToLower(s)); act {
case Replace, Keep, Drop, HashMod, LabelMap, LabelDrop, LabelKeep:
case Replace, Keep, Drop, HashMod, LabelMap, LabelDrop, LabelKeep, Lowercase, Uppercase:
*a = act
return nil
}
Expand Down Expand Up @@ -106,12 +110,15 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
if c.Modulus == 0 && c.Action == HashMod {
return errors.Errorf("relabel configuration for hashmod requires non-zero modulus")
}
if (c.Action == Replace || c.Action == HashMod) && c.TargetLabel == "" {
if (c.Action == Replace || c.Action == HashMod || c.Action == Lowercase || c.Action == Uppercase) && c.TargetLabel == "" {
return errors.Errorf("relabel configuration for %s action requires 'target_label' value", c.Action)
}
if c.Action == Replace && !relabelTarget.MatchString(c.TargetLabel) {
if (c.Action == Replace || c.Action == Lowercase || c.Action == Uppercase) && !relabelTarget.MatchString(c.TargetLabel) {
return errors.Errorf("%q is invalid 'target_label' for %s action", c.TargetLabel, c.Action)
}
if (c.Action == Lowercase || c.Action == Uppercase) && c.Replacement != DefaultRelabelConfig.Replacement {
return errors.Errorf("'replacement' can not be set for %s action", c.Action)
}
if c.Action == LabelMap && !relabelTarget.MatchString(c.Replacement) {
return errors.Errorf("%q is invalid 'replacement' for %s action", c.Replacement, c.Action)
}
Expand Down Expand Up @@ -228,6 +235,10 @@ func relabel(lset labels.Labels, cfg *Config) labels.Labels {
break
}
lb.Set(string(target), string(res))
case Lowercase:
lb.Set(cfg.TargetLabel, strings.ToLower(val))
case Uppercase:
lb.Set(cfg.TargetLabel, strings.ToUpper(val))
case HashMod:
mod := sum64(md5.Sum([]byte(val))) % cfg.Modulus
lb.Set(cfg.TargetLabel, fmt.Sprintf("%d", mod))
Expand Down
22 changes: 22 additions & 0 deletions model/relabel/relabel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,28 @@ func TestRelabel(t *testing.T) {
"a": "foo",
}),
},
{
input: labels.FromMap(map[string]string{
"foo": "bAr123Foo",
}),
relabel: []*Config{
{
SourceLabels: model.LabelNames{"foo"},
Action: Uppercase,
TargetLabel: "foo_uppercase",
},
{
SourceLabels: model.LabelNames{"foo"},
Action: Lowercase,
TargetLabel: "foo_lowercase",
},
},
output: labels.FromMap(map[string]string{
"foo": "bAr123Foo",
"foo_lowercase": "bar123foo",
"foo_uppercase": "BAR123FOO",
}),
},
}

for _, test := range tests {
Expand Down

0 comments on commit cec685b

Please sign in to comment.