github.com/grafana/pyroscope@v1.18.0/pkg/validation/relabeling.go (about)

     1  package validation
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  
     7  	"gopkg.in/yaml.v3"
     8  
     9  	"github.com/prometheus/common/model"
    10  	"github.com/prometheus/prometheus/model/relabel"
    11  )
    12  
    13  var (
    14  	godeltaprof         = relabel.MustNewRegexp("godeltaprof_(.*)")
    15  	defaultRelabelRules = []*relabel.Config{
    16  		// replace godeltaprof_ prefix from name
    17  		{
    18  			SourceLabels: []model.LabelName{"__name__"},
    19  			Action:       relabel.Replace,
    20  			Regex:        godeltaprof,
    21  			TargetLabel:  "__name_replaced__",
    22  			Replacement:  "$0",
    23  		},
    24  		{
    25  			SourceLabels: []model.LabelName{"__name_replaced__"},
    26  			Action:       relabel.Replace,
    27  			Regex:        godeltaprof,
    28  			TargetLabel:  "__delta__",
    29  			Replacement:  "false",
    30  		},
    31  		{
    32  			SourceLabels: []model.LabelName{"__name__"},
    33  			Regex:        godeltaprof,
    34  			Action:       relabel.Replace,
    35  			TargetLabel:  "__name__",
    36  			Replacement:  "$1",
    37  		},
    38  		// replace wall with process_cpu when __type__ is cpu
    39  		{
    40  			SourceLabels: []model.LabelName{"__name__", "__type__"},
    41  			Separator:    "/",
    42  			Regex:        relabel.MustNewRegexp("wall/cpu"),
    43  			Action:       relabel.Replace,
    44  			Replacement:  "wall",
    45  			TargetLabel:  "__name_replaced__",
    46  		},
    47  		{
    48  			SourceLabels: []model.LabelName{"__name__", "__type__"},
    49  			Separator:    "/",
    50  			Regex:        relabel.MustNewRegexp("wall/cpu"),
    51  			Action:       relabel.Replace,
    52  			Replacement:  "process_cpu",
    53  			TargetLabel:  "__name__",
    54  		},
    55  	}
    56  )
    57  
    58  type RelabelRulesPosition string
    59  
    60  func (p *RelabelRulesPosition) Set(s string) error {
    61  	switch sp := RelabelRulesPosition(s); sp {
    62  	case RelabelRulePositionFirst, RelabelRulePositionLast, RelabelRulePositionDisabled:
    63  		*p = sp
    64  		return nil
    65  	}
    66  	return fmt.Errorf("invalid ingestion_relabeling_default_rules_position: %s", s)
    67  }
    68  
    69  func (p *RelabelRulesPosition) String() string {
    70  	return string(*p)
    71  }
    72  
    73  const (
    74  	RelabelRulePositionFirst    RelabelRulesPosition = "first"
    75  	RelabelRulePositionDisabled RelabelRulesPosition = "disabled"
    76  	RelabelRulePositionLast     RelabelRulesPosition = "last"
    77  )
    78  
    79  type RelabelRules []*relabel.Config
    80  
    81  func (p *RelabelRules) Set(s string) error {
    82  	v := []*relabel.Config{}
    83  	if err := yaml.Unmarshal([]byte(s), &v); err != nil {
    84  		return err
    85  	}
    86  
    87  	for idx, rule := range v {
    88  		if err := rule.Validate(); err != nil {
    89  			return fmt.Errorf("rule at pos %d is not valid: %w", idx, err)
    90  		}
    91  	}
    92  	*p = v
    93  	return nil
    94  }
    95  
    96  func (p *RelabelRules) String() string {
    97  	yamlBytes, err := yaml.Marshal(p)
    98  	if err != nil {
    99  		panic(fmt.Errorf("error marshal yaml: %w", err))
   100  	}
   101  
   102  	temp := make([]interface{}, 0, len(*p))
   103  	err = yaml.Unmarshal(yamlBytes, &temp)
   104  	if err != nil {
   105  		panic(fmt.Errorf("error unmarshal yaml: %w", err))
   106  	}
   107  
   108  	jsonBytes, err := json.Marshal(temp)
   109  	if err != nil {
   110  		panic(fmt.Errorf("error marshal json: %w", err))
   111  	}
   112  	return string(jsonBytes)
   113  }
   114  
   115  type IngestionRelabelRules []*relabel.Config
   116  
   117  func (r *IngestionRelabelRules) Set(s string) error {
   118  	return (*RelabelRules)(r).Set(s)
   119  }
   120  
   121  func (r *IngestionRelabelRules) String() string {
   122  	return (*RelabelRules)(r).String()
   123  }
   124  
   125  func (r *IngestionRelabelRules) ExampleDoc() (comment string, yaml interface{}) {
   126  	return `This example consists of two rules, the first one will drop all profiles received with an label 'environment="secrets"' and the second rule will add a label 'powered_by="Grafana Labs"' to all profile series.`,
   127  		[]map[string]interface{}{
   128  			{"action": "drop", "source_labels": []interface{}{"environment"}, "regex": "secret"},
   129  			{"action": "replace", "replacement": "grafana-labs", "target_label": "powered_by"},
   130  		}
   131  }
   132  
   133  type SampleTypeRelabelRules []*relabel.Config
   134  
   135  func (r *SampleTypeRelabelRules) Set(s string) error {
   136  	if err := (*RelabelRules)(r).Set(s); err != nil {
   137  		return err
   138  	}
   139  
   140  	for idx, rule := range *r {
   141  		if rule.Action != relabel.Drop && rule.Action != relabel.Keep {
   142  			return fmt.Errorf("rule at pos %d: sample type relabeling only supports 'drop' and 'keep' actions, got '%s'", idx, rule.Action)
   143  		}
   144  	}
   145  	return nil
   146  }
   147  
   148  func (r *SampleTypeRelabelRules) String() string {
   149  	return (*RelabelRules)(r).String()
   150  }
   151  
   152  func (r *SampleTypeRelabelRules) ExampleDoc() (comment string, yaml interface{}) {
   153  	return `This example shows sample type filtering rules. The first rule drops all allocation-related sample types (alloc_objects, alloc_space) from memory profiles, keeping only in-use metrics. The second rule keeps only CPU-related sample types by matching the __type__ label. The third rule shows how to drop allocation sample types for a specific service by combining __type__ and service_name labels.`,
   154  		[]map[string]interface{}{
   155  			{"action": "drop", "source_labels": []interface{}{"__type__"}, "regex": "alloc_.*"},
   156  			{"action": "keep", "source_labels": []interface{}{"__type__"}, "regex": "cpu|wall"},
   157  			{"action": "drop", "source_labels": []interface{}{"__type__", "service_name"}, "separator": ";", "regex": "alloc_.*;my-service"},
   158  		}
   159  }
   160  
   161  func (o *Overrides) IngestionRelabelingRules(tenantID string) []*relabel.Config {
   162  	l := o.getOverridesForTenant(tenantID)
   163  
   164  	// return only custom rules when default rules are disabled
   165  	if l.IngestionRelabelingDefaultRulesPosition == RelabelRulePositionDisabled {
   166  		return l.IngestionRelabelingRules
   167  	}
   168  
   169  	// quick return if no rules are defined
   170  	if len(l.IngestionRelabelingRules) == 0 {
   171  		return defaultRelabelRules
   172  	}
   173  
   174  	rules := make([]*relabel.Config, 0, len(l.IngestionRelabelingRules)+len(defaultRelabelRules))
   175  
   176  	if l.IngestionRelabelingDefaultRulesPosition == "" || l.IngestionRelabelingDefaultRulesPosition == RelabelRulePositionFirst {
   177  		rules = append(rules, defaultRelabelRules...)
   178  		return append(rules, l.IngestionRelabelingRules...)
   179  	}
   180  
   181  	rules = append(rules, l.IngestionRelabelingRules...)
   182  	return append(rules, defaultRelabelRules...)
   183  }
   184  
   185  func (o *Overrides) SampleTypeRelabelingRules(tenantID string) []*relabel.Config {
   186  	l := o.getOverridesForTenant(tenantID)
   187  	return l.SampleTypeRelabelingRules
   188  }