github.com/grafana/pyroscope@v1.18.0/pkg/model/relabel/relabel_test.go (about)

     1  // Provenance-includes-location: https://github.com/prometheus/prometheus/blob/v2.51.2/model/relabel/relabel_test.go
     2  // Provenance-includes-license: Apache-2.0
     3  // Provenance-includes-copyright: Prometheus Authors
     4  
     5  package relabel
     6  
     7  import (
     8  	"testing"
     9  
    10  	"github.com/google/go-cmp/cmp"
    11  	"github.com/google/go-cmp/cmp/cmpopts"
    12  	"github.com/prometheus/common/model"
    13  	"github.com/prometheus/prometheus/model/relabel"
    14  	"github.com/prometheus/prometheus/util/testutil"
    15  	"github.com/stretchr/testify/require"
    16  
    17  	typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1"
    18  	phlaremodel "github.com/grafana/pyroscope/pkg/model"
    19  )
    20  
    21  func TestRelabel(t *testing.T) {
    22  	tests := []struct {
    23  		input   phlaremodel.Labels
    24  		relabel []*relabel.Config
    25  		output  phlaremodel.Labels
    26  		drop    bool
    27  	}{
    28  		{
    29  			input: phlaremodel.LabelsFromMap(map[string]string{
    30  				"a": "foo",
    31  				"b": "bar",
    32  				"c": "baz",
    33  			}),
    34  			relabel: []*relabel.Config{
    35  				{
    36  					SourceLabels: model.LabelNames{"a"},
    37  					Regex:        relabel.MustNewRegexp("f(.*)"),
    38  					TargetLabel:  "d",
    39  					Separator:    ";",
    40  					Replacement:  "ch${1}-ch${1}",
    41  					Action:       relabel.Replace,
    42  				},
    43  			},
    44  			output: phlaremodel.LabelsFromMap(map[string]string{
    45  				"a": "foo",
    46  				"b": "bar",
    47  				"c": "baz",
    48  				"d": "choo-choo",
    49  			}),
    50  		},
    51  		{
    52  			input: phlaremodel.LabelsFromMap(map[string]string{
    53  				"a": "foo",
    54  				"b": "bar",
    55  				"c": "baz",
    56  			}),
    57  			relabel: []*relabel.Config{
    58  				{
    59  					SourceLabels: model.LabelNames{"a", "b"},
    60  					Regex:        relabel.MustNewRegexp("f(.*);(.*)r"),
    61  					TargetLabel:  "a",
    62  					Separator:    ";",
    63  					Replacement:  "b${1}${2}m", // boobam
    64  					Action:       relabel.Replace,
    65  				},
    66  				{
    67  					SourceLabels: model.LabelNames{"c", "a"},
    68  					Regex:        relabel.MustNewRegexp("(b).*b(.*)ba(.*)"),
    69  					TargetLabel:  "d",
    70  					Separator:    ";",
    71  					Replacement:  "$1$2$2$3",
    72  					Action:       relabel.Replace,
    73  				},
    74  			},
    75  			output: phlaremodel.LabelsFromMap(map[string]string{
    76  				"a": "boobam",
    77  				"b": "bar",
    78  				"c": "baz",
    79  				"d": "boooom",
    80  			}),
    81  		},
    82  		{
    83  			input: phlaremodel.LabelsFromMap(map[string]string{
    84  				"a": "foo",
    85  			}),
    86  			relabel: []*relabel.Config{
    87  				{
    88  					SourceLabels: model.LabelNames{"a"},
    89  					Regex:        relabel.MustNewRegexp(".*o.*"),
    90  					Action:       relabel.Drop,
    91  				}, {
    92  					SourceLabels: model.LabelNames{"a"},
    93  					Regex:        relabel.MustNewRegexp("f(.*)"),
    94  					TargetLabel:  "d",
    95  					Separator:    ";",
    96  					Replacement:  "ch$1-ch$1",
    97  					Action:       relabel.Replace,
    98  				},
    99  			},
   100  			drop: true,
   101  		},
   102  		{
   103  			input: phlaremodel.LabelsFromMap(map[string]string{
   104  				"a": "foo",
   105  				"b": "bar",
   106  			}),
   107  			relabel: []*relabel.Config{
   108  				{
   109  					SourceLabels: model.LabelNames{"a"},
   110  					Regex:        relabel.MustNewRegexp(".*o.*"),
   111  					Action:       relabel.Drop,
   112  				},
   113  			},
   114  			drop: true,
   115  		},
   116  		{
   117  			input: phlaremodel.LabelsFromMap(map[string]string{
   118  				"a": "abc",
   119  			}),
   120  			relabel: []*relabel.Config{
   121  				{
   122  					SourceLabels: model.LabelNames{"a"},
   123  					Regex:        relabel.MustNewRegexp(".*(b).*"),
   124  					TargetLabel:  "d",
   125  					Separator:    ";",
   126  					Replacement:  "$1",
   127  					Action:       relabel.Replace,
   128  				},
   129  			},
   130  			output: phlaremodel.LabelsFromMap(map[string]string{
   131  				"a": "abc",
   132  				"d": "b",
   133  			}),
   134  		},
   135  		{
   136  			input: phlaremodel.LabelsFromMap(map[string]string{
   137  				"a": "foo",
   138  			}),
   139  			relabel: []*relabel.Config{
   140  				{
   141  					SourceLabels: model.LabelNames{"a"},
   142  					Regex:        relabel.MustNewRegexp("no-match"),
   143  					Action:       relabel.Drop,
   144  				},
   145  			},
   146  			output: phlaremodel.LabelsFromMap(map[string]string{
   147  				"a": "foo",
   148  			}),
   149  		},
   150  		{
   151  			input: phlaremodel.LabelsFromMap(map[string]string{
   152  				"a": "foo",
   153  			}),
   154  			relabel: []*relabel.Config{
   155  				{
   156  					SourceLabels: model.LabelNames{"a"},
   157  					Regex:        relabel.MustNewRegexp("f|o"),
   158  					Action:       relabel.Drop,
   159  				},
   160  			},
   161  			output: phlaremodel.LabelsFromMap(map[string]string{
   162  				"a": "foo",
   163  			}),
   164  		},
   165  		{
   166  			input: phlaremodel.LabelsFromMap(map[string]string{
   167  				"a": "foo",
   168  			}),
   169  			relabel: []*relabel.Config{
   170  				{
   171  					SourceLabels: model.LabelNames{"a"},
   172  					Regex:        relabel.MustNewRegexp("no-match"),
   173  					Action:       relabel.Keep,
   174  				},
   175  			},
   176  			drop: true,
   177  		},
   178  		{
   179  			input: phlaremodel.LabelsFromMap(map[string]string{
   180  				"a": "foo",
   181  			}),
   182  			relabel: []*relabel.Config{
   183  				{
   184  					SourceLabels: model.LabelNames{"a"},
   185  					Regex:        relabel.MustNewRegexp("f.*"),
   186  					Action:       relabel.Keep,
   187  				},
   188  			},
   189  			output: phlaremodel.LabelsFromMap(map[string]string{
   190  				"a": "foo",
   191  			}),
   192  		},
   193  		{
   194  			// No replacement must be applied if there is no match.
   195  			input: phlaremodel.LabelsFromMap(map[string]string{
   196  				"a": "boo",
   197  			}),
   198  			relabel: []*relabel.Config{
   199  				{
   200  					SourceLabels: model.LabelNames{"a"},
   201  					Regex:        relabel.MustNewRegexp("f"),
   202  					TargetLabel:  "b",
   203  					Replacement:  "bar",
   204  					Action:       relabel.Replace,
   205  				},
   206  			},
   207  			output: phlaremodel.LabelsFromMap(map[string]string{
   208  				"a": "boo",
   209  			}),
   210  		},
   211  		{
   212  			// Blank replacement should delete the label.
   213  			input: phlaremodel.LabelsFromMap(map[string]string{
   214  				"a": "foo",
   215  				"f": "baz",
   216  			}),
   217  			relabel: []*relabel.Config{
   218  				{
   219  					SourceLabels: model.LabelNames{"a"},
   220  					Regex:        relabel.MustNewRegexp("(f).*"),
   221  					TargetLabel:  "$1",
   222  					Replacement:  "$2",
   223  					Action:       relabel.Replace,
   224  				},
   225  			},
   226  			output: phlaremodel.LabelsFromMap(map[string]string{
   227  				"a": "foo",
   228  			}),
   229  		},
   230  		{
   231  			input: phlaremodel.LabelsFromMap(map[string]string{
   232  				"a": "foo",
   233  				"b": "bar",
   234  				"c": "baz",
   235  			}),
   236  			relabel: []*relabel.Config{
   237  				{
   238  					SourceLabels: model.LabelNames{"c"},
   239  					TargetLabel:  "d",
   240  					Separator:    ";",
   241  					Action:       relabel.HashMod,
   242  					Modulus:      1000,
   243  				},
   244  			},
   245  			output: phlaremodel.LabelsFromMap(map[string]string{
   246  				"a": "foo",
   247  				"b": "bar",
   248  				"c": "baz",
   249  				"d": "976",
   250  			}),
   251  		},
   252  		{
   253  			input: phlaremodel.LabelsFromMap(map[string]string{
   254  				"a": "foo\nbar",
   255  			}),
   256  			relabel: []*relabel.Config{
   257  				{
   258  					SourceLabels: model.LabelNames{"a"},
   259  					TargetLabel:  "b",
   260  					Separator:    ";",
   261  					Action:       relabel.HashMod,
   262  					Modulus:      1000,
   263  				},
   264  			},
   265  			output: phlaremodel.LabelsFromMap(map[string]string{
   266  				"a": "foo\nbar",
   267  				"b": "734",
   268  			}),
   269  		},
   270  		{
   271  			input: phlaremodel.LabelsFromMap(map[string]string{
   272  				"a":  "foo",
   273  				"b1": "bar",
   274  				"b2": "baz",
   275  			}),
   276  			relabel: []*relabel.Config{
   277  				{
   278  					Regex:       relabel.MustNewRegexp("(b.*)"),
   279  					Replacement: "bar_${1}",
   280  					Action:      relabel.LabelMap,
   281  				},
   282  			},
   283  			output: phlaremodel.LabelsFromMap(map[string]string{
   284  				"a":      "foo",
   285  				"b1":     "bar",
   286  				"b2":     "baz",
   287  				"bar_b1": "bar",
   288  				"bar_b2": "baz",
   289  			}),
   290  		},
   291  		{
   292  			input: phlaremodel.LabelsFromMap(map[string]string{
   293  				"a":             "foo",
   294  				"__meta_my_bar": "aaa",
   295  				"__meta_my_baz": "bbb",
   296  				"__meta_other":  "ccc",
   297  			}),
   298  			relabel: []*relabel.Config{
   299  				{
   300  					Regex:       relabel.MustNewRegexp("__meta_(my.*)"),
   301  					Replacement: "${1}",
   302  					Action:      relabel.LabelMap,
   303  				},
   304  			},
   305  			output: phlaremodel.LabelsFromMap(map[string]string{
   306  				"a":             "foo",
   307  				"__meta_my_bar": "aaa",
   308  				"__meta_my_baz": "bbb",
   309  				"__meta_other":  "ccc",
   310  				"my_bar":        "aaa",
   311  				"my_baz":        "bbb",
   312  			}),
   313  		},
   314  		{ // valid case
   315  			input: phlaremodel.LabelsFromMap(map[string]string{
   316  				"a": "some-name-value",
   317  			}),
   318  			relabel: []*relabel.Config{
   319  				{
   320  					SourceLabels: model.LabelNames{"a"},
   321  					Regex:        relabel.MustNewRegexp("some-([^-]+)-([^,]+)"),
   322  					Action:       relabel.Replace,
   323  					Replacement:  "${2}",
   324  					TargetLabel:  "${1}",
   325  				},
   326  			},
   327  			output: phlaremodel.LabelsFromMap(map[string]string{
   328  				"a":    "some-name-value",
   329  				"name": "value",
   330  			}),
   331  		},
   332  		{ // invalid replacement ""
   333  			input: phlaremodel.LabelsFromMap(map[string]string{
   334  				"a": "some-name-value",
   335  			}),
   336  			relabel: []*relabel.Config{
   337  				{
   338  					SourceLabels: model.LabelNames{"a"},
   339  					Regex:        relabel.MustNewRegexp("some-([^-]+)-([^,]+)"),
   340  					Action:       relabel.Replace,
   341  					Replacement:  "${3}",
   342  					TargetLabel:  "${1}",
   343  				},
   344  			},
   345  			output: phlaremodel.LabelsFromMap(map[string]string{
   346  				"a": "some-name-value",
   347  			}),
   348  		},
   349  		{ // invalid target_labels
   350  			input: phlaremodel.LabelsFromMap(map[string]string{
   351  				"a": "some-name-0",
   352  			}),
   353  			relabel: []*relabel.Config{
   354  				{
   355  					SourceLabels: model.LabelNames{"a"},
   356  					Regex:        relabel.MustNewRegexp("some-([^-]+)-([^,]+)"),
   357  					Action:       relabel.Replace,
   358  					Replacement:  "${1}",
   359  					TargetLabel:  "${3}",
   360  				},
   361  				{
   362  					SourceLabels: model.LabelNames{"a"},
   363  					Regex:        relabel.MustNewRegexp("some-([^-]+)-([^,]+)"),
   364  					Action:       relabel.Replace,
   365  					Replacement:  "${1}",
   366  					TargetLabel:  "${3}",
   367  				},
   368  				{
   369  					SourceLabels: model.LabelNames{"a"},
   370  					Regex:        relabel.MustNewRegexp("some-([^-]+)(-[^,]+)"),
   371  					Action:       relabel.Replace,
   372  					Replacement:  "${1}",
   373  					TargetLabel:  "${3}",
   374  				},
   375  			},
   376  			output: phlaremodel.LabelsFromMap(map[string]string{
   377  				"a": "some-name-0",
   378  			}),
   379  		},
   380  		{ // more complex real-life like usecase
   381  			input: phlaremodel.LabelsFromMap(map[string]string{
   382  				"__meta_sd_tags": "path:/secret,job:some-job,label:foo=bar",
   383  			}),
   384  			relabel: []*relabel.Config{
   385  				{
   386  					SourceLabels: model.LabelNames{"__meta_sd_tags"},
   387  					Regex:        relabel.MustNewRegexp("(?:.+,|^)path:(/[^,]+).*"),
   388  					Action:       relabel.Replace,
   389  					Replacement:  "${1}",
   390  					TargetLabel:  "__metrics_path__",
   391  				},
   392  				{
   393  					SourceLabels: model.LabelNames{"__meta_sd_tags"},
   394  					Regex:        relabel.MustNewRegexp("(?:.+,|^)job:([^,]+).*"),
   395  					Action:       relabel.Replace,
   396  					Replacement:  "${1}",
   397  					TargetLabel:  "job",
   398  				},
   399  				{
   400  					SourceLabels: model.LabelNames{"__meta_sd_tags"},
   401  					Regex:        relabel.MustNewRegexp("(?:.+,|^)label:([^=]+)=([^,]+).*"),
   402  					Action:       relabel.Replace,
   403  					Replacement:  "${2}",
   404  					TargetLabel:  "${1}",
   405  				},
   406  			},
   407  			output: phlaremodel.LabelsFromMap(map[string]string{
   408  				"__meta_sd_tags":   "path:/secret,job:some-job,label:foo=bar",
   409  				"__metrics_path__": "/secret",
   410  				"job":              "some-job",
   411  				"foo":              "bar",
   412  			}),
   413  		},
   414  		{ // From https://github.com/prometheus/prometheus/issues/12283
   415  			input: phlaremodel.LabelsFromMap(map[string]string{
   416  				"__meta_kubernetes_pod_container_port_name":         "foo",
   417  				"__meta_kubernetes_pod_annotation_XXX_metrics_port": "9091",
   418  			}),
   419  			relabel: []*relabel.Config{
   420  				{
   421  					Regex:  relabel.MustNewRegexp("^__meta_kubernetes_pod_container_port_name$"),
   422  					Action: relabel.LabelDrop,
   423  				},
   424  				{
   425  					SourceLabels: model.LabelNames{"__meta_kubernetes_pod_annotation_XXX_metrics_port"},
   426  					Regex:        relabel.MustNewRegexp("(.+)"),
   427  					Action:       relabel.Replace,
   428  					Replacement:  "metrics",
   429  					TargetLabel:  "__meta_kubernetes_pod_container_port_name",
   430  				},
   431  				{
   432  					SourceLabels: model.LabelNames{"__meta_kubernetes_pod_container_port_name"},
   433  					Regex:        relabel.MustNewRegexp("^metrics$"),
   434  					Action:       relabel.Keep,
   435  				},
   436  			},
   437  			output: phlaremodel.LabelsFromMap(map[string]string{
   438  				"__meta_kubernetes_pod_annotation_XXX_metrics_port": "9091",
   439  				"__meta_kubernetes_pod_container_port_name":         "metrics",
   440  			}),
   441  		},
   442  		{
   443  			input: phlaremodel.LabelsFromMap(map[string]string{
   444  				"a":  "foo",
   445  				"b1": "bar",
   446  				"b2": "baz",
   447  			}),
   448  			relabel: []*relabel.Config{
   449  				{
   450  					Regex:  relabel.MustNewRegexp("(b.*)"),
   451  					Action: relabel.LabelKeep,
   452  				},
   453  			},
   454  			output: phlaremodel.LabelsFromMap(map[string]string{
   455  				"b1": "bar",
   456  				"b2": "baz",
   457  			}),
   458  		},
   459  		{
   460  			input: phlaremodel.LabelsFromMap(map[string]string{
   461  				"a":  "foo",
   462  				"b1": "bar",
   463  				"b2": "baz",
   464  			}),
   465  			relabel: []*relabel.Config{
   466  				{
   467  					Regex:  relabel.MustNewRegexp("(b.*)"),
   468  					Action: relabel.LabelDrop,
   469  				},
   470  			},
   471  			output: phlaremodel.LabelsFromMap(map[string]string{
   472  				"a": "foo",
   473  			}),
   474  		},
   475  		{
   476  			input: phlaremodel.LabelsFromMap(map[string]string{
   477  				"foo": "bAr123Foo",
   478  			}),
   479  			relabel: []*relabel.Config{
   480  				{
   481  					SourceLabels: model.LabelNames{"foo"},
   482  					Action:       relabel.Uppercase,
   483  					TargetLabel:  "foo_uppercase",
   484  				},
   485  				{
   486  					SourceLabels: model.LabelNames{"foo"},
   487  					Action:       relabel.Lowercase,
   488  					TargetLabel:  "foo_lowercase",
   489  				},
   490  			},
   491  			output: phlaremodel.LabelsFromMap(map[string]string{
   492  				"foo":           "bAr123Foo",
   493  				"foo_lowercase": "bar123foo",
   494  				"foo_uppercase": "BAR123FOO",
   495  			}),
   496  		},
   497  		{
   498  			input: phlaremodel.LabelsFromMap(map[string]string{
   499  				"__tmp_port": "1234",
   500  				"__port1":    "1234",
   501  				"__port2":    "5678",
   502  			}),
   503  			relabel: []*relabel.Config{
   504  				{
   505  					SourceLabels: model.LabelNames{"__tmp_port"},
   506  					Action:       relabel.KeepEqual,
   507  					TargetLabel:  "__port1",
   508  				},
   509  			},
   510  			output: phlaremodel.LabelsFromMap(map[string]string{
   511  				"__tmp_port": "1234",
   512  				"__port1":    "1234",
   513  				"__port2":    "5678",
   514  			}),
   515  		},
   516  		{
   517  			input: phlaremodel.LabelsFromMap(map[string]string{
   518  				"__tmp_port": "1234",
   519  				"__port1":    "1234",
   520  				"__port2":    "5678",
   521  			}),
   522  			relabel: []*relabel.Config{
   523  				{
   524  					SourceLabels: model.LabelNames{"__tmp_port"},
   525  					Action:       relabel.DropEqual,
   526  					TargetLabel:  "__port1",
   527  				},
   528  			},
   529  			drop: true,
   530  		},
   531  		{
   532  			input: phlaremodel.LabelsFromMap(map[string]string{
   533  				"__tmp_port": "1234",
   534  				"__port1":    "1234",
   535  				"__port2":    "5678",
   536  			}),
   537  			relabel: []*relabel.Config{
   538  				{
   539  					SourceLabels: model.LabelNames{"__tmp_port"},
   540  					Action:       relabel.DropEqual,
   541  					TargetLabel:  "__port2",
   542  				},
   543  			},
   544  			output: phlaremodel.LabelsFromMap(map[string]string{
   545  				"__tmp_port": "1234",
   546  				"__port1":    "1234",
   547  				"__port2":    "5678",
   548  			}),
   549  		},
   550  		{
   551  			input: phlaremodel.LabelsFromMap(map[string]string{
   552  				"__tmp_port": "1234",
   553  				"__port1":    "1234",
   554  				"__port2":    "5678",
   555  			}),
   556  			relabel: []*relabel.Config{
   557  				{
   558  					SourceLabels: model.LabelNames{"__tmp_port"},
   559  					Action:       relabel.KeepEqual,
   560  					TargetLabel:  "__port2",
   561  				},
   562  			},
   563  			drop: true,
   564  		},
   565  	}
   566  
   567  	for _, test := range tests {
   568  		// Setting default fields, mimicking the behaviour in Prometheus.
   569  		for _, cfg := range test.relabel {
   570  			if cfg.Action == "" {
   571  				cfg.Action = relabel.DefaultRelabelConfig.Action
   572  			}
   573  			if cfg.Separator == "" {
   574  				cfg.Separator = relabel.DefaultRelabelConfig.Separator
   575  			}
   576  			if cfg.Regex.Regexp == nil || cfg.Regex.String() == "" {
   577  				cfg.Regex = relabel.DefaultRelabelConfig.Regex
   578  			}
   579  			if cfg.Replacement == "" {
   580  				cfg.Replacement = relabel.DefaultRelabelConfig.Replacement
   581  			}
   582  			require.NoError(t, cfg.Validate())
   583  		}
   584  
   585  		res, keep := Process(test.input, test.relabel...)
   586  		require.Equal(t, !test.drop, keep)
   587  		if keep {
   588  			testutil.RequireEqualWithOptions(t, test.output, res, []cmp.Option{cmpopts.IgnoreUnexported(typesv1.LabelPair{})})
   589  		}
   590  	}
   591  }