|
|
@ -406,17 +406,22 @@ func funcSortDesc(vals []parser.Value, args parser.Expressions, enh *EvalNodeHel |
|
|
|
|
|
|
|
|
|
|
|
// === sort_by_label(vector parser.ValueTypeVector, label parser.ValueTypeString...) (Vector, Annotations) ===
|
|
|
|
// === sort_by_label(vector parser.ValueTypeVector, label parser.ValueTypeString...) (Vector, Annotations) ===
|
|
|
|
func funcSortByLabel(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) { |
|
|
|
func funcSortByLabel(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) { |
|
|
|
|
|
|
|
// First, sort by the full label set. This ensures a consistent ordering in case sorting by the
|
|
|
|
|
|
|
|
// labels provided as arguments is not conclusive.
|
|
|
|
slices.SortFunc(vals[0].(Vector), func(a, b Sample) int { |
|
|
|
slices.SortFunc(vals[0].(Vector), func(a, b Sample) int { |
|
|
|
return labels.Compare(a.Metric, b.Metric) |
|
|
|
return labels.Compare(a.Metric, b.Metric) |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
labels := stringSliceFromArgs(args[1:]) |
|
|
|
labels := stringSliceFromArgs(args[1:]) |
|
|
|
|
|
|
|
// Next, sort by the labels provided as arguments.
|
|
|
|
slices.SortFunc(vals[0].(Vector), func(a, b Sample) int { |
|
|
|
slices.SortFunc(vals[0].(Vector), func(a, b Sample) int { |
|
|
|
// Iterate over each given label
|
|
|
|
// Iterate over each given label.
|
|
|
|
for _, label := range labels { |
|
|
|
for _, label := range labels { |
|
|
|
lv1 := a.Metric.Get(label) |
|
|
|
lv1 := a.Metric.Get(label) |
|
|
|
lv2 := b.Metric.Get(label) |
|
|
|
lv2 := b.Metric.Get(label) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If we encounter multiple samples with the same label values, the sorting which was
|
|
|
|
|
|
|
|
// performed in the first step will act as a "tie breaker".
|
|
|
|
if lv1 == lv2 { |
|
|
|
if lv1 == lv2 { |
|
|
|
continue |
|
|
|
continue |
|
|
|
} |
|
|
|
} |
|
|
@ -436,17 +441,22 @@ func funcSortByLabel(vals []parser.Value, args parser.Expressions, enh *EvalNode |
|
|
|
|
|
|
|
|
|
|
|
// === sort_by_label_desc(vector parser.ValueTypeVector, label parser.ValueTypeString...) (Vector, Annotations) ===
|
|
|
|
// === sort_by_label_desc(vector parser.ValueTypeVector, label parser.ValueTypeString...) (Vector, Annotations) ===
|
|
|
|
func funcSortByLabelDesc(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) { |
|
|
|
func funcSortByLabelDesc(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) { |
|
|
|
|
|
|
|
// First, sort by the full label set. This ensures a consistent ordering in case sorting by the
|
|
|
|
|
|
|
|
// labels provided as arguments is not conclusive.
|
|
|
|
slices.SortFunc(vals[0].(Vector), func(a, b Sample) int { |
|
|
|
slices.SortFunc(vals[0].(Vector), func(a, b Sample) int { |
|
|
|
return labels.Compare(b.Metric, a.Metric) |
|
|
|
return labels.Compare(b.Metric, a.Metric) |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
labels := stringSliceFromArgs(args[1:]) |
|
|
|
labels := stringSliceFromArgs(args[1:]) |
|
|
|
|
|
|
|
// Next, sort by the labels provided as arguments.
|
|
|
|
slices.SortFunc(vals[0].(Vector), func(a, b Sample) int { |
|
|
|
slices.SortFunc(vals[0].(Vector), func(a, b Sample) int { |
|
|
|
// Iterate over each given label
|
|
|
|
// Iterate over each given label.
|
|
|
|
for _, label := range labels { |
|
|
|
for _, label := range labels { |
|
|
|
lv1 := a.Metric.Get(label) |
|
|
|
lv1 := a.Metric.Get(label) |
|
|
|
lv2 := b.Metric.Get(label) |
|
|
|
lv2 := b.Metric.Get(label) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If we encounter multiple samples with the same label values, the sorting which was
|
|
|
|
|
|
|
|
// performed in the first step will act as a "tie breaker".
|
|
|
|
if lv1 == lv2 { |
|
|
|
if lv1 == lv2 { |
|
|
|
continue |
|
|
|
continue |
|
|
|
} |
|
|
|
} |
|
|
|