Skip to content

Commit

Permalink
Don't add replica labels to exemplar labels, only to its series labels (
Browse files Browse the repository at this point in the history
#4223)

* don't add replica labels to exemplar labels, only to its series labels

Signed-off-by: yeya24 <yb532204897@gmail.com>

* update changelog

Signed-off-by: yeya24 <yb532204897@gmail.com>

* add logic to dedup and compare exemplars

Signed-off-by: yeya24 <yb532204897@gmail.com>
  • Loading branch information
yeya24 committed May 26, 2021
1 parent 699e0f1 commit 20e8105
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 187 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ We use _breaking :warning:_ to mark changes that are not backward compatible (re
### Fixed
-
### Changed
-

- [#4223](https://github.com/thanos-io/thanos/pull/4223) Query: federated exemplars API only add replica labels to series labels, not to exemplar labels.

### Removed
-
## [v0.20.2](https://github.com/thanos-io/thanos/releases/tag/v0.20.2) - 2021.05.20
Expand Down
65 changes: 30 additions & 35 deletions pkg/exemplars/exemplars.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,54 +79,48 @@ func (rr *GRPCClient) Exemplars(ctx context.Context, req *exemplarspb.ExemplarsR
return nil, nil, errors.Wrap(err, "proxy Exemplars")
}

resp.data = dedupExemplarsData(resp.data, rr.replicaLabels)
for _, d := range resp.data {
d.Exemplars = dedupExemplars(d.Exemplars, rr.replicaLabels)
}

resp.data = dedupExemplarsResponse(resp.data, rr.replicaLabels)
return resp.data, resp.warnings, nil
}

func dedupExemplarsData(exemplarsData []*exemplarspb.ExemplarData, replicaLabels map[string]struct{}) []*exemplarspb.ExemplarData {
func dedupExemplarsResponse(exemplarsData []*exemplarspb.ExemplarData, replicaLabels map[string]struct{}) []*exemplarspb.ExemplarData {
if len(exemplarsData) == 0 {
return exemplarsData
}

// Sort each exemplar's label names such that they are comparable.
for _, d := range exemplarsData {
sort.Slice(d.SeriesLabels.Labels, func(i, j int) bool {
return d.SeriesLabels.Labels[i].Name < d.SeriesLabels.Labels[j].Name
})
}

// Sort exemplars data such that they appear next to each other.
sort.Slice(exemplarsData, func(i, j int) bool {
return exemplarsData[i].Compare(exemplarsData[j]) < 0
})

i := 0
exemplarsData[i].SeriesLabels.Labels = removeReplicaLabels(exemplarsData[i].SeriesLabels.Labels, replicaLabels)
for j := 1; j < len(exemplarsData); j++ {
exemplarsData[j].SeriesLabels.Labels = removeReplicaLabels(exemplarsData[j].SeriesLabels.Labels, replicaLabels)
if exemplarsData[i].Compare(exemplarsData[j]) != 0 {
// Effectively retain exemplarsData[j] in the resulting slice.
i++
exemplarsData[i] = exemplarsData[j]
// Deduplicate series labels.
hashToExemplar := make(map[uint64]*exemplarspb.ExemplarData)
for _, e := range exemplarsData {
if len(e.Exemplars) == 0 {
continue
}
e.SeriesLabels.Labels = removeReplicaLabels(e.SeriesLabels.Labels, replicaLabels)
h := labelpb.ZLabelsToPromLabels(e.SeriesLabels.Labels).Hash()
if ref, ok := hashToExemplar[h]; ok {
ref.Exemplars = append(ref.Exemplars, e.Exemplars...)
} else {
hashToExemplar[h] = e
}
}

return exemplarsData[:i+1]
}

func dedupExemplars(exemplars []*exemplarspb.Exemplar, replicaLabels map[string]struct{}) []*exemplarspb.Exemplar {
if len(exemplars) == 0 {
return exemplars
res := make([]*exemplarspb.ExemplarData, 0, len(hashToExemplar))
for _, e := range hashToExemplar {
// Dedup exemplars with the same series labels.
e.Exemplars = dedupExemplars(e.Exemplars)
res = append(res, e)
}

// Sort by series labels.
sort.Slice(res, func(i, j int) bool {
return res[i].Compare(res[j]) < 0
})
return res
}

func dedupExemplars(exemplars []*exemplarspb.Exemplar) []*exemplarspb.Exemplar {
for _, e := range exemplars {
sort.Slice(e.Labels.Labels, func(i, j int) bool {
return e.Labels.Labels[i].Name < e.Labels.Labels[j].Name
return e.Labels.Labels[i].Compare(e.Labels.Labels[j]) < 0
})
}

Expand All @@ -135,9 +129,7 @@ func dedupExemplars(exemplars []*exemplarspb.Exemplar, replicaLabels map[string]
})

i := 0
exemplars[i].Labels.Labels = removeReplicaLabels(exemplars[i].Labels.Labels, replicaLabels)
for j := 1; j < len(exemplars); j++ {
exemplars[j].Labels.Labels = removeReplicaLabels(exemplars[j].Labels.Labels, replicaLabels)
if exemplars[i].Compare(exemplars[j]) != 0 {
// Effectively retain exemplars[j] in the resulting slice.
i++
Expand All @@ -149,6 +141,9 @@ func dedupExemplars(exemplars []*exemplarspb.Exemplar, replicaLabels map[string]
}

func removeReplicaLabels(labels []labelpb.ZLabel, replicaLabels map[string]struct{}) []labelpb.ZLabel {
if len(replicaLabels) == 0 {
return labels
}
newLabels := make([]labelpb.ZLabel, 0, len(labels))
for _, l := range labels {
if _, ok := replicaLabels[l.Name]; !ok {
Expand Down
215 changes: 91 additions & 124 deletions pkg/exemplars/exemplars_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func TestMain(m *testing.M) {
testutil.TolerantVerifyLeakMain(m)
}

func TestDedupExemplarsData(t *testing.T) {
func TestDedupExemplarsResponse(t *testing.T) {
for _, tc := range []struct {
name string
exemplars, want []*exemplarspb.ExemplarData
Expand Down Expand Up @@ -43,16 +43,7 @@ func TestDedupExemplarsData(t *testing.T) {
}},
},
},
want: []*exemplarspb.ExemplarData{
{
SeriesLabels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "__name__", Value: "test_exemplar_metric_total"},
{Name: "instance", Value: "localhost:8090"},
{Name: "job", Value: "prometheus"},
{Name: "service", Value: "bar"},
}},
},
},
want: []*exemplarspb.ExemplarData{},
},
{
name: "multiple series",
Expand Down Expand Up @@ -118,135 +109,111 @@ func TestDedupExemplarsData(t *testing.T) {
Value: 19,
Ts: 1600096955479,
},
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "EpTxMJ40fUus7aGY"},
}},
Value: 19,
Ts: 1600096955479,
},
},
},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
replicaLabels := make(map[string]struct{})
for _, lbl := range tc.replicaLabels {
replicaLabels[lbl] = struct{}{}
}
testutil.Equals(t, tc.want, dedupExemplarsData(tc.exemplars, replicaLabels))
})
}
}

