Skip to content

Commit c4dc705

Browse files
juliusmhaknuds1
andauthored
Parameterize metric/label name validation scheme (#11848)
#### What this PR does Direct and indirect references to the global name validation scheme were removed in favor of a per-tenant override. - Distributors have a validation middleware that ensures metric and label names are valid. - Rulers validate rule(group)s using this naming scheme. - Queriers use UTF8 validation *everywhere*. TODO: - [x] Reach consensus on whether `streamingpromqlcompat.NameValidatingEngine` is the right approach: Decided to do UTF8 validation in query path. - [x] Get Alertmanager updated with fix, stop using our own fork #### Which issue(s) this PR fixes or relates to Depends on - grafana/mimir-prometheus#946 - grafana/prometheus-alertmanager#116 Fixes: #11503 #### Checklist - [x] Tests updated. - [ ] Documentation added. - [x] `CHANGELOG.md` updated - the order of entries should be `[CHANGE]`, `[FEATURE]`, `[ENHANCEMENT]`, `[BUGFIX]`. If changelog entry is not needed, please add the `changelog-not-needed` label to the PR. - [ ] [`about-versioning.md`](https://github.com/grafana/mimir/blob/main/docs/sources/mimir/configure/about-versioning.md) updated with experimental features. --------- Signed-off-by: Julius Hinze <julius.hinze@grafana.com> Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>
1 parent 362b99c commit c4dc705

File tree

34 files changed

+400
-155
lines changed

34 files changed

+400
-155
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### Grafana Mimir
66

7+
* [CHANGE] Query-frontend: Add support for UTF-8 label and metric names in `/api/v1/cardinality/{label_values|label_values|active_series}` endpoints. #11848.
8+
* [CHANGE] Querier: Add support for UTF-8 label and metric names in `label_join`, `label_replace` and `count_values` PromQL functions. #11848.
79
* [CHANGE] Remove support for Redis as a cache backend. #12163
810
* [CHANGE] Memcached: Remove experimental `-<prefix>.memcached.addresses-provider` flag to use alternate DNS service discovery backends. The more reliable backend introduced in 2.16.0 (#10895) is now the default. As a result of this change, DNS-based cache service discovery no longer supports search domains. #12175
911
* [FEATURE] Distributor: Add experimental `-distributor.otel-native-delta-ingestion` option to allow primitive delta metrics ingestion via the OTLP endpoint. #11631

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ lint: check-makefiles
344344
faillint -paths "github.com/grafana/mimir/pkg/..." ./pkg/querier/api/...
345345
faillint -paths "github.com/grafana/mimir/pkg/..." ./pkg/util/math/...
346346

347-
# Ensure all errors are report as APIError
347+
# Ensure all errors are reported as APIError
348348
faillint -paths "github.com/weaveworks/common/httpgrpc.{Errorf}=github.com/grafana/mimir/pkg/api/error.Newf" ./pkg/frontend/querymiddleware/...
349349

350350
# errors.Cause() only work on errors wrapped by github.com/pkg/errors, while it doesn't work

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ require (
343343
sigs.k8s.io/yaml v1.4.0 // indirect
344344
)
345345

346-
replace github.com/prometheus/prometheus => github.com/grafana/mimir-prometheus v1.8.2-0.20250725113505-6dd7af9abc56
346+
replace github.com/prometheus/prometheus => github.com/grafana/mimir-prometheus v1.8.2-0.20250725123259-c4bd4faba234
347347

348348
// Replace memberlist with our fork which includes some fixes that haven't been
349349
// merged upstream yet:
@@ -370,7 +370,7 @@ replace github.com/opentracing-contrib/go-stdlib => github.com/grafana/opentraci
370370
replace github.com/opentracing-contrib/go-grpc => github.com/charleskorn/go-grpc v0.0.0-20231024023642-e9298576254f
371371

372372
// Replacing prometheus/alertmanager with our fork.
373-
replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6
373+
replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250722103749-329f0c4df1ba
374374

375375
// Use Mimir fork of prometheus/otlptranslator to allow for higher velocity of upstream development,
376376
// while allowing Mimir to move at a more conservative pace.

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -571,14 +571,14 @@ github.com/grafana/memberlist v0.3.1-0.20250428154222-f7d51a6f6700 h1:0t7iOQ5ZkB
571571
github.com/grafana/memberlist v0.3.1-0.20250428154222-f7d51a6f6700/go.mod h1:Ri9p/tRShbjYnpNf4FFPXG7wxEGY4Nrcn6E7jrVa//4=
572572
github.com/grafana/mimir-otlptranslator v0.0.0-20250703083430-c31a9568ad96 h1:kq5zJVW9LyFOB5xCeQPTON2HNjwwEkefhegZXGIhQPk=
573573
github.com/grafana/mimir-otlptranslator v0.0.0-20250703083430-c31a9568ad96/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI=
574-
github.com/grafana/mimir-prometheus v1.8.2-0.20250725113505-6dd7af9abc56 h1:HdQyhMJ+AkDUTlFAU7qIIkC3C2n0R/cV8T2S7JnbK7U=
575-
github.com/grafana/mimir-prometheus v1.8.2-0.20250725113505-6dd7af9abc56/go.mod h1:bi1IiCulyFfPIsfFMaCqlggqiLO4PyqNwK/DiqTaYDI=
574+
github.com/grafana/mimir-prometheus v1.8.2-0.20250725123259-c4bd4faba234 h1:hwME5D5GMogJkN9yobyKTEvOk/SzUFDnYNkUjLsg3ik=
575+
github.com/grafana/mimir-prometheus v1.8.2-0.20250725123259-c4bd4faba234/go.mod h1:Pe/2vVv91zryCeOwLSjIFJFsw4Pvd2VNHbTUGu6kUls=
576576
github.com/grafana/opentracing-contrib-go-stdlib v0.0.0-20230509071955-f410e79da956 h1:em1oddjXL8c1tL0iFdtVtPloq2hRPen2MJQKoAWpxu0=
577577
github.com/grafana/opentracing-contrib-go-stdlib v0.0.0-20230509071955-f410e79da956/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU=
578578
github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8=
579579
github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls=
580-
github.com/grafana/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6 h1:oJnbhG6ZNy10AjsgNeAtAKeGHogIGOMfAsBH6fYYa5M=
581-
github.com/grafana/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6/go.mod h1:O/QP1BCm0HHIzbKvgMzqb5sSyH88rzkFk84F4TfJjBU=
580+
github.com/grafana/prometheus-alertmanager v0.25.1-0.20250722103749-329f0c4df1ba h1:8u5N0btFygn+2S+B6Xs0HFfq4NJ0kJsX9UpIOlidDmQ=
581+
github.com/grafana/prometheus-alertmanager v0.25.1-0.20250722103749-329f0c4df1ba/go.mod h1:O/QP1BCm0HHIzbKvgMzqb5sSyH88rzkFk84F4TfJjBU=
582582
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKtUuKQbJqgAIjlnicKg=
583583
github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU=
584584
github.com/grafana/regexp v0.0.0-20240531075221-3685f1377d7b h1:oMAq12GxTpwo9jxbnG/M4F/HdpwbibTaVoxNA0NZprY=

integration/kv_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ package integration
99
import (
1010
"context"
1111
"errors"
12-
"sort"
12+
"slices"
1313
"sync"
1414
"testing"
1515
"time"
@@ -40,7 +40,7 @@ func TestKVList(t *testing.T) {
4040
// Get list of keys and sort them
4141
keys, err := client.List(context.Background(), "")
4242
require.NoError(t, err, "could not list keys")
43-
sort.Strings(keys)
43+
slices.Sort(keys)
4444
require.Equal(t, keysToCreate, keys, "returned key paths did not match created paths")
4545

4646
verifyClientMetricsHistogram(t, reg, "cortex_kv_request_duration_seconds", map[string]uint64{

pkg/distributor/distributor.go

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,6 @@ import (
6666

6767
var tracer = otel.Tracer("pkg/distributor")
6868

69-
func init() {
70-
// Mimir doesn't support Prometheus' UTF-8 metric/label name scheme yet.
71-
// nolint:staticcheck
72-
model.NameValidationScheme = model.LegacyValidation
73-
}
74-
7569
var (
7670
// Validation errors.
7771
errInvalidTenantShardSize = errors.New("invalid tenant shard size, the value must be greater than or equal to zero")
@@ -1098,15 +1092,18 @@ func (d *Distributor) prePushRelabelMiddleware(next PushFunc) PushFunc {
10981092
return err
10991093
}
11001094

1095+
dropLabels := d.limits.DropLabels(userID)
1096+
relabelConfigs := d.limits.MetricRelabelConfigs(userID)
1097+
11011098
var removeTsIndexes []int
11021099
lb := labels.NewBuilder(labels.EmptyLabels())
11031100
for tsIdx := 0; tsIdx < len(req.Timeseries); tsIdx++ {
11041101
ts := req.Timeseries[tsIdx]
11051102

1106-
if mrc := d.limits.MetricRelabelConfigs(userID); len(mrc) > 0 {
1103+
if len(relabelConfigs) > 0 {
11071104
mimirpb.FromLabelAdaptersToBuilder(ts.Labels, lb)
11081105
lb.Set(metaLabelTenantID, userID)
1109-
keep := relabel.ProcessBuilder(lb, mrc...)
1106+
keep := relabel.ProcessBuilder(lb, relabelConfigs...)
11101107
if !keep {
11111108
removeTsIndexes = append(removeTsIndexes, tsIdx)
11121109
continue
@@ -1115,7 +1112,7 @@ func (d *Distributor) prePushRelabelMiddleware(next PushFunc) PushFunc {
11151112
req.Timeseries[tsIdx].SetLabels(mimirpb.FromBuilderToLabelAdapters(lb, ts.Labels))
11161113
}
11171114

1118-
for _, labelName := range d.limits.DropLabels(userID) {
1115+
for _, labelName := range dropLabels {
11191116
req.Timeseries[tsIdx].RemoveLabel(labelName)
11201117
}
11211118

pkg/distributor/validate.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616

1717
"github.com/prometheus/client_golang/prometheus"
1818
"github.com/prometheus/common/model"
19+
"github.com/prometheus/prometheus/model/labels"
1920

2021
"github.com/grafana/mimir/pkg/costattribution"
2122
"github.com/grafana/mimir/pkg/mimirpb"
@@ -390,6 +391,7 @@ type labelValidationConfig interface {
390391
MaxLabelNamesPerInfoSeries(userID string) int
391392
MaxLabelNameLength(userID string) int
392393
MaxLabelValueLength(userID string) int
394+
ValidationScheme(userID string) model.ValidationScheme
393395
}
394396

395397
func removeNonASCIIChars(in string) (out string) {
@@ -421,7 +423,9 @@ func validateLabels(m *sampleValidationMetrics, cfg labelValidationConfig, userI
421423
return errors.New(noMetricNameMsgFormat)
422424
}
423425

424-
if !model.IsValidMetricName(model.LabelValue(unsafeMetricName)) {
426+
validationScheme := cfg.ValidationScheme(userID)
427+
428+
if !labels.IsValidMetricName(unsafeMetricName, validationScheme) {
425429
cat.IncrementDiscardedSamples(ls, 1, reasonInvalidMetricName, ts)
426430
m.invalidMetricName.WithLabelValues(userID, group).Inc()
427431
return fmt.Errorf(invalidMetricNameMsgFormat, removeNonASCIIChars(unsafeMetricName))
@@ -447,7 +451,7 @@ func validateLabels(m *sampleValidationMetrics, cfg labelValidationConfig, userI
447451
maxLabelValueLength := cfg.MaxLabelValueLength(userID)
448452
lastLabelName := ""
449453
for _, l := range ls {
450-
if !skipLabelValidation && !model.LabelName(l.Name).IsValid() {
454+
if !skipLabelValidation && !labels.IsValidLabelName(l.Name, validationScheme) {
451455
m.invalidLabel.WithLabelValues(userID, group).Inc()
452456
cat.IncrementDiscardedSamples(ls, 1, reasonInvalidLabel, ts)
453457
return fmt.Errorf(invalidLabelMsgFormat, l.Name, mimirpb.FromLabelAdaptersToString(ls))

0 commit comments

Comments
 (0)