fix: interpret missing point as zero value in formula evaluation (#4668)

This commit is contained in:
Srikanth Chekuri 2024-03-11 23:47:19 +05:30 committed by GitHub
parent 5a2d729ba9
commit b4d12966f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 218 additions and 130 deletions

View File

@ -87,23 +87,6 @@ func joinAndCalculate(results []*v3.Result, uniqueLabelSet map[string]string, ex
}
}
vars := expression.Vars()
var doesNotHaveAllVars bool
for _, v := range vars {
if _, ok := seriesMap[v]; !ok {
doesNotHaveAllVars = true
break
}
}
// There is no series that matches the label set from all queries
// TODO: Does the lack of a series from one query mean that the result should be nil?
// Or should we interpret the series as having a value of 0 at all timestamps?
// The current behaviour with ClickHouse is to show no data
if doesNotHaveAllVars {
return nil, nil
}
resultSeries := &v3.Series{
Labels: uniqueLabelSet,
}

View File

@ -235,7 +235,39 @@ func TestProcessResults(t *testing.T) {
},
},
want: &v3.Result{
Series: []*v3.Series{},
Series: []*v3.Series{
{
Labels: map[string]string{
"service_name": "frontend",
"operation": "GET /api",
},
Points: []v3.Point{
{
Timestamp: 1,
Value: 10,
},
{
Timestamp: 2,
Value: 20,
},
},
},
{
Labels: map[string]string{
"service_name": "redis",
},
Points: []v3.Point{
{
Timestamp: 1,
Value: 30,
},
{
Timestamp: 3,
Value: 40,
},
},
},
},
},
},
}
@ -350,6 +382,21 @@ func TestProcessResultsErrorRate(t *testing.T) {
},
want: &v3.Result{
Series: []*v3.Series{
{
Labels: map[string]string{
"service_name": "frontend",
},
Points: []v3.Point{
{
Timestamp: 1,
Value: 0,
},
{
Timestamp: 2,
Value: 0,
},
},
},
{
Labels: map[string]string{
"service_name": "redis",
@ -365,6 +412,21 @@ func TestProcessResultsErrorRate(t *testing.T) {
},
},
},
{
Labels: map[string]string{
"service_name": "route",
},
Points: []v3.Point{
{
Timestamp: 1,
Value: 0,
},
{
Timestamp: 2,
Value: 0,
},
},
},
},
},
},
@ -906,132 +968,118 @@ func TestFormula(t *testing.T) {
},
},
},
want: &v3.Result{},
},
{
name: "Group keys on both sides are overlapping but do not match exactly",
expression: "A/B",
results: []*v3.Result{
{
QueryName: "A",
Series: []*v3.Series{
{
Labels: map[string]string{
"host_name": "ip-10-420-69-1",
"state": "running",
},
Points: []v3.Point{
{
Timestamp: 1,
Value: 10,
},
{
Timestamp: 2,
Value: 20,
},
{
Timestamp: 4,
Value: 40,
},
{
Timestamp: 5,
Value: 50,
},
{
Timestamp: 7,
Value: 70,
},
},
want: &v3.Result{
Series: []*v3.Series{
{
Labels: map[string]string{
"host_name": "ip-10-420-69-1",
"state": "running",
},
{
Labels: map[string]string{
"host_name": "ip-10-420-69-2",
"state": "idle",
Points: []v3.Point{
{
Timestamp: 1,
Value: math.Inf(0),
},
Points: []v3.Point{
{
Timestamp: 1,
Value: 12,
},
{
Timestamp: 2,
Value: 45,
},
{
Timestamp: 3,
Value: 30,
},
{
Timestamp: 4,
Value: 40,
},
{
Timestamp: 5,
Value: 50,
},
{
Timestamp: 2,
Value: math.Inf(0),
},
{
Timestamp: 4,
Value: math.Inf(0),
},
{
Timestamp: 5,
Value: math.Inf(0),
},
{
Timestamp: 7,
Value: math.Inf(0),
},
},
},
},
{
QueryName: "B",
Series: []*v3.Series{
{
Labels: map[string]string{
"os.type": "linux",
"state": "running",
{
Labels: map[string]string{
"host_name": "ip-10-420-69-2",
"state": "idle",
},
Points: []v3.Point{
{
Timestamp: 1,
Value: math.Inf(0),
},
Points: []v3.Point{
{
Timestamp: 1,
Value: 22,
},
{
Timestamp: 2,
Value: 65,
},
{
Timestamp: 3,
Value: 30,
},
{
Timestamp: 4,
Value: 40,
},
{
Timestamp: 5,
Value: 50,
},
{
Timestamp: 2,
Value: math.Inf(0),
},
{
Timestamp: 3,
Value: math.Inf(0),
},
{
Timestamp: 4,
Value: math.Inf(0),
},
{
Timestamp: 5,
Value: math.Inf(0),
},
},
{
Labels: map[string]string{
"os.type": "windows",
"state": "busy",
},
{
Labels: map[string]string{
"host_name": "ip-10-420-69-1",
"state": "not_running_chalamet",
},
Points: []v3.Point{
{
Timestamp: 1,
Value: 0,
},
Points: []v3.Point{
{
Timestamp: 1,
Value: 22,
},
{
Timestamp: 2,
Value: 65,
},
{
Timestamp: 4,
Value: 40,
},
{
Timestamp: 5,
Value: 50,
},
{
Timestamp: 2,
Value: 0,
},
{
Timestamp: 3,
Value: 0,
},
{
Timestamp: 4,
Value: 0,
},
{
Timestamp: 5,
Value: 0,
},
},
},
{
Labels: map[string]string{
"host_name": "ip-10-420-69-2",
"state": "busy",
},
Points: []v3.Point{
{
Timestamp: 1,
Value: 0,
},
{
Timestamp: 2,
Value: 0,
},
{
Timestamp: 4,
Value: 0,
},
{
Timestamp: 5,
Value: 0,
},
},
},
},
},
want: &v3.Result{},
},
{
name: "Group keys on the left side are a superset of the right side",
@ -1193,6 +1241,59 @@ func TestFormula(t *testing.T) {
},
},
},
{
Labels: map[string]string{
"host_name": "ip-10-420-69-2",
"state": "idle",
"os.type": "linux",
},
Points: []v3.Point{
{
Timestamp: 1,
Value: math.Inf(0),
},
{
Timestamp: 2,
Value: math.Inf(0),
},
{
Timestamp: 3,
Value: math.Inf(0),
},
{
Timestamp: 4,
Value: math.Inf(0),
},
{
Timestamp: 5,
Value: math.Inf(0),
},
},
},
{
Labels: map[string]string{
"state": "busy",
"os.type": "linux",
},
Points: []v3.Point{
{
Timestamp: 1,
Value: 0,
},
{
Timestamp: 2,
Value: 0,
},
{
Timestamp: 4,
Value: 0,
},
{
Timestamp: 5,
Value: 0,
},
},
},
},
},
},
@ -1454,18 +1555,22 @@ func TestFormula(t *testing.T) {
expression, err := govaluate.NewEvaluableExpression(tt.expression)
if err != nil {
t.Errorf("Error parsing expression: %v", err)
return
}
got, err := processResults(tt.results, expression)
if err != nil {
t.Errorf("Error processing results: %v", err)
return
}
if len(got.Series) != len(tt.want.Series) {
t.Errorf("processResults(): number of series - got = %v, want %v", len(got.Series), len(tt.want.Series))
return
}
for i := range got.Series {
if len(got.Series[i].Points) != len(tt.want.Series[i].Points) {
t.Errorf("processResults(): number of points - got = %v, want %v", len(got.Series[i].Points), len(tt.want.Series[i].Points))
return
}
for j := range got.Series[i].Points {
if got.Series[i].Points[j].Value != tt.want.Series[i].Points[j].Value {