mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-22 09:56:57 +00:00
fix: support canDefaultZero for logs and traces (#8973)
* fix: support canDefaultZero for logs and traces * fix: remove increase * fix: move changes to req.go * fix: add tood * fix: address comments
This commit is contained in:
parent
5d9247f591
commit
052fb8b703
@ -326,9 +326,8 @@ func (q *querier) processTimeSeriesFormula(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canDefaultZero := req.GetQueriesSupportingZeroDefault()
|
||||||
// Create formula evaluator
|
// Create formula evaluator
|
||||||
// TODO(srikanthccv): add conditional default zero
|
|
||||||
canDefaultZero := make(map[string]bool)
|
|
||||||
evaluator, err := qbtypes.NewFormulaEvaluator(formula.Expression, canDefaultZero)
|
evaluator, err := qbtypes.NewFormulaEvaluator(formula.Expression, canDefaultZero)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
q.logger.ErrorContext(ctx, "failed to create formula evaluator", "error", err, "formula", formula.Name)
|
q.logger.ErrorContext(ctx, "failed to create formula evaluator", "error", err, "formula", formula.Name)
|
||||||
@ -478,7 +477,7 @@ func (q *querier) processScalarFormula(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
canDefaultZero := make(map[string]bool)
|
canDefaultZero := req.GetQueriesSupportingZeroDefault()
|
||||||
evaluator, err := qbtypes.NewFormulaEvaluator(formula.Expression, canDefaultZero)
|
evaluator, err := qbtypes.NewFormulaEvaluator(formula.Expression, canDefaultZero)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
q.logger.ErrorContext(ctx, "failed to create formula evaluator", "error", err, "formula", formula.Name)
|
q.logger.ErrorContext(ctx, "failed to create formula evaluator", "error", err, "formula", formula.Name)
|
||||||
|
|||||||
@ -403,3 +403,37 @@ type FormatOptions struct {
|
|||||||
FillGaps bool `json:"fillGaps,omitempty"`
|
FillGaps bool `json:"fillGaps,omitempty"`
|
||||||
FormatTableResultForUI bool `json:"formatTableResultForUI,omitempty"`
|
FormatTableResultForUI bool `json:"formatTableResultForUI,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *QueryRangeRequest) GetQueriesSupportingZeroDefault() map[string]bool {
|
||||||
|
canDefaultZeroAgg := func(expr string) bool {
|
||||||
|
expr = strings.ToLower(expr)
|
||||||
|
// only pure additive/counting operations should default to zero,
|
||||||
|
// while statistical/analytical operations should show gaps when there's no data to analyze.
|
||||||
|
// TODO: use newExprVisitor for getting the function used in the expression
|
||||||
|
if strings.HasPrefix(expr, "count(") ||
|
||||||
|
strings.HasPrefix(expr, "count_distinct(") ||
|
||||||
|
strings.HasPrefix(expr, "sum(") ||
|
||||||
|
strings.HasPrefix(expr, "rate(") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
canDefaultZero := make(map[string]bool)
|
||||||
|
for _, q := range r.CompositeQuery.Queries {
|
||||||
|
if q.Type == QueryTypeBuilder {
|
||||||
|
if query, ok := q.Spec.(QueryBuilderQuery[TraceAggregation]); ok {
|
||||||
|
if len(query.Aggregations) == 1 && canDefaultZeroAgg(query.Aggregations[0].Expression) {
|
||||||
|
canDefaultZero[query.Name] = true
|
||||||
|
}
|
||||||
|
} else if query, ok := q.Spec.(QueryBuilderQuery[LogAggregation]); ok {
|
||||||
|
if len(query.Aggregations) == 1 && canDefaultZeroAgg(query.Aggregations[0].Expression) {
|
||||||
|
canDefaultZero[query.Name] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return canDefaultZero
|
||||||
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package querybuildertypesv5
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -1529,3 +1530,114 @@ func TestValidateUniqueTraceOperator(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestQueryRangeRequest_GetQueriesSupportingZeroDefault(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
CompositeQuery CompositeQuery
|
||||||
|
want map[string]bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "test count on traces - support zeroDefault",
|
||||||
|
CompositeQuery: CompositeQuery{
|
||||||
|
Queries: []QueryEnvelope{
|
||||||
|
{
|
||||||
|
Type: QueryTypeBuilder,
|
||||||
|
Spec: QueryBuilderQuery[TraceAggregation]{
|
||||||
|
Name: "A",
|
||||||
|
Signal: telemetrytypes.SignalTraces,
|
||||||
|
Filter: &Filter{
|
||||||
|
Expression: "service.name = demo",
|
||||||
|
},
|
||||||
|
Aggregations: []TraceAggregation{
|
||||||
|
{
|
||||||
|
Expression: "count()",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: QueryTypeBuilder,
|
||||||
|
Spec: QueryBuilderQuery[TraceAggregation]{
|
||||||
|
Name: "B",
|
||||||
|
Signal: telemetrytypes.SignalTraces,
|
||||||
|
Aggregations: []TraceAggregation{
|
||||||
|
{
|
||||||
|
Expression: "count()",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: QueryTypeFormula,
|
||||||
|
Spec: QueryBuilderFormula{
|
||||||
|
Expression: "A / B * 100",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: map[string]bool{
|
||||||
|
"A": true,
|
||||||
|
"B": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "test rate on logs - support zeroDefault",
|
||||||
|
CompositeQuery: CompositeQuery{
|
||||||
|
Queries: []QueryEnvelope{
|
||||||
|
{
|
||||||
|
Type: QueryTypeBuilder,
|
||||||
|
Spec: QueryBuilderQuery[LogAggregation]{
|
||||||
|
Name: "A",
|
||||||
|
Signal: telemetrytypes.SignalTraces,
|
||||||
|
Filter: &Filter{
|
||||||
|
Expression: "service.name = demo",
|
||||||
|
},
|
||||||
|
Aggregations: []LogAggregation{
|
||||||
|
{
|
||||||
|
Expression: "rate()",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: map[string]bool{
|
||||||
|
"A": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "test min on logs - doesn't support zeroDefault",
|
||||||
|
CompositeQuery: CompositeQuery{
|
||||||
|
Queries: []QueryEnvelope{
|
||||||
|
{
|
||||||
|
Type: QueryTypeBuilder,
|
||||||
|
Spec: QueryBuilderQuery[LogAggregation]{
|
||||||
|
Name: "A",
|
||||||
|
Signal: telemetrytypes.SignalTraces,
|
||||||
|
Filter: &Filter{
|
||||||
|
Expression: "service.name = demo",
|
||||||
|
},
|
||||||
|
Aggregations: []LogAggregation{
|
||||||
|
{
|
||||||
|
Expression: "min(duration)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: map[string]bool{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
r := &QueryRangeRequest{
|
||||||
|
CompositeQuery: tt.CompositeQuery,
|
||||||
|
}
|
||||||
|
if got := r.GetQueriesSupportingZeroDefault(); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("QueryRangeRequest.GetQueriesSupportingZeroDefault() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user