fix: update clickhouse quries

Signed-off-by: Shivanshu Raj Shrivastava <shivanshu1333@gmail.com>
This commit is contained in:
Shivanshu Raj Shrivastava 2025-06-02 12:11:53 +05:30
parent 31cd192f24
commit 7ddf002d46
No known key found for this signature in database
GPG Key ID: D34D26C62AC3E9AE
2 changed files with 110 additions and 17 deletions

View File

@ -2,12 +2,21 @@ package tracefunnel
import ( import (
"fmt" "fmt"
"strings"
tracev4 "github.com/SigNoz/signoz/pkg/query-service/app/traces/v4" tracev4 "github.com/SigNoz/signoz/pkg/query-service/app/traces/v4"
v3 "github.com/SigNoz/signoz/pkg/query-service/model/v3" v3 "github.com/SigNoz/signoz/pkg/query-service/model/v3"
"github.com/SigNoz/signoz/pkg/types/tracefunneltypes" "github.com/SigNoz/signoz/pkg/types/tracefunneltypes"
"strings"
) )
// sanitizeClause adds AND prefix to non-empty clauses
func sanitizeClause(clause string) string {
if clause == "" {
return ""
}
return "AND " + clause
}
func ValidateTraces(funnel *tracefunneltypes.StorableFunnel, timeRange tracefunneltypes.TimeRange) (*v3.ClickHouseQuery, error) { func ValidateTraces(funnel *tracefunneltypes.StorableFunnel, timeRange tracefunneltypes.TimeRange) (*v3.ClickHouseQuery, error) {
var query string var query string
var err error var err error
@ -28,22 +37,27 @@ func ValidateTraces(funnel *tracefunneltypes.StorableFunnel, timeRange tracefunn
} }
// Build filter clauses for each step // Build filter clauses for each step
clauseStep1, err := tracev4.BuildTracesFilterQuery(funnelSteps[0].Filters) clauseStep1, err := tracev4.BuildTracesFilter(funnelSteps[0].Filters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
clauseStep2, err := tracev4.BuildTracesFilterQuery(funnelSteps[1].Filters) clauseStep2, err := tracev4.BuildTracesFilter(funnelSteps[1].Filters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
clauseStep3 := "" clauseStep3 := ""
if len(funnel.Steps) > 2 { if len(funnel.Steps) > 2 {
clauseStep3, err = tracev4.BuildTracesFilterQuery(funnelSteps[2].Filters) clauseStep3, err = tracev4.BuildTracesFilter(funnelSteps[2].Filters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
// Sanitize clauses
clauseStep1 = sanitizeClause(clauseStep1)
clauseStep2 = sanitizeClause(clauseStep2)
clauseStep3 = sanitizeClause(clauseStep3)
if len(funnel.Steps) > 2 { if len(funnel.Steps) > 2 {
query = BuildThreeStepFunnelValidationQuery( query = BuildThreeStepFunnelValidationQuery(
containsErrorT1, containsErrorT1,
@ -107,22 +121,27 @@ func GetFunnelAnalytics(funnel *tracefunneltypes.StorableFunnel, timeRange trace
} }
// Build filter clauses for each step // Build filter clauses for each step
clauseStep1, err := tracev4.BuildTracesFilterQuery(funnelSteps[0].Filters) clauseStep1, err := tracev4.BuildTracesFilter(funnelSteps[0].Filters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
clauseStep2, err := tracev4.BuildTracesFilterQuery(funnelSteps[1].Filters) clauseStep2, err := tracev4.BuildTracesFilter(funnelSteps[1].Filters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
clauseStep3 := "" clauseStep3 := ""
if len(funnel.Steps) > 2 { if len(funnel.Steps) > 2 {
clauseStep3, err = tracev4.BuildTracesFilterQuery(funnelSteps[2].Filters) clauseStep3, err = tracev4.BuildTracesFilter(funnelSteps[2].Filters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
// Sanitize clauses
clauseStep1 = sanitizeClause(clauseStep1)
clauseStep2 = sanitizeClause(clauseStep2)
clauseStep3 = sanitizeClause(clauseStep3)
if len(funnel.Steps) > 2 { if len(funnel.Steps) > 2 {
query = BuildThreeStepFunnelOverviewQuery( query = BuildThreeStepFunnelOverviewQuery(
containsErrorT1, containsErrorT1,
@ -215,22 +234,27 @@ func GetFunnelStepAnalytics(funnel *tracefunneltypes.StorableFunnel, timeRange t
} }
// Build filter clauses for each step // Build filter clauses for each step
clauseStep1, err := tracev4.BuildTracesFilterQuery(funnelSteps[0].Filters) clauseStep1, err := tracev4.BuildTracesFilter(funnelSteps[0].Filters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
clauseStep2, err := tracev4.BuildTracesFilterQuery(funnelSteps[1].Filters) clauseStep2, err := tracev4.BuildTracesFilter(funnelSteps[1].Filters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
clauseStep3 := "" clauseStep3 := ""
if len(funnel.Steps) > 2 { if len(funnel.Steps) > 2 {
clauseStep3, err = tracev4.BuildTracesFilterQuery(funnelSteps[2].Filters) clauseStep3, err = tracev4.BuildTracesFilter(funnelSteps[2].Filters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
// Sanitize clauses
clauseStep1 = sanitizeClause(clauseStep1)
clauseStep2 = sanitizeClause(clauseStep2)
clauseStep3 = sanitizeClause(clauseStep3)
if len(funnel.Steps) > 2 { if len(funnel.Steps) > 2 {
query = BuildThreeStepFunnelStepOverviewQuery( query = BuildThreeStepFunnelStepOverviewQuery(
containsErrorT1, containsErrorT1,
@ -294,22 +318,27 @@ func GetStepAnalytics(funnel *tracefunneltypes.StorableFunnel, timeRange tracefu
} }
// Build filter clauses for each step // Build filter clauses for each step
clauseStep1, err := tracev4.BuildTracesFilterQuery(funnelSteps[0].Filters) clauseStep1, err := tracev4.BuildTracesFilter(funnelSteps[0].Filters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
clauseStep2, err := tracev4.BuildTracesFilterQuery(funnelSteps[1].Filters) clauseStep2, err := tracev4.BuildTracesFilter(funnelSteps[1].Filters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
clauseStep3 := "" clauseStep3 := ""
if len(funnel.Steps) > 2 { if len(funnel.Steps) > 2 {
clauseStep3, err = tracev4.BuildTracesFilterQuery(funnelSteps[2].Filters) clauseStep3, err = tracev4.BuildTracesFilter(funnelSteps[2].Filters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
// Sanitize clauses
clauseStep1 = sanitizeClause(clauseStep1)
clauseStep2 = sanitizeClause(clauseStep2)
clauseStep3 = sanitizeClause(clauseStep3)
if len(funnel.Steps) > 2 { if len(funnel.Steps) > 2 {
query = BuildThreeStepFunnelCountQuery( query = BuildThreeStepFunnelCountQuery(
containsErrorT1, containsErrorT1,
@ -366,15 +395,19 @@ func GetSlowestTraces(funnel *tracefunneltypes.StorableFunnel, timeRange tracefu
} }
// Build filter clauses for the steps // Build filter clauses for the steps
clauseStep1, err := tracev4.BuildTracesFilterQuery(funnelSteps[stepStartOrder].Filters) clauseStep1, err := tracev4.BuildTracesFilter(funnelSteps[stepStartOrder].Filters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
clauseStep2, err := tracev4.BuildTracesFilterQuery(funnelSteps[stepEndOrder].Filters) clauseStep2, err := tracev4.BuildTracesFilter(funnelSteps[stepEndOrder].Filters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Sanitize clauses
clauseStep1 = sanitizeClause(clauseStep1)
clauseStep2 = sanitizeClause(clauseStep2)
query := BuildTwoStepFunnelTopSlowTracesQuery( query := BuildTwoStepFunnelTopSlowTracesQuery(
containsErrorT1, containsErrorT1,
containsErrorT2, containsErrorT2,
@ -409,15 +442,19 @@ func GetErroredTraces(funnel *tracefunneltypes.StorableFunnel, timeRange tracefu
} }
// Build filter clauses for the steps // Build filter clauses for the steps
clauseStep1, err := tracev4.BuildTracesFilterQuery(funnelSteps[stepStartOrder].Filters) clauseStep1, err := tracev4.BuildTracesFilter(funnelSteps[stepStartOrder].Filters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
clauseStep2, err := tracev4.BuildTracesFilterQuery(funnelSteps[stepEndOrder].Filters) clauseStep2, err := tracev4.BuildTracesFilter(funnelSteps[stepEndOrder].Filters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Sanitize clauses
clauseStep1 = sanitizeClause(clauseStep1)
clauseStep2 = sanitizeClause(clauseStep2)
query := BuildTwoStepFunnelTopSlowErrorTracesQuery( query := BuildTwoStepFunnelTopSlowErrorTracesQuery(
containsErrorT1, containsErrorT1,
containsErrorT2, containsErrorT2,

View File

@ -87,6 +87,62 @@ func existsSubQueryForFixedColumn(key v3.AttributeKey, op v3.FilterOperator) (st
} }
} }
func BuildTracesFilter(fs *v3.FilterSet) (string, error) {
var conditions []string
if fs != nil && len(fs.Items) != 0 {
for _, item := range fs.Items {
val := item.Value
// generate the key
columnName := getColumnName(item.Key)
var fmtVal string
item.Operator = v3.FilterOperator(strings.ToLower(strings.TrimSpace(string(item.Operator))))
if item.Operator != v3.FilterOperatorExists && item.Operator != v3.FilterOperatorNotExists {
var err error
val, err = utils.ValidateAndCastValue(val, item.Key.DataType)
if err != nil {
return "", fmt.Errorf("invalid value for key %s: %v", item.Key.Key, err)
}
}
if val != nil {
fmtVal = utils.ClickHouseFormattedValue(val)
}
if operator, ok := tracesOperatorMappingV3[item.Operator]; ok {
switch item.Operator {
case v3.FilterOperatorContains, v3.FilterOperatorNotContains:
// we also want to treat %, _ as literals for contains
val := utils.QuoteEscapedStringForContains(fmt.Sprintf("%s", item.Value), false)
conditions = append(conditions, fmt.Sprintf("%s %s '%%%s%%'", columnName, operator, val))
case v3.FilterOperatorRegex, v3.FilterOperatorNotRegex:
conditions = append(conditions, fmt.Sprintf(operator, columnName, fmtVal))
case v3.FilterOperatorExists, v3.FilterOperatorNotExists:
if item.Key.IsColumn {
subQuery, err := existsSubQueryForFixedColumn(item.Key, item.Operator)
if err != nil {
return "", err
}
conditions = append(conditions, subQuery)
} else {
cType := getClickHouseTracesColumnType(item.Key.Type)
cDataType := getClickHouseTracesColumnDataType(item.Key.DataType)
col := fmt.Sprintf("%s_%s", cType, cDataType)
conditions = append(conditions, fmt.Sprintf(operator, col, item.Key.Key))
}
default:
conditions = append(conditions, fmt.Sprintf("%s %s %s", columnName, operator, fmtVal))
}
} else {
return "", fmt.Errorf("unsupported operator %s", item.Operator)
}
}
}
queryString := strings.Join(conditions, " AND ")
return queryString, nil
}
func BuildTracesFilterQuery(fs *v3.FilterSet) (string, error) { func BuildTracesFilterQuery(fs *v3.FilterSet) (string, error) {
var conditions []string var conditions []string