Files
signoz/pkg/modules/spanpercentile/implspanpercentile/module.go
Nityananda Gohain 3a82085eb4 chore: enrich clickhouse log_comment (#10446)
* chore: enchance clickhouse log_comment

* chore: enrich all clickhouse queries

* fix: remove is_meatadata

* fix: use the new func

* fix: use semconv keys

* fix: add more details

* fix: minor changes

* fix: address comments

* fix: address cursor comments

* fix: minor changes

* fix: addressed comments

* fix: address comments and move to module functions where possible

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2026-03-06 12:57:15 +00:00

133 lines
4.0 KiB
Go

package implspanpercentile
import (
"context"
"fmt"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/modules/spanpercentile"
"github.com/SigNoz/signoz/pkg/querier"
"github.com/SigNoz/signoz/pkg/types/ctxtypes"
"github.com/SigNoz/signoz/pkg/types/instrumentationtypes"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/SigNoz/signoz/pkg/types/spanpercentiletypes"
"github.com/SigNoz/signoz/pkg/valuer"
)
type module struct {
querier querier.Querier
}
func NewModule(
querier querier.Querier,
_ factory.ProviderSettings,
) spanpercentile.Module {
return &module{
querier: querier,
}
}
func (m *module) GetSpanPercentile(ctx context.Context, orgID valuer.UUID, userID valuer.UUID, req *spanpercentiletypes.SpanPercentileRequest) (*spanpercentiletypes.SpanPercentileResponse, error) {
ctx = ctxtypes.NewContextWithCommentVals(ctx, map[string]string{
instrumentationtypes.CodeNamespace: "spanpercentile",
instrumentationtypes.CodeFunctionName: "GetSpanPercentile",
})
queryRangeRequest, err := buildSpanPercentileQuery(ctx, req)
if err != nil {
return nil, err
}
if err := queryRangeRequest.Validate(); err != nil {
return nil, err
}
result, err := m.querier.QueryRange(ctx, orgID, queryRangeRequest)
if err != nil {
return nil, err
}
return transformToSpanPercentileResponse(result)
}
func transformToSpanPercentileResponse(queryResult *qbtypes.QueryRangeResponse) (*spanpercentiletypes.SpanPercentileResponse, error) {
if len(queryResult.Data.Results) == 0 {
return nil, errors.New(errors.TypeInternal, errors.CodeInternal, "no data returned from query")
}
scalarData, ok := queryResult.Data.Results[0].(*qbtypes.ScalarData)
if !ok {
return nil, errors.New(errors.TypeInternal, errors.CodeInternal, "unexpected result type")
}
if len(scalarData.Data) == 0 {
return nil, errors.New(errors.TypeInternal, errors.CodeInternal, "no rows returned from query")
}
row := scalarData.Data[0]
columnMap := make(map[string]int)
for i, col := range scalarData.Columns {
columnMap[col.Name] = i
}
p50Idx, ok := columnMap["__result_0"]
if !ok {
return nil, errors.New(errors.TypeInternal, errors.CodeInternal, "missing __result_0 column")
}
p90Idx, ok := columnMap["__result_1"]
if !ok {
return nil, errors.New(errors.TypeInternal, errors.CodeInternal, "missing __result_1 column")
}
p99Idx, ok := columnMap["__result_2"]
if !ok {
return nil, errors.New(errors.TypeInternal, errors.CodeInternal, "missing __result_2 column")
}
positionIdx, ok := columnMap["__result_3"]
if !ok {
return nil, errors.New(errors.TypeInternal, errors.CodeInternal, "missing __result_3 column")
}
p50, err := toFloat64(row[p50Idx])
if err != nil {
return nil, errors.New(errors.TypeNotFound, errors.CodeNotFound, "no spans found matching the specified criteria")
}
p90, err := toFloat64(row[p90Idx])
if err != nil {
return nil, errors.New(errors.TypeNotFound, errors.CodeNotFound, "no spans found matching the specified criteria")
}
p99, err := toFloat64(row[p99Idx])
if err != nil {
return nil, errors.New(errors.TypeNotFound, errors.CodeNotFound, "no spans found matching the specified criteria")
}
position, err := toFloat64(row[positionIdx])
if err != nil {
return nil, errors.New(errors.TypeNotFound, errors.CodeNotFound, "no spans found matching the specified criteria")
}
description := fmt.Sprintf("slower than %.1f%% of spans", position)
if position < 50 {
description = fmt.Sprintf("faster than %.1f%% of spans", 100-position)
}
return &spanpercentiletypes.SpanPercentileResponse{
Percentiles: spanpercentiletypes.PercentileStats{
P50: p50,
P90: p90,
P99: p99,
},
Position: spanpercentiletypes.PercentilePosition{
Percentile: position,
Description: description,
},
}, nil
}
func toFloat64(val any) (float64, error) {
result, ok := val.(float64)
if !ok {
return 0, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "cannot convert %T to float64", val)
}
return result, nil
}