mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-28 23:19:41 -08:00
e1d5eb52f2
ReplaceAllString only replaces the matching part of the regex, the unmatched bits around it are left in place. This is not the expected or desired behaviour as the replacement string should be everything. This may break users dependant on this behaviour, but what they're doing is still possible.
94 lines
2.3 KiB
Go
94 lines
2.3 KiB
Go
package retrieval
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"fmt"
|
|
"strings"
|
|
|
|
clientmodel "github.com/prometheus/client_golang/model"
|
|
|
|
"github.com/prometheus/prometheus/config"
|
|
)
|
|
|
|
// Relabel returns a relabeled copy of the given label set. The relabel configurations
|
|
// are applied in order of input.
|
|
// If a label set is dropped, nil is returned.
|
|
func Relabel(labels clientmodel.LabelSet, cfgs ...*config.RelabelConfig) (clientmodel.LabelSet, error) {
|
|
out := clientmodel.LabelSet{}
|
|
for ln, lv := range labels {
|
|
out[ln] = lv
|
|
}
|
|
var err error
|
|
for _, cfg := range cfgs {
|
|
if out, err = relabel(out, cfg); err != nil {
|
|
return nil, err
|
|
}
|
|
if out == nil {
|
|
return nil, nil
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func relabel(labels clientmodel.LabelSet, cfg *config.RelabelConfig) (clientmodel.LabelSet, error) {
|
|
values := make([]string, 0, len(cfg.SourceLabels))
|
|
for _, ln := range cfg.SourceLabels {
|
|
values = append(values, string(labels[ln]))
|
|
}
|
|
val := strings.Join(values, cfg.Separator)
|
|
|
|
switch cfg.Action {
|
|
case config.RelabelDrop:
|
|
if cfg.Regex.MatchString(val) {
|
|
return nil, nil
|
|
}
|
|
case config.RelabelKeep:
|
|
if !cfg.Regex.MatchString(val) {
|
|
return nil, nil
|
|
}
|
|
case config.RelabelReplace:
|
|
indexes := cfg.Regex.FindStringSubmatchIndex(val)
|
|
// If there is no match no replacement must take place.
|
|
if indexes == nil {
|
|
break
|
|
}
|
|
res := cfg.Regex.ExpandString([]byte{}, cfg.Replacement, val, indexes)
|
|
if len(res) == 0 {
|
|
delete(labels, cfg.TargetLabel)
|
|
} else {
|
|
labels[cfg.TargetLabel] = clientmodel.LabelValue(res)
|
|
}
|
|
case config.RelabelHashMod:
|
|
mod := sum64(md5.Sum([]byte(val))) % cfg.Modulus
|
|
labels[cfg.TargetLabel] = clientmodel.LabelValue(fmt.Sprintf("%d", mod))
|
|
case config.RelabelLabelMap:
|
|
out := make(clientmodel.LabelSet, len(labels))
|
|
// Take a copy to avoid infinite loops.
|
|
for ln, lv := range labels {
|
|
out[ln] = lv
|
|
}
|
|
for ln, lv := range labels {
|
|
if cfg.Regex.MatchString(string(ln)) {
|
|
res := cfg.Regex.ReplaceAllString(string(ln), cfg.Replacement)
|
|
out[clientmodel.LabelName(res)] = lv
|
|
}
|
|
}
|
|
labels = out
|
|
default:
|
|
panic(fmt.Errorf("retrieval.relabel: unknown relabel action type %q", cfg.Action))
|
|
}
|
|
return labels, nil
|
|
}
|
|
|
|
// sum64 sums the md5 hash to an uint64.
|
|
func sum64(hash [md5.Size]byte) uint64 {
|
|
var s uint64
|
|
|
|
for i, b := range hash {
|
|
shift := uint64((md5.Size - i - 1) * 8)
|
|
|
|
s |= uint64(b) << shift
|
|
}
|
|
return s
|
|
}
|