Skip to content

Commit db252aa

Browse files
authored
filter out label with empty value in distributor (#7069)
* filter out label with empty value in distributor Signed-off-by: yeya24 <benye@amazon.com> * update changelog Signed-off-by: yeya24 <benye@amazon.com> --------- Signed-off-by: yeya24 <benye@amazon.com>
1 parent f5a27ec commit db252aa

File tree

3 files changed

+67
-0
lines changed

3 files changed

+67
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
* [ENHANCEMENT] Add new metric `cortex_discarded_series` and `cortex_discarded_series_per_labelset` to track number of series that have a discarded sample. #6995
8585
* [ENHANCEMENT] Ingester: Add `cortex_ingester_tsdb_head_stale_series` metric to keep track of number of stale series on head. #7071
8686
* [ENHANCEMENT] Expose more Go runtime metrics. #7070
87+
* [ENHANCEMENT] Distributor: Filter out label with empty value. #7069
8788
* [BUGFIX] Ingester: Avoid error or early throttling when READONLY ingesters are present in the ring #6517
8889
* [BUGFIX] Ingester: Fix labelset data race condition. #6573
8990
* [BUGFIX] Compactor: Cleaner should not put deletion marker for blocks with no-compact marker. #6576

pkg/distributor/distributor.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,18 @@ func removeLabel(labelName string, labels *[]cortexpb.LabelAdapter) {
600600
}
601601
}
602602

603+
// Remove all labels with empty values from a slice of LabelPairs.
604+
func removeEmptyLabels(labels *[]cortexpb.LabelAdapter) {
605+
i := 0
606+
for j := 0; j < len(*labels); j++ {
607+
if (*labels)[j].Value != "" {
608+
(*labels)[i] = (*labels)[j]
609+
i++
610+
}
611+
}
612+
*labels = (*labels)[:i]
613+
}
614+
603615
// Returns a boolean that indicates whether or not we want to remove the replica label going forward,
604616
// and an error that indicates whether we want to accept samples based on the cluster/replica found in ts.
605617
// nil for the error means accept the sample.
@@ -1080,6 +1092,9 @@ func (d *Distributor) prepareSeriesKeys(ctx context.Context, req *cortexpb.Write
10801092
removeLabel(labelName, &ts.Labels)
10811093
}
10821094

1095+
// Make sure no label with empty value is sent to the Ingester.
1096+
removeEmptyLabels(&ts.Labels)
1097+
10831098
if len(ts.Labels) == 0 {
10841099
d.validateMetrics.DiscardedSamples.WithLabelValues(
10851100
validation.DroppedByUserConfigurationOverride,

pkg/distributor/distributor_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4192,6 +4192,53 @@ func TestDistributor_Push_Relabel(t *testing.T) {
41924192
}
41934193
}
41944194

4195+
func TestRemoveEmptyLabels(t *testing.T) {
4196+
t.Parallel()
4197+
4198+
tests := []struct {
4199+
name string
4200+
input []cortexpb.LabelAdapter
4201+
expected []cortexpb.LabelAdapter
4202+
}{
4203+
{
4204+
name: "no empty labels",
4205+
input: []cortexpb.LabelAdapter{{Name: "job", Value: "test"}, {Name: "instance", Value: "localhost"}},
4206+
expected: []cortexpb.LabelAdapter{{Name: "job", Value: "test"}, {Name: "instance", Value: "localhost"}},
4207+
},
4208+
{
4209+
name: "empty label at beginning",
4210+
input: []cortexpb.LabelAdapter{{Name: "empty", Value: ""}, {Name: "job", Value: "test"}},
4211+
expected: []cortexpb.LabelAdapter{{Name: "job", Value: "test"}},
4212+
},
4213+
{
4214+
name: "empty label in middle",
4215+
input: []cortexpb.LabelAdapter{{Name: "job", Value: "test"}, {Name: "empty", Value: ""}, {Name: "instance", Value: "localhost"}},
4216+
expected: []cortexpb.LabelAdapter{{Name: "job", Value: "test"}, {Name: "instance", Value: "localhost"}},
4217+
},
4218+
{
4219+
name: "empty label at end",
4220+
input: []cortexpb.LabelAdapter{{Name: "job", Value: "test"}, {Name: "empty", Value: ""}},
4221+
expected: []cortexpb.LabelAdapter{{Name: "job", Value: "test"}},
4222+
},
4223+
{
4224+
name: "multiple empty labels - removes all empty ones",
4225+
input: []cortexpb.LabelAdapter{{Name: "empty1", Value: ""}, {Name: "job", Value: "test"}, {Name: "empty2", Value: ""}},
4226+
expected: []cortexpb.LabelAdapter{{Name: "job", Value: "test"}},
4227+
},
4228+
}
4229+
4230+
for _, tt := range tests {
4231+
t.Run(tt.name, func(t *testing.T) {
4232+
// Make a copy of the input to avoid modifying the original
4233+
input := make([]cortexpb.LabelAdapter, len(tt.input))
4234+
copy(input, tt.input)
4235+
4236+
removeEmptyLabels(&input)
4237+
assert.Equal(t, tt.expected, input)
4238+
})
4239+
}
4240+
}
4241+
41954242
func TestDistributor_Push_EmptyLabel(t *testing.T) {
41964243
t.Parallel()
41974244
ctx := user.InjectOrgID(context.Background(), "pushEmptyLabel")
@@ -4255,6 +4302,10 @@ func TestDistributor_Push_EmptyLabel(t *testing.T) {
42554302
timeseries := ingesters[i].series()
42564303
if len(timeseries) > 0 {
42574304
ingesterWithSeries++
4305+
// Assert on the expected series
4306+
for _, v := range timeseries {
4307+
assert.Equal(t, tc.expectedSeries, cortexpb.FromLabelAdaptersToLabels(v.Labels))
4308+
}
42584309
}
42594310
}
42604311
assert.Equal(t, 1, ingesterWithSeries)

0 commit comments

Comments
 (0)