Skip to content

Commit 71dbb4d

Browse files
author
Julien Pivotto
authored
Add lowercase and uppercase relabel action (prometheus#10641)
Signed-off-by: Julien Pivotto <[email protected]>
1 parent 4e63741 commit 71dbb4d

11 files changed

+113
-3
lines changed

config/config_test.go

+35
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,17 @@ var expectedConf = &Config{
858858
Scheme: DefaultScrapeConfig.Scheme,
859859
HTTPClientConfig: config.DefaultHTTPClientConfig,
860860

861+
RelabelConfigs: []*relabel.Config{
862+
{
863+
Action: relabel.Uppercase,
864+
Regex: relabel.DefaultRelabelConfig.Regex,
865+
Replacement: relabel.DefaultRelabelConfig.Replacement,
866+
Separator: relabel.DefaultRelabelConfig.Separator,
867+
SourceLabels: model.LabelNames{"instance"},
868+
TargetLabel: "instance",
869+
},
870+
},
871+
861872
ServiceDiscoveryConfigs: discovery.Configs{
862873
&hetzner.SDConfig{
863874
HTTPClientConfig: config.HTTPClientConfig{
@@ -1197,6 +1208,30 @@ var expectedErrors = []struct {
11971208
filename: "labelmap.bad.yml",
11981209
errMsg: "\"l-$1\" is invalid 'replacement' for labelmap action",
11991210
},
1211+
{
1212+
filename: "lowercase.bad.yml",
1213+
errMsg: "relabel configuration for lowercase action requires 'target_label' value",
1214+
},
1215+
{
1216+
filename: "lowercase2.bad.yml",
1217+
errMsg: "\"42lab\" is invalid 'target_label' for lowercase action",
1218+
},
1219+
{
1220+
filename: "lowercase3.bad.yml",
1221+
errMsg: "'replacement' can not be set for lowercase action",
1222+
},
1223+
{
1224+
filename: "uppercase.bad.yml",
1225+
errMsg: "relabel configuration for uppercase action requires 'target_label' value",
1226+
},
1227+
{
1228+
filename: "uppercase2.bad.yml",
1229+
errMsg: "\"42lab\" is invalid 'target_label' for uppercase action",
1230+
},
1231+
{
1232+
filename: "uppercase3.bad.yml",
1233+
errMsg: "'replacement' can not be set for uppercase action",
1234+
},
12001235
{
12011236
filename: "rules.bad.yml",
12021237
errMsg: "invalid rule file path",

config/testdata/conf.good.yml

+4
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,10 @@ scrape_configs:
328328
key_file: valid_key_file
329329

330330
- job_name: hetzner
331+
relabel_configs:
332+
- action: uppercase
333+
source_labels: [instance]
334+
target_label: instance
331335
hetzner_sd_configs:
332336
- role: hcloud
333337
authorization:

config/testdata/lowercase.bad.yml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
scrape_configs:
2+
- job_name: prometheus
3+
relabel_configs:
4+
- action: lowercase
5+
source_labels: [__name__]

config/testdata/lowercase2.bad.yml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
scrape_configs:
2+
- job_name: prometheus
3+
relabel_configs:
4+
- action: lowercase
5+
source_labels: [__name__]
6+
target_label: 42lab

config/testdata/lowercase3.bad.yml

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
scrape_configs:
2+
- job_name: prometheus
3+
relabel_configs:
4+
- action: lowercase
5+
source_labels: [__name__]
6+
target_label: __name__
7+
replacement: bar

config/testdata/uppercase.bad.yml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
scrape_configs:
2+
- job_name: prometheus
3+
relabel_configs:
4+
- action: uppercase
5+
source_labels: [__name__]

config/testdata/uppercase2.bad.yml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
scrape_configs:
2+
- job_name: prometheus
3+
relabel_configs:
4+
- action: uppercase
5+
source_labels: [__name__]
6+
target_label: 42lab

config/testdata/uppercase3.bad.yml

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
scrape_configs:
2+
- job_name: prometheus
3+
relabel_configs:
4+
- action: uppercase
5+
source_labels: [__name__]
6+
target_label: __name__
7+
replacement: bar

docs/configuration/configuration.md

+2
Original file line numberDiff line numberDiff line change
@@ -2536,6 +2536,8 @@ anchored on both ends. To un-anchor the regex, use `.*<regex>.*`.
25362536
`target_label` to `replacement`, with match group references
25372537
(`${1}`, `${2}`, ...) in `replacement` substituted by their value. If `regex`
25382538
does not match, no replacement takes place.
2539+
* `lowercase`: Maps the concatenated `source_labels` to their lower case.
2540+
* `uppercase`: Maps the concatenated `source_labels` to their upper case.
25392541
* `keep`: Drop targets for which `regex` does not match the concatenated `source_labels`.
25402542
* `drop`: Drop targets for which `regex` matches the concatenated `source_labels`.
25412543
* `hashmod`: Set `target_label` to the `modulus` of a hash of the concatenated `source_labels`.

model/relabel/relabel.go

+14-3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ const (
5454
LabelDrop Action = "labeldrop"
5555
// LabelKeep drops any label not matching the regex.
5656
LabelKeep Action = "labelkeep"
57+
// Lowercase maps input letters to their lower case.
58+
Lowercase Action = "lowercase"
59+
// Uppercase maps input letters to their upper case.
60+
Uppercase Action = "uppercase"
5761
)
5862

5963
// UnmarshalYAML implements the yaml.Unmarshaler interface.
@@ -63,7 +67,7 @@ func (a *Action) UnmarshalYAML(unmarshal func(interface{}) error) error {
6367
return err
6468
}
6569
switch act := Action(strings.ToLower(s)); act {
66-
case Replace, Keep, Drop, HashMod, LabelMap, LabelDrop, LabelKeep:
70+
case Replace, Keep, Drop, HashMod, LabelMap, LabelDrop, LabelKeep, Lowercase, Uppercase:
6771
*a = act
6872
return nil
6973
}
@@ -106,12 +110,15 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
106110
if c.Modulus == 0 && c.Action == HashMod {
107111
return errors.Errorf("relabel configuration for hashmod requires non-zero modulus")
108112
}
109-
if (c.Action == Replace || c.Action == HashMod) && c.TargetLabel == "" {
113+
if (c.Action == Replace || c.Action == HashMod || c.Action == Lowercase || c.Action == Uppercase) && c.TargetLabel == "" {
110114
return errors.Errorf("relabel configuration for %s action requires 'target_label' value", c.Action)
111115
}
112-
if c.Action == Replace && !relabelTarget.MatchString(c.TargetLabel) {
116+
if (c.Action == Replace || c.Action == Lowercase || c.Action == Uppercase) && !relabelTarget.MatchString(c.TargetLabel) {
113117
return errors.Errorf("%q is invalid 'target_label' for %s action", c.TargetLabel, c.Action)
114118
}
119+
if (c.Action == Lowercase || c.Action == Uppercase) && c.Replacement != DefaultRelabelConfig.Replacement {
120+
return errors.Errorf("'replacement' can not be set for %s action", c.Action)
121+
}
115122
if c.Action == LabelMap && !relabelTarget.MatchString(c.Replacement) {
116123
return errors.Errorf("%q is invalid 'replacement' for %s action", c.Replacement, c.Action)
117124
}
@@ -228,6 +235,10 @@ func relabel(lset labels.Labels, cfg *Config) labels.Labels {
228235
break
229236
}
230237
lb.Set(string(target), string(res))
238+
case Lowercase:
239+
lb.Set(cfg.TargetLabel, strings.ToLower(val))
240+
case Uppercase:
241+
lb.Set(cfg.TargetLabel, strings.ToUpper(val))
231242
case HashMod:
232243
mod := sum64(md5.Sum([]byte(val))) % cfg.Modulus
233244
lb.Set(cfg.TargetLabel, fmt.Sprintf("%d", mod))

model/relabel/relabel_test.go

+22
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,28 @@ func TestRelabel(t *testing.T) {
428428
"a": "foo",
429429
}),
430430
},
431+
{
432+
input: labels.FromMap(map[string]string{
433+
"foo": "bAr123Foo",
434+
}),
435+
relabel: []*Config{
436+
{
437+
SourceLabels: model.LabelNames{"foo"},
438+
Action: Uppercase,
439+
TargetLabel: "foo_uppercase",
440+
},
441+
{
442+
SourceLabels: model.LabelNames{"foo"},
443+
Action: Lowercase,
444+
TargetLabel: "foo_lowercase",
445+
},
446+
},
447+
output: labels.FromMap(map[string]string{
448+
"foo": "bAr123Foo",
449+
"foo_lowercase": "bar123foo",
450+
"foo_uppercase": "BAR123FOO",
451+
}),
452+
},
431453
}
432454

433455
for _, test := range tests {

0 commit comments

Comments
 (0)