mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-08 13:29:01 +08:00
fix: interpret missing point as zero value in formula evaluation (#4668)
This commit is contained in:
parent
5a2d729ba9
commit
b4d12966f3
@ -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{
|
resultSeries := &v3.Series{
|
||||||
Labels: uniqueLabelSet,
|
Labels: uniqueLabelSet,
|
||||||
}
|
}
|
||||||
|
@ -235,7 +235,39 @@ func TestProcessResults(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: &v3.Result{
|
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{
|
want: &v3.Result{
|
||||||
Series: []*v3.Series{
|
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{
|
Labels: map[string]string{
|
||||||
"service_name": "redis",
|
"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,14 +968,7 @@ func TestFormula(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: &v3.Result{},
|
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{
|
Series: []*v3.Series{
|
||||||
{
|
{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
@ -923,23 +978,23 @@ func TestFormula(t *testing.T) {
|
|||||||
Points: []v3.Point{
|
Points: []v3.Point{
|
||||||
{
|
{
|
||||||
Timestamp: 1,
|
Timestamp: 1,
|
||||||
Value: 10,
|
Value: math.Inf(0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Timestamp: 2,
|
Timestamp: 2,
|
||||||
Value: 20,
|
Value: math.Inf(0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Timestamp: 4,
|
Timestamp: 4,
|
||||||
Value: 40,
|
Value: math.Inf(0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Timestamp: 5,
|
Timestamp: 5,
|
||||||
Value: 50,
|
Value: math.Inf(0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Timestamp: 7,
|
Timestamp: 7,
|
||||||
Value: 70,
|
Value: math.Inf(0),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -951,88 +1006,81 @@ func TestFormula(t *testing.T) {
|
|||||||
Points: []v3.Point{
|
Points: []v3.Point{
|
||||||
{
|
{
|
||||||
Timestamp: 1,
|
Timestamp: 1,
|
||||||
Value: 12,
|
Value: math.Inf(0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Timestamp: 2,
|
Timestamp: 2,
|
||||||
Value: 45,
|
Value: math.Inf(0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Timestamp: 3,
|
Timestamp: 3,
|
||||||
Value: 30,
|
Value: math.Inf(0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Timestamp: 4,
|
Timestamp: 4,
|
||||||
Value: 40,
|
Value: math.Inf(0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Timestamp: 5,
|
Timestamp: 5,
|
||||||
Value: 50,
|
Value: math.Inf(0),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
QueryName: "B",
|
|
||||||
Series: []*v3.Series{
|
|
||||||
{
|
{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"os.type": "linux",
|
"host_name": "ip-10-420-69-1",
|
||||||
"state": "running",
|
"state": "not_running_chalamet",
|
||||||
},
|
},
|
||||||
Points: []v3.Point{
|
Points: []v3.Point{
|
||||||
{
|
{
|
||||||
Timestamp: 1,
|
Timestamp: 1,
|
||||||
Value: 22,
|
Value: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Timestamp: 2,
|
Timestamp: 2,
|
||||||
Value: 65,
|
Value: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Timestamp: 3,
|
Timestamp: 3,
|
||||||
Value: 30,
|
Value: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Timestamp: 4,
|
Timestamp: 4,
|
||||||
Value: 40,
|
Value: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Timestamp: 5,
|
Timestamp: 5,
|
||||||
Value: 50,
|
Value: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"os.type": "windows",
|
"host_name": "ip-10-420-69-2",
|
||||||
"state": "busy",
|
"state": "busy",
|
||||||
},
|
},
|
||||||
Points: []v3.Point{
|
Points: []v3.Point{
|
||||||
{
|
{
|
||||||
Timestamp: 1,
|
Timestamp: 1,
|
||||||
Value: 22,
|
Value: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Timestamp: 2,
|
Timestamp: 2,
|
||||||
Value: 65,
|
Value: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Timestamp: 4,
|
Timestamp: 4,
|
||||||
Value: 40,
|
Value: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Timestamp: 5,
|
Timestamp: 5,
|
||||||
Value: 50,
|
Value: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: &v3.Result{},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "Group keys on the left side are a superset of the right side",
|
name: "Group keys on the left side are a superset of the right side",
|
||||||
expression: "A/B",
|
expression: "A/B",
|
||||||
@ -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)
|
expression, err := govaluate.NewEvaluableExpression(tt.expression)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error parsing expression: %v", err)
|
t.Errorf("Error parsing expression: %v", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
got, err := processResults(tt.results, expression)
|
got, err := processResults(tt.results, expression)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error processing results: %v", err)
|
t.Errorf("Error processing results: %v", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if len(got.Series) != len(tt.want.Series) {
|
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))
|
t.Errorf("processResults(): number of series - got = %v, want %v", len(got.Series), len(tt.want.Series))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range got.Series {
|
for i := range got.Series {
|
||||||
if len(got.Series[i].Points) != len(tt.want.Series[i].Points) {
|
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))
|
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 {
|
for j := range got.Series[i].Points {
|
||||||
if got.Series[i].Points[j].Value != tt.want.Series[i].Points[j].Value {
|
if got.Series[i].Points[j].Value != tt.want.Series[i].Points[j].Value {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user