Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/component/common/relabel/relabel.go
4096 views
1
package relabel
2
3
import (
4
"fmt"
5
6
"github.com/grafana/regexp"
7
"github.com/prometheus/common/model"
8
"github.com/prometheus/prometheus/model/relabel"
9
)
10
11
// Action is the relabelling action to be performed.
12
type Action string
13
14
// All possible Action values.
15
const (
16
Replace Action = "replace"
17
Keep Action = "keep"
18
Drop Action = "drop"
19
HashMod Action = "hashmod"
20
LabelMap Action = "labelmap"
21
LabelDrop Action = "labeldrop"
22
LabelKeep Action = "labelkeep"
23
Lowercase Action = "lowercase"
24
Uppercase Action = "uppercase"
25
KeepEqual Action = "keepequal"
26
DropEqual Action = "dropequal"
27
)
28
29
var actions = map[Action]struct{}{
30
Replace: {},
31
Keep: {},
32
Drop: {},
33
HashMod: {},
34
LabelMap: {},
35
LabelDrop: {},
36
LabelKeep: {},
37
Lowercase: {},
38
Uppercase: {},
39
KeepEqual: {},
40
DropEqual: {},
41
}
42
43
// String returns the string representation of the Action type.
44
func (a Action) String() string {
45
if _, exists := actions[a]; exists {
46
return string(a)
47
}
48
return "Action:" + string(a)
49
}
50
51
// MarshalText implements encoding.TextMarshaler for Action.
52
func (a Action) MarshalText() (text []byte, err error) {
53
return []byte(a.String()), nil
54
}
55
56
// UnmarshalText implements encoding.TextUnmarshaler for Action.
57
func (a *Action) UnmarshalText(text []byte) error {
58
if _, exists := actions[Action(text)]; exists {
59
*a = Action(text)
60
return nil
61
}
62
return fmt.Errorf("unrecognized action type %q", string(text))
63
}
64
65
// Regexp encapsulates the Regexp type from Grafana's fork of the Go stdlib regexp package.
66
type Regexp struct {
67
*regexp.Regexp
68
}
69
70
func newRegexp(s string) (Regexp, error) {
71
re, err := regexp.Compile("^(?:" + s + ")$")
72
return Regexp{re}, err
73
}
74
75
func mustNewRegexp(s string) Regexp {
76
re, err := newRegexp(s)
77
if err != nil {
78
panic(err)
79
}
80
return re
81
}
82
83
// MarshalText implements encoding.TextMarshaler for Regexp.
84
func (re Regexp) MarshalText() (text []byte, err error) {
85
if re.String() != "" {
86
return []byte(re.String()), nil
87
}
88
return nil, nil
89
}
90
91
// UnmarshalText implements encoding.TextUnmarshaler for Regexp.
92
func (re *Regexp) UnmarshalText(text []byte) error {
93
regex, err := regexp.Compile("^(?:" + string(text) + ")$")
94
if err != nil {
95
return err
96
}
97
98
*re = Regexp{regex}
99
return nil
100
}
101
102
// Config describes a relabelling step to be applied on a target.
103
type Config struct {
104
SourceLabels []string `river:"source_labels,attr,optional"`
105
Separator string `river:"separator,attr,optional"`
106
Regex Regexp `river:"regex,attr,optional"`
107
Modulus uint64 `river:"modulus,attr,optional"`
108
TargetLabel string `river:"target_label,attr,optional"`
109
Replacement string `river:"replacement,attr,optional"`
110
Action Action `river:"action,attr,optional"`
111
}
112
113
// DefaultRelabelConfig sets the default values of fields when decoding a RelabelConfig block.
114
var DefaultRelabelConfig = Config{
115
Action: Replace,
116
Separator: ";",
117
Regex: mustNewRegexp("(.*)"),
118
Replacement: "$1",
119
}
120
121
var relabelTarget = regexp.MustCompile(`^(?:(?:[a-zA-Z_]|\$(?:\{\w+\}|\w+))+\w*)+$`)
122
123
// UnmarshalRiver implements river.Unmarshaler.
124
func (rc *Config) UnmarshalRiver(f func(interface{}) error) error {
125
*rc = DefaultRelabelConfig
126
127
type relabelConfig Config
128
if err := f((*relabelConfig)(rc)); err != nil {
129
return err
130
}
131
132
if rc.Action == "" {
133
return fmt.Errorf("relabel action cannot be empty")
134
}
135
if rc.Modulus == 0 && rc.Action == HashMod {
136
return fmt.Errorf("relabel configuration for hashmod requires non-zero modulus")
137
}
138
if (rc.Action == Replace || rc.Action == KeepEqual || rc.Action == DropEqual || rc.Action == HashMod || rc.Action == Lowercase || rc.Action == Uppercase) && rc.TargetLabel == "" {
139
return fmt.Errorf("relabel configuration for %s action requires 'target_label' value", rc.Action)
140
}
141
if (rc.Action == KeepEqual || rc.Action == DropEqual) && rc.SourceLabels == nil {
142
return fmt.Errorf("relabel configuration for %s action requires 'source_labels' value", rc.Action)
143
}
144
if (rc.Action == Replace || rc.Action == Lowercase || rc.Action == Uppercase) && !relabelTarget.MatchString(rc.TargetLabel) {
145
return fmt.Errorf("%q is invalid 'target_label' for %s action", rc.TargetLabel, rc.Action)
146
}
147
if (rc.Action == Lowercase || rc.Action == Uppercase) && rc.Replacement != DefaultRelabelConfig.Replacement {
148
return fmt.Errorf("'replacement' can not be set for %s action", rc.Action)
149
}
150
if rc.Action == LabelMap && !relabelTarget.MatchString(rc.Replacement) {
151
return fmt.Errorf("%q is invalid 'replacement' for %s action", rc.Replacement, rc.Action)
152
}
153
if rc.Action == HashMod && !model.LabelName(rc.TargetLabel).IsValid() {
154
return fmt.Errorf("%q is invalid 'target_label' for %s action", rc.TargetLabel, rc.Action)
155
}
156
157
if rc.Action == LabelDrop || rc.Action == LabelKeep {
158
if rc.SourceLabels != nil ||
159
rc.TargetLabel != DefaultRelabelConfig.TargetLabel ||
160
rc.Modulus != DefaultRelabelConfig.Modulus ||
161
rc.Separator != DefaultRelabelConfig.Separator ||
162
rc.Replacement != DefaultRelabelConfig.Replacement {
163
164
return fmt.Errorf("%s action requires only 'regex', and no other fields", rc.Action)
165
}
166
}
167
168
if rc.Action == KeepEqual || rc.Action == DropEqual {
169
if rc.Regex != DefaultRelabelConfig.Regex ||
170
rc.Modulus != DefaultRelabelConfig.Modulus ||
171
rc.Separator != DefaultRelabelConfig.Separator ||
172
rc.Replacement != DefaultRelabelConfig.Replacement {
173
174
return fmt.Errorf("%s action requires only 'source_labels' and 'target_label', and no other fields", rc.Action)
175
}
176
}
177
178
return nil
179
}
180
181
// ComponentToPromRelabelConfigs bridges the Component-based configuration of
182
// relabeling steps to the Prometheus implementation.
183
func ComponentToPromRelabelConfigs(rcs []*Config) []*relabel.Config {
184
res := make([]*relabel.Config, len(rcs))
185
for i, rc := range rcs {
186
sourceLabels := make([]model.LabelName, len(rc.SourceLabels))
187
for i, sl := range rc.SourceLabels {
188
sourceLabels[i] = model.LabelName(sl)
189
}
190
191
res[i] = &relabel.Config{
192
SourceLabels: sourceLabels,
193
Separator: rc.Separator,
194
Modulus: rc.Modulus,
195
TargetLabel: rc.TargetLabel,
196
Replacement: rc.Replacement,
197
Action: relabel.Action(rc.Action),
198
Regex: relabel.Regexp{Regexp: rc.Regex.Regexp},
199
}
200
}
201
202
return res
203
}
204
205
// Rules returns the relabel configs in use for a relabeling component.
206
type Rules []*Config
207
208
// RiverCapsule marks the alias defined above as a "capsule type" so that it
209
// cannot be invoked by River code.
210
func (r Rules) RiverCapsule() {}
211
212