github.com/grafana/pyroscope@v1.18.0/pkg/model/relabel/relabel.go (about) 1 // Provenance-includes-location: https://github.com/prometheus/prometheus/blob/v2.51.2/model/relabel/relabel.go 2 // Provenance-includes-license: Apache-2.0 3 // Provenance-includes-copyright: Prometheus Authors 4 5 package relabel 6 7 import ( 8 "crypto/md5" 9 "encoding/binary" 10 "fmt" 11 "strconv" 12 "strings" 13 14 "github.com/prometheus/common/model" 15 "github.com/prometheus/prometheus/model/relabel" 16 17 typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" 18 phlaremodel "github.com/grafana/pyroscope/pkg/model" 19 ) 20 21 type Config = relabel.Config 22 23 // Process returns a relabeled version of the given label set. The relabel configurations 24 // are applied in order of input. 25 // There are circumstances where Process will modify the input label. 26 // If you want to avoid issues with the input label set being modified, at the cost of 27 // higher memory usage, you can use lbls.Copy(). 28 // If a label set is dropped, EmptyLabels and false is returned. 29 func Process(lbls phlaremodel.Labels, cfgs ...*relabel.Config) (ret phlaremodel.Labels, keep bool) { 30 lb := phlaremodel.NewLabelsBuilder(lbls) 31 if !ProcessBuilder(lb, cfgs...) { 32 return phlaremodel.EmptyLabels(), false 33 } 34 return lb.Labels(), true 35 } 36 37 // ProcessBuilder is like Process, but the caller passes a labels.Builder 38 // containing the initial set of labels, which is mutated by the rules. 39 func ProcessBuilder(lb *phlaremodel.LabelsBuilder, cfgs ...*Config) (keep bool) { 40 for _, cfg := range cfgs { 41 keep = relabelBuilder(cfg, lb) 42 if !keep { 43 return false 44 } 45 } 46 return true 47 } 48 49 func relabelBuilder(cfg *Config, lb *phlaremodel.LabelsBuilder) (keep bool) { 50 var va [16]string 51 values := va[:0] 52 if len(cfg.SourceLabels) > cap(values) { 53 values = make([]string, 0, len(cfg.SourceLabels)) 54 } 55 for _, ln := range cfg.SourceLabels { 56 values = append(values, lb.Get(string(ln))) 57 } 58 val := strings.Join(values, cfg.Separator) 59 60 switch cfg.Action { 61 case relabel.Drop: 62 if cfg.Regex.MatchString(val) { 63 return false 64 } 65 case relabel.Keep: 66 if !cfg.Regex.MatchString(val) { 67 return false 68 } 69 case relabel.DropEqual: 70 if lb.Get(cfg.TargetLabel) == val { 71 return false 72 } 73 case relabel.KeepEqual: 74 if lb.Get(cfg.TargetLabel) != val { 75 return false 76 } 77 case relabel.Replace: 78 indexes := cfg.Regex.FindStringSubmatchIndex(val) 79 // If there is no match no replacement must take place. 80 if indexes == nil { 81 break 82 } 83 target := model.LabelName(cfg.Regex.ExpandString([]byte{}, cfg.TargetLabel, val, indexes)) 84 if !model.UTF8Validation.IsValidLabelName(string(target)) { 85 break 86 } 87 res := cfg.Regex.ExpandString([]byte{}, cfg.Replacement, val, indexes) 88 if len(res) == 0 { 89 lb.Del(string(target)) 90 break 91 } 92 lb.Set(string(target), string(res)) 93 case relabel.Lowercase: 94 lb.Set(cfg.TargetLabel, strings.ToLower(val)) 95 case relabel.Uppercase: 96 lb.Set(cfg.TargetLabel, strings.ToUpper(val)) 97 case relabel.HashMod: 98 hash := md5.Sum([]byte(val)) 99 // Use only the last 8 bytes of the hash to give the same result as earlier versions of this code. 100 mod := binary.BigEndian.Uint64(hash[8:]) % cfg.Modulus 101 lb.Set(cfg.TargetLabel, strconv.FormatUint(mod, 10)) 102 case relabel.LabelMap: 103 lb.Range(func(l *typesv1.LabelPair) { 104 if cfg.Regex.MatchString(l.Name) { 105 res := cfg.Regex.ReplaceAllString(l.Name, cfg.Replacement) 106 lb.Set(res, l.Value) 107 } 108 }) 109 case relabel.LabelDrop: 110 lb.Range(func(l *typesv1.LabelPair) { 111 if cfg.Regex.MatchString(l.Name) { 112 lb.Del(l.Name) 113 } 114 }) 115 case relabel.LabelKeep: 116 lb.Range(func(l *typesv1.LabelPair) { 117 if !cfg.Regex.MatchString(l.Name) { 118 lb.Del(l.Name) 119 } 120 }) 121 default: 122 panic(fmt.Errorf("relabel: unknown relabel action type %q", cfg.Action)) 123 } 124 125 return true 126 }