func TestDedupExemplars(t *testing.T) {
for _, tc := range []struct {
name string
exemplars, want []*exemplarspb.Exemplar
replicaLabels []string
}{
{
name: "nil slice",
exemplars: nil,
want: nil,
},
{
name: "empty exemplars slice",
exemplars: []*exemplarspb.Exemplar{},
want: []*exemplarspb.Exemplar{},
},
{
name: "duplicate exemplars",
exemplars: []*exemplarspb.Exemplar{
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "EpTxMJ40fUus7aGY"},
}},
Value: 19,
Ts: 1600096955479,
},
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "EpTxMJ40fUus7aGY"},
}},
Value: 19,
Ts: 1600096955479,
},
},
want: []*exemplarspb.Exemplar{
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "EpTxMJ40fUus7aGY"},
}},
Value: 19,
Ts: 1600096955479,
},
},
},
{
name: "distinct exemplars",
exemplars: []*exemplarspb.Exemplar{
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "EpTxMJ40fUus7aGY"},
}},
Value: 19,
Ts: 1600096955479,
},
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "EpTxMJ40fUus7aGY"},
}},
Value: 20,
Ts: 1600096955479,
},
},
want: []*exemplarspb.Exemplar{
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "EpTxMJ40fUus7aGY"},
}},
Value: 19,
Ts: 1600096955479,
},
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "EpTxMJ40fUus7aGY"},
}},
Value: 20,
Ts: 1600096955479,
},
},
},
{
name: "exemplars with replica labels",
name: "multiple series with multiple exemplars data",
replicaLabels: []string{"replica"},
exemplars: []*exemplarspb.Exemplar{
exemplars: []*exemplarspb.ExemplarData{
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "EpTxMJ40fUus7aGY"},
SeriesLabels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "__name__", Value: "test_exemplar_metric_total"},
{Name: "instance", Value: "localhost:8090"},
{Name: "job", Value: "prometheus"},
{Name: "service", Value: "bar"},
{Name: "replica", Value: "0"},
}},
Value: 19,
Ts: 1600096955479,
Exemplars: []*exemplarspb.Exemplar{
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "EpTxMJ40fUus7aGY"},
}},
Value: 19,
Ts: 1600096955479,
},
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "foo"},
}},
Value: 19,
Ts: 1600096955470,
},
},
},
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "EpTxMJ40fUus7aGY"},
SeriesLabels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "__name__", Value: "test_exemplar_metric_total"},
{Name: "instance", Value: "localhost:8090"},
{Name: "job", Value: "prometheus"},
{Name: "service", Value: "bar"},
{Name: "replica", Value: "1"},
}},
Value: 19,
Ts: 1600096955479,
Exemplars: []*exemplarspb.Exemplar{
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "bar"},
}},
Value: 19,
Ts: 1600096955579,
},
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "EpTxMJ40fUus7aGY"},
}},
Value: 19,
Ts: 1600096955479,
},
// Same ts but different labels, cannot dedup.
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "test"},
}},
Value: 19,
Ts: 1600096955479,
},
},
},
},
want: []*exemplarspb.Exemplar{
want: []*exemplarspb.ExemplarData{
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "EpTxMJ40fUus7aGY"},
SeriesLabels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "__name__", Value: "test_exemplar_metric_total"},
{Name: "instance", Value: "localhost:8090"},
{Name: "job", Value: "prometheus"},
{Name: "service", Value: "bar"},
}},
Value: 19,
Ts: 1600096955479,
Exemplars: []*exemplarspb.Exemplar{
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "foo"},
}},
Value: 19,
Ts: 1600096955470,
},
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "EpTxMJ40fUus7aGY"},
}},
Value: 19,
Ts: 1600096955479,
},
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "test"},
}},
Value: 19,
Ts: 1600096955479,
},
{
Labels: labelpb.ZLabelSet{Labels: []labelpb.ZLabel{
{Name: "traceID", Value: "bar"},
}},
Value: 19,
Ts: 1600096955579,
},
},
},
},
},
Expand All @@ -256,7 +223,7 @@ func TestDedupExemplars(t *testing.T) {
for _, lbl := range tc.replicaLabels {
replicaLabels[lbl] = struct{}{}
}
testutil.Equals(t, tc.want, dedupExemplars(tc.exemplars, replicaLabels))
testutil.Equals(t, tc.want, dedupExemplarsResponse(tc.exemplars, replicaLabels))
})
}
}

0 comments on commit 20e8105

Please sign in to comment.