From 3c3c3c49450a0fa40a3e1242ed8d59e419fb7328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Giedrius=20Statkevi=C4=8Dius?= Date: Tue, 1 Apr 2025 12:17:13 +0300 Subject: [PATCH] ruler/decoder: ensure labels order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure that the labels are in order because we are iterating over map[string]string which has a random sorting order. I think the consequence of not sorting this is that when using a frontend directly, the write requests might have unsorted labels in them. Signed-off-by: Giedrius Statkevičius --- pkg/ruler/frontend_decoder.go | 4 ++++ pkg/ruler/frontend_decoder_test.go | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/pkg/ruler/frontend_decoder.go b/pkg/ruler/frontend_decoder.go index 3ea23875b2f..92a6b1a3f6e 100644 --- a/pkg/ruler/frontend_decoder.go +++ b/pkg/ruler/frontend_decoder.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "sort" "github.com/prometheus/common/model" "github.com/prometheus/prometheus/model/labels" @@ -82,6 +83,9 @@ func (j JsonDecoder) vectorToPromQLVector(vector model.Vector) promql.Vector { Value: string(v), }) } + sort.Slice(metric, func(i, j int) bool { + return metric[i].Name < metric[j].Name + }) v = append(v, promql.Sample{ T: int64(sample.Timestamp), F: float64(sample.Value), diff --git a/pkg/ruler/frontend_decoder_test.go b/pkg/ruler/frontend_decoder_test.go index 4cabe478590..116b96ba911 100644 --- a/pkg/ruler/frontend_decoder_test.go +++ b/pkg/ruler/frontend_decoder_test.go @@ -4,6 +4,7 @@ import ( "errors" "testing" + "github.com/prometheus/common/model" "github.com/prometheus/prometheus/model/histogram" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/promql" @@ -13,6 +14,28 @@ import ( "github.com/cortexproject/cortex/pkg/querier/tripperware" ) +func TestDecodeLabelOrder(t *testing.T) { + j := JsonDecoder{} + + decoded := j.vectorToPromQLVector( + model.Vector{ + { + Metric: model.Metric{ + "foo": "bar", + "a": "b", + "b": "b", + }, + Timestamp: 1724146338123, + Value: 1.234, + }, + }, + ) + require.Equal(t, 1, len(decoded)) + require.Equal(t, int64(1724146338123), decoded[0].T) + require.Equal(t, 1.234, decoded[0].F) + require.Equal(t, labels.FromStrings("a", "b", "b", "b", "foo", "bar"), decoded[0].Metric) +} + func TestProtoDecode(t *testing.T) { tests := []struct { description string