mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-17 23:47:12 +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
|
||||
// TODO(srikanthccv): add conditional default zero
|
||||
canDefaultZero := make(map[string]bool)
|
||||
evaluator, err := qbtypes.NewFormulaEvaluator(formula.Expression, canDefaultZero)
|
||||
if err != nil {
|
||||
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)
|
||||
if err != nil {
|
||||
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"`
|
||||
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 (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
"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