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 }