Files
signoz/pkg/modules/spanpercentile/implspanpercentile/statement_builder.go
Ekansh Gupta e90bb016f7 feat: add span percentile for traces (#8955)
* feat: add span percentile for traces

* feat: fixed merge conflicts

* feat: fixed merge conflicts

* feat: fixed merge conflicts

* feat: added span percentile

* feat: added span percentile

* feat: added test for span percentiles

* feat: added test for span percentiles

* feat: added test for span percentiles

* feat: added test for span percentiles

* feat: removed comments

* feat: moved everything to module

* feat: refactored span percentile

* feat: refactored span percentile

* feat: refactored module package

* feat: fixed tests for span percentile

* feat: refactored span percentile and changed query

* feat: refactored span percentile and changed query

* feat: refactored span percentile and changed query

* feat: refactored span percentile and changed query

* feat: added better error handling

* feat: added better error handling

* feat: addressed pr comments

* feat: addressed pr comments

* feat: renamed translator.go

* feat: added query settings

* feat: added full query test

* feat: added fingerprinting

* feat: refactored tests

* feat: refactored to use fingerprinting and changed tests

* feat: refactored to use fingerprinting and changed tests

* feat: refactored to use fingerprinting and changed tests

* feat: changed errors

* feat: removed redundant tests

* feat: removed redundant tests

* feat: moved everything to trace aggregation and updated tests

* feat: addressed comments regarding metadatastore

* feat: addressed comments regarding metadatastore

* feat: addressed comments regarding metadatastore

* feat: addressed comments for float64

* feat: cleaned up code

* feat: cleaned up code
2025-10-29 21:35:59 +05:30

119 lines
3.0 KiB
Go

package implspanpercentile
import (
"context"
"fmt"
"sort"
"strings"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/SigNoz/signoz/pkg/types/spanpercentiletypes"
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
)
func buildSpanPercentileQuery(
_ context.Context,
req *spanpercentiletypes.SpanPercentileRequest,
) (*qbtypes.QueryRangeRequest, error) {
if err := req.Validate(); err != nil {
return nil, err
}
var attrKeys []string
for key := range req.ResourceAttributes {
attrKeys = append(attrKeys, key)
}
sort.Strings(attrKeys)
filterConditions := []string{
fmt.Sprintf("service.name = '%s'", strings.ReplaceAll(req.ServiceName, "'", `\'`)),
fmt.Sprintf("name = '%s'", strings.ReplaceAll(req.Name, "'", `\'`)),
}
for _, key := range attrKeys {
value := req.ResourceAttributes[key]
filterConditions = append(filterConditions,
fmt.Sprintf("%s = '%s'", key, strings.ReplaceAll(value, "'", `\'`)))
}
filterExpr := strings.Join(filterConditions, " AND ")
groupByKeys := []qbtypes.GroupByKey{
{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
Name: "service.name",
Signal: telemetrytypes.SignalTraces,
FieldContext: telemetrytypes.FieldContextResource,
FieldDataType: telemetrytypes.FieldDataTypeString,
},
},
{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
Name: "name",
Signal: telemetrytypes.SignalTraces,
FieldContext: telemetrytypes.FieldContextSpan,
FieldDataType: telemetrytypes.FieldDataTypeString,
},
},
}
for _, key := range attrKeys {
groupByKeys = append(groupByKeys, qbtypes.GroupByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
Name: key,
Signal: telemetrytypes.SignalTraces,
FieldContext: telemetrytypes.FieldContextResource,
FieldDataType: telemetrytypes.FieldDataTypeString,
},
})
}
query := qbtypes.QueryBuilderQuery[qbtypes.TraceAggregation]{
Name: "span_percentile",
Signal: telemetrytypes.SignalTraces,
Aggregations: []qbtypes.TraceAggregation{
{
Expression: "p50(duration_nano)",
Alias: "p50_duration_nano",
},
{
Expression: "p90(duration_nano)",
Alias: "p90_duration_nano",
},
{
Expression: "p99(duration_nano)",
Alias: "p99_duration_nano",
},
{
Expression: fmt.Sprintf(
"(100.0 * countIf(duration_nano <= %d)) / count()",
req.DurationNano,
),
Alias: "percentile_position",
},
},
GroupBy: groupByKeys,
Filter: &qbtypes.Filter{
Expression: filterExpr,
},
}
queryEnvelope := qbtypes.QueryEnvelope{
Type: qbtypes.QueryTypeBuilder,
Spec: query,
}
return &qbtypes.QueryRangeRequest{
SchemaVersion: "v5",
Start: req.Start,
End: req.End,
RequestType: qbtypes.RequestTypeScalar,
CompositeQuery: qbtypes.CompositeQuery{
Queries: []qbtypes.QueryEnvelope{queryEnvelope},
},
FormatOptions: &qbtypes.FormatOptions{
FormatTableResultForUI: true,
},
}, nil
}