mirror of
https://github.com/SigNoz/signoz.git
synced 2026-11-04 15:31:08 +00:00
Compare commits
1 Commits
main
...
fix/resolv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63fa05d037 |
@@ -80,7 +80,7 @@
|
||||
"crypto-js": "4.2.0",
|
||||
"d3-hierarchy": "3.1.2",
|
||||
"dayjs": "^1.10.7",
|
||||
"dompurify": "3.4.17",
|
||||
"dompurify": "3.4.15",
|
||||
"event-source-polyfill": "1.0.31",
|
||||
"eventemitter3": "5.0.1",
|
||||
"history": "4.10.1",
|
||||
@@ -200,17 +200,17 @@
|
||||
"oxfmt": "0.73.0",
|
||||
"oxlint": "1.88.0",
|
||||
"oxlint-tsgolint": "7.0.2004",
|
||||
"postcss": "8.5.32",
|
||||
"postcss": "8.5.26",
|
||||
"postcss-scss": "4.0.9",
|
||||
"react-resizable": "3.0.4",
|
||||
"redux-mock-store": "1.5.4",
|
||||
"sass": "1.97.3",
|
||||
"sharp": "0.35.5",
|
||||
"sharp": "0.35.4",
|
||||
"storybook": "10.6.3",
|
||||
"stylelint": "17.15.0",
|
||||
"svgo": "4.1.0",
|
||||
"ts-jest": "29.4.15",
|
||||
"typescript-plugin-css-modules": "5.3.0",
|
||||
"typescript-plugin-css-modules": "5.2.0",
|
||||
"use-sync-external-store": "1.6.0",
|
||||
"vite-plugin-checker": "0.12.0",
|
||||
"vite-plugin-compression": "0.5.1",
|
||||
|
||||
465
frontend/pnpm-lock.yaml
generated
465
frontend/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -37,9 +37,9 @@ overrides:
|
||||
cookie@<0.7.0: '>=0.7.1 <1'
|
||||
# via: @grafana/data@11.6.15 (3.4.0/3.2.4 exact);
|
||||
# @monaco-editor/react > monaco-editor@0.55.1 (3.2.7 exact)
|
||||
# remove: blocked. The direct dep is already on 3.4.17, but @grafana/data
|
||||
# remove: blocked. The direct dep is already on 3.4.15, but @grafana/data
|
||||
# (latest 13.1.0) and monaco-editor (latest 0.55.1) still pin vulnerable versions
|
||||
dompurify@<=3.4.16: '>=3.4.17 <4'
|
||||
dompurify@<=3.4.12: '>=3.4.13 <4'
|
||||
# via: rolldown-vite@7.3.1 (esbuild ^0.27.0); ts-jest@29.4.9 (~0.27.4)
|
||||
# remove: blocked on rolldown-vite (7.3.1 is latest, still ^0.27.0);
|
||||
# orval >=8.20.0 and ts-jest >=29.4.11 already fixed on their side
|
||||
@@ -60,10 +60,17 @@ overrides:
|
||||
# @commitlint/cli > @commitlint/load > cosmiconfig@9 (^4.1.0)
|
||||
# remove: blocked, both consumers cap js-yaml at ^4 and only 4.3.2 carries the fix
|
||||
'js-yaml@>=4.0.0 <4.3.2': '>=4.3.2 <5'
|
||||
# via: typescript-plugin-css-modules@5.2.0 (less ^4.2.0) > less@4.4.0 (image-size ~0.5.0)
|
||||
# remove: bump typescript-plugin-css-modules once it floors less itself; image-size has
|
||||
# no patched release at all, so dropping the dep is the only fix — less@4.5.0 did
|
||||
less@<4.5.0: '>=4.5.0 <5'
|
||||
# via: direct dep postcss (nanoid ^3.3.17)
|
||||
# remove: blocked — postcss 8.5.26 (latest) caps nanoid at ^3, fix landed in 3.3.18
|
||||
nanoid@<3.3.18: '>=3.3.18 <4'
|
||||
# via: react-syntax-highlighter@15.5.0 (prismjs ^1.27.0 + refractor@3 ~1.27.0 tilde-pinned)
|
||||
# remove: bump react-syntax-highlighter to >=16.1.1 (prismjs ^1.30.0, refractor@5)
|
||||
prismjs@<1.30.0: '>=1.30.0 <2'
|
||||
# via: typescript-plugin-css-modules@5.3.0 > postcss-modules-local-by-default@4.2.0
|
||||
# via: typescript-plugin-css-modules@5.2.0 > postcss-modules-local-by-default@4.2.0
|
||||
# (postcss-selector-parser ^7.0.0)
|
||||
# remove: blocked, 4.2.0 is latest and the range is open, so the floor is what pulls the fix
|
||||
postcss-selector-parser@>=7.1.0 <7.1.3: '>=7.1.3 <8'
|
||||
|
||||
@@ -199,7 +199,8 @@ func (s *traceStore) genAISpanColumns(ctx context.Context, orgID valuer.UUID, bo
|
||||
|
||||
for _, value := range values {
|
||||
// lookup by number, the type metadata stores numeric attributes under; float64 is only the output cast
|
||||
expr, err := querybuilder.ResolveColumn(ctx, q, s.storage, attributeKey(value.key, telemetrytypes.FieldDataTypeNumber), telemetrytypes.FieldDataTypeFloat64, keys)
|
||||
// fixed gen_ai keys that many traces lack, so a not-found warning means nothing here
|
||||
expr, _, err := querybuilder.ResolveColumn(ctx, q, s.storage, attributeKey(value.key, telemetrytypes.FieldDataTypeNumber), telemetrytypes.FieldDataTypeFloat64, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -55,27 +55,27 @@ func (r *aggExprRewriter) Rewrite(
|
||||
expr string,
|
||||
rateInterval uint64,
|
||||
keys map[string][]*telemetrytypes.TelemetryFieldKey,
|
||||
) (string, []any, error) {
|
||||
) (string, []any, []string, error) {
|
||||
|
||||
wrapped := fmt.Sprintf("SELECT %s", expr)
|
||||
p := chparser.NewParser(wrapped)
|
||||
stmts, err := p.ParseStmts()
|
||||
|
||||
if err != nil {
|
||||
return "", nil, errors.WrapInternalf(err, errors.CodeInternal, "failed to parse aggregation expression %q", expr)
|
||||
return "", nil, nil, errors.WrapInternalf(err, errors.CodeInternal, "failed to parse aggregation expression %q", expr)
|
||||
}
|
||||
|
||||
if len(stmts) == 0 {
|
||||
return "", nil, errors.NewInternalf(errors.CodeInternal, "no statements found for %q", expr)
|
||||
return "", nil, nil, errors.NewInternalf(errors.CodeInternal, "no statements found for %q", expr)
|
||||
}
|
||||
|
||||
sel, ok := stmts[0].(*chparser.SelectQuery)
|
||||
if !ok {
|
||||
return "", nil, errors.NewInternalf(errors.CodeInternal, "expected SelectQuery, got %T", stmts[0])
|
||||
return "", nil, nil, errors.NewInternalf(errors.CodeInternal, "expected SelectQuery, got %T", stmts[0])
|
||||
}
|
||||
|
||||
if len(sel.SelectItems) == 0 {
|
||||
return "", nil, errors.NewInternalf(errors.CodeInternal, "no SELECT items for %q", expr)
|
||||
return "", nil, nil, errors.NewInternalf(errors.CodeInternal, "no SELECT items for %q", expr)
|
||||
}
|
||||
|
||||
visitor := &exprVisitor{
|
||||
@@ -88,13 +88,13 @@ func (r *aggExprRewriter) Rewrite(
|
||||
}
|
||||
// Rewrite the first select item (our expression)
|
||||
if err := sel.SelectItems[0].Accept(visitor); err != nil {
|
||||
return "", nil, err
|
||||
return "", nil, nil, err
|
||||
}
|
||||
|
||||
if visitor.isRate {
|
||||
return fmt.Sprintf("%s/%d", chparser.Format(sel.SelectItems[0]), rateInterval), visitor.chArgs, nil
|
||||
return fmt.Sprintf("%s/%d", chparser.Format(sel.SelectItems[0]), rateInterval), visitor.chArgs, visitor.warnings, nil
|
||||
}
|
||||
return chparser.Format(sel.SelectItems[0]), visitor.chArgs, nil
|
||||
return chparser.Format(sel.SelectItems[0]), visitor.chArgs, visitor.warnings, nil
|
||||
}
|
||||
|
||||
// RewriteMulti rewrites a slice of expressions.
|
||||
@@ -106,24 +106,26 @@ func (r *aggExprRewriter) RewriteMulti(
|
||||
exprs []string,
|
||||
rateInterval uint64,
|
||||
keys map[string][]*telemetrytypes.TelemetryFieldKey,
|
||||
) ([]string, [][]any, error) {
|
||||
) ([]string, [][]any, []string, error) {
|
||||
out := make([]string, len(exprs))
|
||||
var errs []error
|
||||
var chArgsList [][]any
|
||||
var warnings []string
|
||||
for i, e := range exprs {
|
||||
w, chArgs, err := r.Rewrite(ctx, orgID, startNs, endNs, e, rateInterval, keys)
|
||||
w, chArgs, exprWarnings, err := r.Rewrite(ctx, orgID, startNs, endNs, e, rateInterval, keys)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
out[i] = e
|
||||
} else {
|
||||
out[i] = w
|
||||
chArgsList = append(chArgsList, chArgs)
|
||||
warnings = append(warnings, exprWarnings...)
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return out, nil, errors.Join(errs...)
|
||||
return out, nil, nil, errors.Join(errs...)
|
||||
}
|
||||
return out, chArgsList, nil
|
||||
return out, chArgsList, warnings, nil
|
||||
}
|
||||
|
||||
// exprVisitor walks FunctionExpr nodes and resolves and renders their
|
||||
@@ -138,6 +140,7 @@ type exprVisitor struct {
|
||||
storage qbtypes.Storage
|
||||
Modified bool
|
||||
chArgs []any
|
||||
warnings []string
|
||||
isRate bool
|
||||
}
|
||||
|
||||
@@ -189,6 +192,7 @@ func (v *exprVisitor) VisitFunctionExpr(fn *chparser.FunctionExpr) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.warnings = append(v.warnings, whereClause.Warnings...)
|
||||
// not possible for whereClause to be empty here but still adding a check.
|
||||
if whereClause.IsEmpty() {
|
||||
return errors.NewInvalidInputf(errors.CodeInvalidInput, "invalid predicate argument for %q: %q", name, origPred)
|
||||
@@ -208,10 +212,11 @@ func (v *exprVisitor) VisitFunctionExpr(fn *chparser.FunctionExpr) error {
|
||||
for i := 0; i < len(args)-1; i++ {
|
||||
origVal := chparser.Format(args[i])
|
||||
fieldKey := telemetrytypes.GetFieldKeyFromKeyText(origVal)
|
||||
expr, err := ResolveColumn(v.ctx, v.query, v.storage, &fieldKey, dataType, v.fieldKeys)
|
||||
expr, warnings, err := ResolveColumn(v.ctx, v.query, v.storage, &fieldKey, dataType, v.fieldKeys)
|
||||
if err != nil {
|
||||
return errors.WrapInvalidInputf(err, errors.CodeInvalidInput, "failed to get table field name for %q", origVal)
|
||||
}
|
||||
v.warnings = append(v.warnings, warnings...)
|
||||
newVal := sqlbuilder.Escape(expr)
|
||||
parsedVal, err := parseFragment(newVal)
|
||||
if err != nil {
|
||||
@@ -225,10 +230,11 @@ func (v *exprVisitor) VisitFunctionExpr(fn *chparser.FunctionExpr) error {
|
||||
for i, arg := range args {
|
||||
orig := chparser.Format(arg)
|
||||
fieldKey := telemetrytypes.GetFieldKeyFromKeyText(orig)
|
||||
expr, err := ResolveColumn(v.ctx, v.query, v.storage, &fieldKey, dataType, v.fieldKeys)
|
||||
expr, warnings, err := ResolveColumn(v.ctx, v.query, v.storage, &fieldKey, dataType, v.fieldKeys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.warnings = append(v.warnings, warnings...)
|
||||
newCol := sqlbuilder.Escape(expr)
|
||||
parsed, err := parseFragment(newCol)
|
||||
if err != nil {
|
||||
|
||||
@@ -111,7 +111,8 @@ func Resolve(
|
||||
}
|
||||
|
||||
// ResolveColumn resolves one key for a select field, group by, order by, or
|
||||
// aggregation, and renders its column expression.
|
||||
// aggregation, and renders its column expression. The warnings are the ones
|
||||
// a filter on the same key reports.
|
||||
func ResolveColumn(
|
||||
ctx context.Context,
|
||||
q qbtypes.QueryInfo,
|
||||
@@ -119,12 +120,27 @@ func ResolveColumn(
|
||||
key *telemetrytypes.TelemetryFieldKey,
|
||||
target telemetrytypes.FieldDataType,
|
||||
fieldKeys map[string][]*telemetrytypes.TelemetryFieldKey,
|
||||
) (string, error) {
|
||||
) (string, []string, error) {
|
||||
resolved, err := Resolve(ctx, q, storage, key, qbtypes.FilterOperatorUnknown, nil, fieldKeys)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", nil, err
|
||||
}
|
||||
return Column(ctx, q, storage, resolved, target)
|
||||
column, err := Column(ctx, q, storage, resolved, target)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return column, resolved.Warnings, nil
|
||||
}
|
||||
|
||||
// AppendWarnings appends each warning dst does not hold yet, so a key in both
|
||||
// the filter and a group by warns once.
|
||||
func AppendWarnings(dst []string, warnings ...string) []string {
|
||||
for _, warning := range warnings {
|
||||
if !slices.Contains(dst, warning) {
|
||||
dst = append(dst, warning)
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// intrinsicColumnFirst puts a column every row has first for a bare key.
|
||||
|
||||
@@ -229,8 +229,9 @@ func (b *auditQueryStatementBuilder) buildListQuery(
|
||||
) (*qbtypes.Statement, error) {
|
||||
info := querybuilder.NewQueryInfo(ctx, orgID, b.fl, telemetrytypes.SignalLogs, nil, start, end)
|
||||
var (
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
columnWarnings []string
|
||||
)
|
||||
|
||||
if frag, args, err := b.maybeAttachResourceFilter(ctx, orgID, sb, query, start, end, variables); err != nil {
|
||||
@@ -263,10 +264,11 @@ func (b *auditQueryStatementBuilder) buildListQuery(
|
||||
continue
|
||||
}
|
||||
|
||||
colExpr, err := querybuilder.ResolveColumn(ctx, info, b.storage, &query.SelectFields[index], telemetrytypes.FieldDataTypeUnspecified, keys)
|
||||
colExpr, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.storage, &query.SelectFields[index], telemetrytypes.FieldDataTypeUnspecified, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
sb.SelectMore(fmt.Sprintf("%s AS `%s`", sqlbuilder.Escape(colExpr), query.SelectFields[index].Name))
|
||||
}
|
||||
}
|
||||
@@ -279,10 +281,11 @@ func (b *auditQueryStatementBuilder) buildListQuery(
|
||||
}
|
||||
|
||||
for _, orderBy := range query.Order {
|
||||
colExpr, err := querybuilder.ResolveColumn(ctx, info, b.storage, &orderBy.Key.TelemetryFieldKey, telemetrytypes.FieldDataTypeUnspecified, keys)
|
||||
colExpr, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.storage, &orderBy.Key.TelemetryFieldKey, telemetrytypes.FieldDataTypeUnspecified, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
sb.OrderBy(fmt.Sprintf("%s %s", sqlbuilder.Escape(colExpr), orderBy.Direction.StringValue()))
|
||||
}
|
||||
|
||||
@@ -304,7 +307,7 @@ func (b *auditQueryStatementBuilder) buildListQuery(
|
||||
stmt := &qbtypes.Statement{
|
||||
Query: finalSQL,
|
||||
Args: finalArgs,
|
||||
Warnings: preparedWhereClause.Warnings,
|
||||
Warnings: querybuilder.AppendWarnings(preparedWhereClause.Warnings, columnWarnings...),
|
||||
WarningsDocURL: preparedWhereClause.WarningsDocURL,
|
||||
}
|
||||
|
||||
@@ -321,8 +324,9 @@ func (b *auditQueryStatementBuilder) buildTimeSeriesQuery(
|
||||
variables map[string]qbtypes.VariableItem,
|
||||
) (*qbtypes.Statement, error) {
|
||||
var (
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
columnWarnings []string
|
||||
)
|
||||
|
||||
if frag, args, err := b.maybeAttachResourceFilter(ctx, orgID, sb, query, start, end, variables); err != nil {
|
||||
@@ -342,10 +346,11 @@ func (b *auditQueryStatementBuilder) buildTimeSeriesQuery(
|
||||
fieldNames := make([]string, 0, len(query.GroupBy))
|
||||
info := querybuilder.NewQueryInfo(ctx, orgID, b.fl, telemetrytypes.SignalLogs, nil, start, end)
|
||||
for _, gb := range query.GroupBy {
|
||||
expr, err := querybuilder.ResolveColumn(ctx, info, b.storage, &gb.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
expr, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.storage, &gb.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
|
||||
colExpr := sqlbuilder.Escape(fmt.Sprintf("toString(%s) AS %s", expr, clickhousesql.Identifier(gb.Name)))
|
||||
sb.SelectMore(colExpr)
|
||||
@@ -354,10 +359,11 @@ func (b *auditQueryStatementBuilder) buildTimeSeriesQuery(
|
||||
|
||||
allAggChArgs := make([]any, 0)
|
||||
for i, agg := range query.Aggregations {
|
||||
rewritten, chArgs, err := b.aggExprRewriter.Rewrite(ctx, orgID, start, end, agg.Expression, uint64(query.StepInterval.Seconds()), keys)
|
||||
rewritten, chArgs, aggWarnings, err := b.aggExprRewriter.Rewrite(ctx, orgID, start, end, agg.Expression, uint64(query.StepInterval.Seconds()), keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, aggWarnings...)
|
||||
allAggChArgs = append(allAggChArgs, chArgs...)
|
||||
sb.SelectMore(fmt.Sprintf("%s AS __result_%d", rewritten, i))
|
||||
}
|
||||
@@ -443,7 +449,7 @@ func (b *auditQueryStatementBuilder) buildTimeSeriesQuery(
|
||||
stmt := &qbtypes.Statement{
|
||||
Query: finalSQL,
|
||||
Args: finalArgs,
|
||||
Warnings: preparedWhereClause.Warnings,
|
||||
Warnings: querybuilder.AppendWarnings(preparedWhereClause.Warnings, columnWarnings...),
|
||||
WarningsDocURL: preparedWhereClause.WarningsDocURL,
|
||||
}
|
||||
|
||||
@@ -461,8 +467,9 @@ func (b *auditQueryStatementBuilder) buildScalarQuery(
|
||||
variables map[string]qbtypes.VariableItem,
|
||||
) (*qbtypes.Statement, error) {
|
||||
var (
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
columnWarnings []string
|
||||
)
|
||||
|
||||
if frag, args, err := b.maybeAttachResourceFilter(ctx, orgID, sb, query, start, end, variables); err != nil {
|
||||
@@ -478,10 +485,11 @@ func (b *auditQueryStatementBuilder) buildScalarQuery(
|
||||
|
||||
info := querybuilder.NewQueryInfo(ctx, orgID, b.fl, telemetrytypes.SignalLogs, nil, start, end)
|
||||
for _, gb := range query.GroupBy {
|
||||
expr, err := querybuilder.ResolveColumn(ctx, info, b.storage, &gb.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
expr, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.storage, &gb.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
|
||||
colExpr := sqlbuilder.Escape(fmt.Sprintf("toString(%s) AS %s", expr, clickhousesql.Identifier(gb.Name)))
|
||||
sb.SelectMore(colExpr)
|
||||
@@ -492,10 +500,11 @@ func (b *auditQueryStatementBuilder) buildScalarQuery(
|
||||
if len(query.Aggregations) > 0 {
|
||||
for idx := range query.Aggregations {
|
||||
aggExpr := query.Aggregations[idx]
|
||||
rewritten, chArgs, err := b.aggExprRewriter.Rewrite(ctx, orgID, start, end, aggExpr.Expression, rateInterval, keys)
|
||||
rewritten, chArgs, aggWarnings, err := b.aggExprRewriter.Rewrite(ctx, orgID, start, end, aggExpr.Expression, rateInterval, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, aggWarnings...)
|
||||
allAggChArgs = append(allAggChArgs, chArgs...)
|
||||
sb.SelectMore(fmt.Sprintf("%s AS __result_%d", rewritten, idx))
|
||||
}
|
||||
@@ -546,7 +555,7 @@ func (b *auditQueryStatementBuilder) buildScalarQuery(
|
||||
stmt := &qbtypes.Statement{
|
||||
Query: finalSQL,
|
||||
Args: finalArgs,
|
||||
Warnings: preparedWhereClause.Warnings,
|
||||
Warnings: querybuilder.AppendWarnings(preparedWhereClause.Warnings, columnWarnings...),
|
||||
WarningsDocURL: preparedWhereClause.WarningsDocURL,
|
||||
}
|
||||
|
||||
|
||||
@@ -337,8 +337,9 @@ func (b *logQueryStatementBuilder) buildListQuery(
|
||||
info := querybuilder.NewQueryInfo(ctx, orgID, b.fl, telemetrytypes.SignalLogs, nil, start, end)
|
||||
|
||||
var (
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
columnWarnings []string
|
||||
)
|
||||
|
||||
frag, args, skipResourceFilter, err := b.maybeAttachResourceFilter(ctx, orgID, sb, query, start, end, variables)
|
||||
@@ -377,10 +378,11 @@ func (b *logQueryStatementBuilder) buildListQuery(
|
||||
}
|
||||
|
||||
// get column expression for the field - use array index directly to avoid pointer to loop variable
|
||||
colExpr, err := querybuilder.ResolveColumn(ctx, info, b.storage, columnKey(&query.SelectFields[index]), telemetrytypes.FieldDataTypeUnspecified, keys)
|
||||
colExpr, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.storage, columnKey(&query.SelectFields[index]), telemetrytypes.FieldDataTypeUnspecified, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
sb.SelectMore(sqlbuilder.Escape(fmt.Sprintf("%s AS %s", colExpr, selectColumnAlias(index, query.SelectFields[index].Name))))
|
||||
}
|
||||
}
|
||||
@@ -396,10 +398,11 @@ func (b *logQueryStatementBuilder) buildListQuery(
|
||||
// Add order by
|
||||
for _, orderBy := range query.Order {
|
||||
|
||||
colExpr, err := querybuilder.ResolveColumn(ctx, info, b.storage, columnKey(&orderBy.Key.TelemetryFieldKey), telemetrytypes.FieldDataTypeUnspecified, keys)
|
||||
colExpr, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.storage, columnKey(&orderBy.Key.TelemetryFieldKey), telemetrytypes.FieldDataTypeUnspecified, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
sb.OrderBy(fmt.Sprintf("%s %s", sqlbuilder.Escape(colExpr), orderBy.Direction.StringValue()))
|
||||
}
|
||||
|
||||
@@ -422,7 +425,7 @@ func (b *logQueryStatementBuilder) buildListQuery(
|
||||
stmt := &qbtypes.Statement{
|
||||
Query: finalSQL,
|
||||
Args: finalArgs,
|
||||
Warnings: preparedWhereClause.Warnings,
|
||||
Warnings: querybuilder.AppendWarnings(preparedWhereClause.Warnings, columnWarnings...),
|
||||
WarningsDocURL: preparedWhereClause.WarningsDocURL,
|
||||
CostGuard: b.costGuardFor(ctx, orgID, preparedWhereClause.RequiresCostGuard),
|
||||
}
|
||||
@@ -441,8 +444,9 @@ func (b *logQueryStatementBuilder) buildTimeSeriesQuery(
|
||||
) (*qbtypes.Statement, error) {
|
||||
|
||||
var (
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
columnWarnings []string
|
||||
)
|
||||
|
||||
frag, args, skipResourceFilter, err := b.maybeAttachResourceFilter(ctx, orgID, sb, query, start, end, variables)
|
||||
@@ -466,10 +470,11 @@ func (b *logQueryStatementBuilder) buildTimeSeriesQuery(
|
||||
if !info.BodyJSONOn && (strings.Contains(gb.Name, telemetrytypes.ArraySep) || strings.Contains(gb.Name, telemetrytypes.ArrayAnyIndex)) {
|
||||
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "Group by/Aggregation isn't available for the Array Paths: %s", gb.Name)
|
||||
}
|
||||
expr, err := querybuilder.ResolveColumn(ctx, info, b.storage, columnKey(&gb.TelemetryFieldKey), telemetrytypes.FieldDataTypeString, keys)
|
||||
expr, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.storage, columnKey(&gb.TelemetryFieldKey), telemetrytypes.FieldDataTypeString, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
|
||||
fieldAlias := groupByColumnAlias(i, gb.Name)
|
||||
sb.SelectMore(sqlbuilder.Escape(fmt.Sprintf("toString(%s) AS %s", expr, fieldAlias)))
|
||||
@@ -479,7 +484,7 @@ func (b *logQueryStatementBuilder) buildTimeSeriesQuery(
|
||||
// Aggregations
|
||||
allAggChArgs := make([]any, 0)
|
||||
for i, agg := range query.Aggregations {
|
||||
rewritten, chArgs, err := b.aggExprRewriter.Rewrite(
|
||||
rewritten, chArgs, aggWarnings, err := b.aggExprRewriter.Rewrite(
|
||||
ctx, orgID, start, end, agg.Expression,
|
||||
uint64(query.StepInterval.Seconds()),
|
||||
keys,
|
||||
@@ -487,6 +492,7 @@ func (b *logQueryStatementBuilder) buildTimeSeriesQuery(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, aggWarnings...)
|
||||
allAggChArgs = append(allAggChArgs, chArgs...)
|
||||
sb.SelectMore(fmt.Sprintf("%s AS __result_%d", rewritten, i))
|
||||
}
|
||||
@@ -589,7 +595,7 @@ func (b *logQueryStatementBuilder) buildTimeSeriesQuery(
|
||||
stmt := &qbtypes.Statement{
|
||||
Query: finalSQL,
|
||||
Args: finalArgs,
|
||||
Warnings: preparedWhereClause.Warnings,
|
||||
Warnings: querybuilder.AppendWarnings(preparedWhereClause.Warnings, columnWarnings...),
|
||||
WarningsDocURL: preparedWhereClause.WarningsDocURL,
|
||||
CostGuard: b.costGuardFor(ctx, orgID, preparedWhereClause.RequiresCostGuard),
|
||||
}
|
||||
@@ -610,8 +616,9 @@ func (b *logQueryStatementBuilder) buildScalarQuery(
|
||||
) (*qbtypes.Statement, error) {
|
||||
|
||||
var (
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
columnWarnings []string
|
||||
)
|
||||
|
||||
frag, args, skipResourceFilter, err := b.maybeAttachResourceFilter(ctx, orgID, sb, query, start, end, variables)
|
||||
@@ -631,10 +638,11 @@ func (b *logQueryStatementBuilder) buildScalarQuery(
|
||||
if !info.BodyJSONOn && (strings.Contains(gb.Name, telemetrytypes.ArraySep) || strings.Contains(gb.Name, telemetrytypes.ArrayAnyIndex)) {
|
||||
return nil, errors.NewInvalidInputf(errors.CodeInvalidInput, "Group by/Aggregation isn't available for the Array Paths: %s", gb.Name)
|
||||
}
|
||||
expr, err := querybuilder.ResolveColumn(ctx, info, b.storage, columnKey(&gb.TelemetryFieldKey), telemetrytypes.FieldDataTypeString, keys)
|
||||
expr, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.storage, columnKey(&gb.TelemetryFieldKey), telemetrytypes.FieldDataTypeString, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
|
||||
fieldAlias := groupByColumnAlias(i, gb.Name)
|
||||
sb.SelectMore(sqlbuilder.Escape(fmt.Sprintf("toString(%s) AS %s", expr, fieldAlias)))
|
||||
@@ -648,7 +656,7 @@ func (b *logQueryStatementBuilder) buildScalarQuery(
|
||||
if len(query.Aggregations) > 0 {
|
||||
for idx := range query.Aggregations {
|
||||
aggExpr := query.Aggregations[idx]
|
||||
rewritten, chArgs, err := b.aggExprRewriter.Rewrite(
|
||||
rewritten, chArgs, aggWarnings, err := b.aggExprRewriter.Rewrite(
|
||||
ctx, orgID, start, end, aggExpr.Expression,
|
||||
rateInterval,
|
||||
keys,
|
||||
@@ -656,6 +664,7 @@ func (b *logQueryStatementBuilder) buildScalarQuery(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, aggWarnings...)
|
||||
allAggChArgs = append(allAggChArgs, chArgs...)
|
||||
sb.SelectMore(fmt.Sprintf("%s AS __result_%d", rewritten, idx))
|
||||
}
|
||||
@@ -717,7 +726,7 @@ func (b *logQueryStatementBuilder) buildScalarQuery(
|
||||
stmt := &qbtypes.Statement{
|
||||
Query: finalSQL,
|
||||
Args: finalArgs,
|
||||
Warnings: preparedWhereClause.Warnings,
|
||||
Warnings: querybuilder.AppendWarnings(preparedWhereClause.Warnings, columnWarnings...),
|
||||
WarningsDocURL: preparedWhereClause.WarningsDocURL,
|
||||
CostGuard: b.costGuardFor(ctx, orgID, preparedWhereClause.RequiresCostGuard),
|
||||
}
|
||||
|
||||
@@ -148,7 +148,8 @@ func (b *meterQueryStatementBuilder) buildTemporalAggDeltaFastPath(
|
||||
))
|
||||
info := querybuilder.NewQueryInfo(ctx, orgID, nil, telemetrytypes.SignalMetrics, &telemetrytypes.MetricContext{MetricName: query.Aggregations[0].MetricName}, start, end)
|
||||
for i, g := range query.GroupBy {
|
||||
col, err := querybuilder.ResolveColumn(ctx, info, b.storage, &g.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
// the meter path returns no warnings, filter warnings included
|
||||
col, _, err := querybuilder.ResolveColumn(ctx, info, b.storage, &g.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
@@ -235,7 +236,8 @@ func (b *meterQueryStatementBuilder) buildTemporalAggDelta(
|
||||
|
||||
info := querybuilder.NewQueryInfo(ctx, orgID, nil, telemetrytypes.SignalMetrics, &telemetrytypes.MetricContext{MetricName: query.Aggregations[0].MetricName}, start, end)
|
||||
for i, g := range query.GroupBy {
|
||||
col, err := querybuilder.ResolveColumn(ctx, info, b.storage, &g.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
// the meter path returns no warnings, filter warnings included
|
||||
col, _, err := querybuilder.ResolveColumn(ctx, info, b.storage, &g.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
@@ -311,7 +313,8 @@ func (b *meterQueryStatementBuilder) buildTemporalAggCumulativeOrUnspecified(
|
||||
))
|
||||
info := querybuilder.NewQueryInfo(ctx, orgID, nil, telemetrytypes.SignalMetrics, &telemetrytypes.MetricContext{MetricName: query.Aggregations[0].MetricName}, start, end)
|
||||
for i, g := range query.GroupBy {
|
||||
col, err := querybuilder.ResolveColumn(ctx, info, b.storage, &g.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
// the meter path returns no warnings, filter warnings included
|
||||
col, _, err := querybuilder.ResolveColumn(ctx, info, b.storage, &g.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
@@ -320,7 +320,8 @@ func (b *StatementBuilder) buildReducedTimeSeriesCTE(
|
||||
sb.From(fmt.Sprintf("%s.%s", metricstelemetryschema.DBName, metricstelemetryschema.TimeseriesV4ReducedLocalTableName))
|
||||
sb.Select("fingerprint")
|
||||
for i, g := range query.GroupBy {
|
||||
col, err := querybuilder.ResolveColumn(ctx, info, b.storage, &g.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
// buildTimeSeriesCTE resolves the same keys and reports their warnings
|
||||
col, _, err := querybuilder.ResolveColumn(ctx, info, b.storage, &g.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
@@ -544,11 +545,16 @@ func (b *StatementBuilder) buildTimeSeriesCTE(
|
||||
sb.From(fmt.Sprintf("%s.%s", metricstelemetryschema.DBName, tsTable))
|
||||
|
||||
sb.Select("fingerprint")
|
||||
var columnWarnings []string
|
||||
for i, g := range query.GroupBy {
|
||||
col, err := querybuilder.ResolveColumn(ctx, info, b.storage, &g.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
col, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.storage, &g.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
if err != nil {
|
||||
return "", nil, nil, err
|
||||
}
|
||||
// the histogram rewrite adds le itself, so its warning is not the caller's
|
||||
if !isHistogramBucket(g) {
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
}
|
||||
sb.SelectMore(sqlbuilder.Escape(fmt.Sprintf("%s AS %s", col, GroupByColumnAlias(i, g.Name))))
|
||||
}
|
||||
|
||||
@@ -577,7 +583,7 @@ func (b *StatementBuilder) buildTimeSeriesCTE(
|
||||
|
||||
q, args := sb.BuildWithFlavor(sqlbuilder.ClickHouse)
|
||||
// the caller joins this into another builder, which compiles it again
|
||||
return fmt.Sprintf("(%s) AS filtered_time_series", sqlbuilder.Escape(q)), args, preparedWhereClause.Warnings, nil
|
||||
return fmt.Sprintf("(%s) AS filtered_time_series", sqlbuilder.Escape(q)), args, querybuilder.AppendWarnings(preparedWhereClause.Warnings, columnWarnings...), nil
|
||||
}
|
||||
|
||||
func (b *StatementBuilder) buildTemporalAggregationCTE(
|
||||
|
||||
@@ -36,7 +36,8 @@ func (r *columnResolver) ValueFor(ctx context.Context, q qbtypes.QueryInfo, key
|
||||
if cands := r.keys[key.Name]; len(cands) > 0 {
|
||||
key = cands[0]
|
||||
}
|
||||
expr, err := querybuilder.ResolveColumn(ctx, q, r.storage, key, dt, r.keys)
|
||||
// aggregate renders return no warnings
|
||||
expr, _, err := querybuilder.ResolveColumn(ctx, q, r.storage, key, dt, r.keys)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -478,19 +478,21 @@ func groupBySelectors(groupBy []qbtypes.GroupByKey) []*telemetrytypes.FieldKeySe
|
||||
|
||||
// resolveGroupColumns resolves group-by keys through the storage for selection
|
||||
// inside the per-trace scan; keys must cover the group-by selectors.
|
||||
func (b *scopedTraceStatementBuilder) resolveGroupColumns(ctx context.Context, q qbtypes.QueryInfo, groupBy []qbtypes.GroupByKey, keys map[string][]*telemetrytypes.TelemetryFieldKey) ([]groupColumn, error) {
|
||||
func (b *scopedTraceStatementBuilder) resolveGroupColumns(ctx context.Context, q qbtypes.QueryInfo, groupBy []qbtypes.GroupByKey, keys map[string][]*telemetrytypes.TelemetryFieldKey) ([]groupColumn, []string, error) {
|
||||
if len(groupBy) == 0 {
|
||||
return nil, nil
|
||||
return nil, nil, nil
|
||||
}
|
||||
out := make([]groupColumn, 0, len(groupBy))
|
||||
var warnings []string
|
||||
for i := range groupBy {
|
||||
expr, err := querybuilder.ResolveColumn(ctx, q, b.storage, &groupBy[i].TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
expr, keyWarnings, err := querybuilder.ResolveColumn(ctx, q, b.storage, &groupBy[i].TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
warnings = append(warnings, keyWarnings...)
|
||||
out = append(out, groupColumn{alias: groupByColumnAlias(i, groupBy[i].Name), expr: sqlbuilder.Escape(expr)})
|
||||
}
|
||||
return out, nil
|
||||
return out, warnings, nil
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -598,7 +600,7 @@ func (b *scopedTraceStatementBuilder) buildTraceAggregationQuery(
|
||||
}
|
||||
}
|
||||
|
||||
groupCols, err := b.resolveGroupColumns(ctx, querybuilder.NewQueryInfo(ctx, orgID, b.fl, telemetrytypes.SignalTraces, nil, start, end), query.GroupBy, keys)
|
||||
groupCols, groupWarnings, err := b.resolveGroupColumns(ctx, querybuilder.NewQueryInfo(ctx, orgID, b.fl, telemetrytypes.SignalTraces, nil, start, end), query.GroupBy, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -731,7 +733,7 @@ func (b *scopedTraceStatementBuilder) buildTraceAggregationQuery(
|
||||
return &qbtypes.Statement{
|
||||
Query: finalSQL,
|
||||
Args: finalArgs,
|
||||
Warnings: msc.warnings,
|
||||
Warnings: querybuilder.AppendWarnings(msc.warnings, groupWarnings...),
|
||||
WarningsDocURL: msc.warnURL,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -362,8 +362,9 @@ func (b *traceQueryStatementBuilder) buildListQuery(
|
||||
) (*qbtypes.Statement, error) {
|
||||
|
||||
var (
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
columnWarnings []string
|
||||
)
|
||||
|
||||
frag, args, skipResourceFilter, err := b.maybeAttachResourceFilter(ctx, orgID, sb, query, start, end, variables)
|
||||
@@ -382,10 +383,11 @@ func (b *traceQueryStatementBuilder) buildListQuery(
|
||||
|
||||
info := querybuilder.NewQueryInfo(ctx, orgID, b.fl, telemetrytypes.SignalTraces, nil, start, end)
|
||||
for i, field := range query.SelectFields {
|
||||
expr, err := querybuilder.ResolveColumn(ctx, info, b.storage, &field, telemetrytypes.FieldDataTypeUnspecified, keys)
|
||||
expr, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.storage, &field, telemetrytypes.FieldDataTypeUnspecified, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
sb.SelectMore(sqlbuilder.Escape(fmt.Sprintf("%s AS %s", expr, selectColumnAlias(i, field.Name))))
|
||||
}
|
||||
|
||||
@@ -406,10 +408,11 @@ func (b *traceQueryStatementBuilder) buildListQuery(
|
||||
|
||||
// Add order by
|
||||
for _, orderBy := range query.Order {
|
||||
expr, err := querybuilder.ResolveColumn(ctx, info, b.storage, &orderBy.Key.TelemetryFieldKey, telemetrytypes.FieldDataTypeUnspecified, keys)
|
||||
expr, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.storage, &orderBy.Key.TelemetryFieldKey, telemetrytypes.FieldDataTypeUnspecified, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
sb.OrderBy(fmt.Sprintf("%s %s", sqlbuilder.Escape(expr), orderBy.Direction.StringValue()))
|
||||
}
|
||||
|
||||
@@ -432,7 +435,7 @@ func (b *traceQueryStatementBuilder) buildListQuery(
|
||||
stmt := &qbtypes.Statement{
|
||||
Query: finalSQL,
|
||||
Args: finalArgs,
|
||||
Warnings: preparedWhereClause.Warnings,
|
||||
Warnings: querybuilder.AppendWarnings(preparedWhereClause.Warnings, columnWarnings...),
|
||||
WarningsDocURL: preparedWhereClause.WarningsDocURL,
|
||||
}
|
||||
|
||||
@@ -569,8 +572,9 @@ func (b *traceQueryStatementBuilder) buildTimeSeriesQuery(
|
||||
) (*qbtypes.Statement, error) {
|
||||
|
||||
var (
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
columnWarnings []string
|
||||
)
|
||||
|
||||
frag, args, skipResourceFilter, err := b.maybeAttachResourceFilter(ctx, orgID, sb, query, start, end, variables)
|
||||
@@ -596,10 +600,11 @@ func (b *traceQueryStatementBuilder) buildTimeSeriesQuery(
|
||||
fieldNames := make([]string, 0, len(query.GroupBy))
|
||||
info := querybuilder.NewQueryInfo(ctx, orgID, b.fl, telemetrytypes.SignalTraces, nil, start, end)
|
||||
for i, gb := range query.GroupBy {
|
||||
expr, err := querybuilder.ResolveColumn(ctx, info, b.storage, &gb.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
expr, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.storage, &gb.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
fieldAlias := groupByColumnAlias(i, gb.Name)
|
||||
sb.SelectMore(sqlbuilder.Escape(fmt.Sprintf("toString(%s) AS %s", expr, fieldAlias)))
|
||||
fieldNames = append(fieldNames, sqlbuilder.Escape(fieldAlias))
|
||||
@@ -608,7 +613,7 @@ func (b *traceQueryStatementBuilder) buildTimeSeriesQuery(
|
||||
// Aggregations
|
||||
allAggChArgs := make([]any, 0)
|
||||
for i, agg := range query.Aggregations {
|
||||
rewritten, chArgs, err := b.aggExprRewriter.Rewrite(
|
||||
rewritten, chArgs, aggWarnings, err := b.aggExprRewriter.Rewrite(
|
||||
ctx, orgID, start, end, agg.Expression,
|
||||
uint64(query.StepInterval.Seconds()),
|
||||
keys,
|
||||
@@ -616,6 +621,7 @@ func (b *traceQueryStatementBuilder) buildTimeSeriesQuery(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, aggWarnings...)
|
||||
allAggChArgs = append(allAggChArgs, chArgs...)
|
||||
sb.SelectMore(fmt.Sprintf("%s AS __result_%d", rewritten, i))
|
||||
}
|
||||
@@ -714,7 +720,7 @@ func (b *traceQueryStatementBuilder) buildTimeSeriesQuery(
|
||||
stmt := &qbtypes.Statement{
|
||||
Query: finalSQL,
|
||||
Args: finalArgs,
|
||||
Warnings: preparedWhereClause.Warnings,
|
||||
Warnings: querybuilder.AppendWarnings(preparedWhereClause.Warnings, columnWarnings...),
|
||||
WarningsDocURL: preparedWhereClause.WarningsDocURL,
|
||||
}
|
||||
|
||||
@@ -735,8 +741,9 @@ func (b *traceQueryStatementBuilder) buildScalarQuery(
|
||||
) (*qbtypes.Statement, error) {
|
||||
|
||||
var (
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
cteFragments []string
|
||||
cteArgs [][]any
|
||||
columnWarnings []string
|
||||
)
|
||||
|
||||
frag, args, skipResourceFilter, err := b.maybeAttachResourceFilter(ctx, orgID, sb, query, start, end, variables)
|
||||
@@ -760,10 +767,11 @@ func (b *traceQueryStatementBuilder) buildScalarQuery(
|
||||
fieldNames := make([]string, 0, len(query.GroupBy))
|
||||
info := querybuilder.NewQueryInfo(ctx, orgID, b.fl, telemetrytypes.SignalTraces, nil, start, end)
|
||||
for i, gb := range query.GroupBy {
|
||||
expr, err := querybuilder.ResolveColumn(ctx, info, b.storage, &gb.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
expr, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.storage, &gb.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
fieldAlias := groupByColumnAlias(i, gb.Name)
|
||||
sb.SelectMore(sqlbuilder.Escape(fmt.Sprintf("toString(%s) AS %s", expr, fieldAlias)))
|
||||
fieldNames = append(fieldNames, sqlbuilder.Escape(fieldAlias))
|
||||
@@ -776,7 +784,7 @@ func (b *traceQueryStatementBuilder) buildScalarQuery(
|
||||
if len(query.Aggregations) > 0 {
|
||||
for idx := range query.Aggregations {
|
||||
aggExpr := query.Aggregations[idx]
|
||||
rewritten, chArgs, err := b.aggExprRewriter.Rewrite(
|
||||
rewritten, chArgs, aggWarnings, err := b.aggExprRewriter.Rewrite(
|
||||
ctx, orgID, start, end, aggExpr.Expression,
|
||||
rateInterval,
|
||||
keys,
|
||||
@@ -784,6 +792,7 @@ func (b *traceQueryStatementBuilder) buildScalarQuery(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, aggWarnings...)
|
||||
allAggChArgs = append(allAggChArgs, chArgs...)
|
||||
sb.SelectMore(fmt.Sprintf("%s AS __result_%d", rewritten, idx))
|
||||
}
|
||||
@@ -845,7 +854,7 @@ func (b *traceQueryStatementBuilder) buildScalarQuery(
|
||||
stmt := &qbtypes.Statement{
|
||||
Query: finalSQL,
|
||||
Args: finalArgs,
|
||||
Warnings: preparedWhereClause.Warnings,
|
||||
Warnings: querybuilder.AppendWarnings(preparedWhereClause.Warnings, columnWarnings...),
|
||||
WarningsDocURL: preparedWhereClause.WarningsDocURL,
|
||||
}
|
||||
|
||||
|
||||
@@ -756,8 +756,9 @@ func TestStatementBuilderListQuery(t *testing.T) {
|
||||
Limit: 10,
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "WITH __resource_filter AS (SELECT fingerprint FROM signoz_traces.distributed_traces_v3_resource WHERE (simpleJSONExtractString(labels, 'service.name') = ? AND labels LIKE ? AND labels LIKE ?) AND seen_at_ts_bucket_start >= ? AND seen_at_ts_bucket_start <= ? GROUP BY fingerprint) SELECT timestamp AS `__SELECT_KEY_0_timestamp`, trace_id AS `__SELECT_KEY_1_trace_id`, span_id AS `__SELECT_KEY_2_span_id`, name AS `__SELECT_KEY_3_name`, resource_string_service$$name AS `__SELECT_KEY_4_serviceName`, duration_nano AS `__SELECT_KEY_5_durationNano`, http_method AS `__SELECT_KEY_6_httpMethod`, multiIf(mapContains(attributes_string, 'non-existent.key'), attributes_string['non-existent.key'], mapContains(attributes_number, 'non-existent.key'), toString(attributes_number['non-existent.key']), mapContains(attributes_bool, 'non-existent.key'), toString(attributes_bool['non-existent.key']), NULL) AS `__SELECT_KEY_7_non-existent.key` FROM signoz_traces.distributed_signoz_index_v3 WHERE resource_fingerprint GLOBAL IN (SELECT fingerprint FROM __resource_filter) AND timestamp >= ? AND timestamp < ? AND ts_bucket_start >= ? AND ts_bucket_start <= ? LIMIT ?",
|
||||
Args: []any{"redis-manual", "%service.name%", "%service.name\":\"redis-manual%", uint64(1747945619), uint64(1747983448), "1747947419000000000", "1747983448000000000", uint64(1747945619), uint64(1747983448), 10},
|
||||
Query: "WITH __resource_filter AS (SELECT fingerprint FROM signoz_traces.distributed_traces_v3_resource WHERE (simpleJSONExtractString(labels, 'service.name') = ? AND labels LIKE ? AND labels LIKE ?) AND seen_at_ts_bucket_start >= ? AND seen_at_ts_bucket_start <= ? GROUP BY fingerprint) SELECT timestamp AS `__SELECT_KEY_0_timestamp`, trace_id AS `__SELECT_KEY_1_trace_id`, span_id AS `__SELECT_KEY_2_span_id`, name AS `__SELECT_KEY_3_name`, resource_string_service$$name AS `__SELECT_KEY_4_serviceName`, duration_nano AS `__SELECT_KEY_5_durationNano`, http_method AS `__SELECT_KEY_6_httpMethod`, multiIf(mapContains(attributes_string, 'non-existent.key'), attributes_string['non-existent.key'], mapContains(attributes_number, 'non-existent.key'), toString(attributes_number['non-existent.key']), mapContains(attributes_bool, 'non-existent.key'), toString(attributes_bool['non-existent.key']), NULL) AS `__SELECT_KEY_7_non-existent.key` FROM signoz_traces.distributed_signoz_index_v3 WHERE resource_fingerprint GLOBAL IN (SELECT fingerprint FROM __resource_filter) AND timestamp >= ? AND timestamp < ? AND ts_bucket_start >= ? AND ts_bucket_start <= ? LIMIT ?",
|
||||
Args: []any{"redis-manual", "%service.name%", "%service.name\":\"redis-manual%", uint64(1747945619), uint64(1747983448), "1747947419000000000", "1747983448000000000", uint64(1747945619), uint64(1747983448), 10},
|
||||
Warnings: []string{querybuilder.NewKeyNotFoundWarning("non-existent.key")},
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
@@ -926,8 +927,9 @@ func TestStatementBuilderListQueryWithCorruptData(t *testing.T) {
|
||||
Limit: 10,
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "SELECT timestamp AS `__SELECT_KEY_0_timestamp`, trace_id AS `__SELECT_KEY_1_trace_id`, span_id AS `__SELECT_KEY_2_span_id`, multiIf(scope.version::String <> '', scope.version::String, NULL) AS `__SELECT_KEY_3_scope.version` FROM signoz_traces.distributed_signoz_index_v3 WHERE timestamp >= ? AND timestamp < ? AND ts_bucket_start >= ? AND ts_bucket_start <= ? LIMIT ?",
|
||||
Args: []any{"1747947419000000000", "1747983448000000000", uint64(1747945619), uint64(1747983448), 10},
|
||||
Query: "SELECT timestamp AS `__SELECT_KEY_0_timestamp`, trace_id AS `__SELECT_KEY_1_trace_id`, span_id AS `__SELECT_KEY_2_span_id`, multiIf(scope.version::String <> '', scope.version::String, NULL) AS `__SELECT_KEY_3_scope.version` FROM signoz_traces.distributed_signoz_index_v3 WHERE timestamp >= ? AND timestamp < ? AND ts_bucket_start >= ? AND ts_bucket_start <= ? LIMIT ?",
|
||||
Args: []any{"1747947419000000000", "1747983448000000000", uint64(1747945619), uint64(1747983448), 10},
|
||||
Warnings: []string{querybuilder.NewKeyNotFoundWarning("scope.version")},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1017,8 +1019,9 @@ func TestStatementBuilderListQueryWithCorruptData(t *testing.T) {
|
||||
Limit: 10,
|
||||
},
|
||||
expected: qbtypes.Statement{
|
||||
Query: "SELECT timestamp AS `__SELECT_KEY_0_timestamp`, trace_id AS `__SELECT_KEY_1_trace_id`, span_id AS `__SELECT_KEY_2_span_id`, multiIf(scope.name::String <> '', scope.name::String, NULL) AS `__SELECT_KEY_3_scope.name` FROM signoz_traces.distributed_signoz_index_v3 WHERE timestamp >= ? AND timestamp < ? AND ts_bucket_start >= ? AND ts_bucket_start <= ? LIMIT ?",
|
||||
Args: []any{"1747947419000000000", "1747983448000000000", uint64(1747945619), uint64(1747983448), 10},
|
||||
Query: "SELECT timestamp AS `__SELECT_KEY_0_timestamp`, trace_id AS `__SELECT_KEY_1_trace_id`, span_id AS `__SELECT_KEY_2_span_id`, multiIf(scope.name::String <> '', scope.name::String, NULL) AS `__SELECT_KEY_3_scope.name` FROM signoz_traces.distributed_signoz_index_v3 WHERE timestamp >= ? AND timestamp < ? AND ts_bucket_start >= ? AND ts_bucket_start <= ? LIMIT ?",
|
||||
Args: []any{"1747947419000000000", "1747983448000000000", uint64(1747945619), uint64(1747983448), 10},
|
||||
Warnings: []string{querybuilder.NewKeyNotFoundWarning("scope.name")},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -462,6 +462,7 @@ func (b *traceOperatorCTEBuilder) buildFinalQuery(ctx context.Context, selectFro
|
||||
}
|
||||
|
||||
func (b *traceOperatorCTEBuilder) buildListQuery(ctx context.Context, selectFromCTE string, keys map[string][]*telemetrytypes.TelemetryFieldKey, isSelectFieldsEmpty bool) (*qbtypes.Statement, error) {
|
||||
var columnWarnings []string
|
||||
sb := sqlbuilder.NewSelectBuilder()
|
||||
|
||||
// Select core fields. These are always present so the trace operator
|
||||
@@ -490,12 +491,13 @@ func (b *traceOperatorCTEBuilder) buildListQuery(ctx context.Context, selectFrom
|
||||
if selectedFields[field.Name] {
|
||||
continue
|
||||
}
|
||||
expr, err := querybuilder.ResolveColumn(ctx, info, b.stmtBuilder.storage, &field, telemetrytypes.FieldDataTypeUnspecified, keys)
|
||||
expr, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.stmtBuilder.storage, &field, telemetrytypes.FieldDataTypeUnspecified, keys)
|
||||
if err != nil {
|
||||
b.stmtBuilder.logger.WarnContext(ctx, "failed to map select field",
|
||||
slog.String("field", field.Name), errors.Attr(err))
|
||||
continue
|
||||
}
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
sb.SelectMore(sqlbuilder.Escape(fmt.Sprintf("%s AS %s", expr, selectColumnAlias(i, field.Name))))
|
||||
selectedFields[field.Name] = true
|
||||
}
|
||||
@@ -511,10 +513,11 @@ func (b *traceOperatorCTEBuilder) buildListQuery(ctx context.Context, selectFrom
|
||||
// Add order by support
|
||||
orderApplied := false
|
||||
for _, orderBy := range b.operator.Order {
|
||||
expr, err := querybuilder.ResolveColumn(ctx, info, b.stmtBuilder.storage, &orderBy.Key.TelemetryFieldKey, telemetrytypes.FieldDataTypeUnspecified, keys)
|
||||
expr, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.stmtBuilder.storage, &orderBy.Key.TelemetryFieldKey, telemetrytypes.FieldDataTypeUnspecified, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
sb.OrderBy(fmt.Sprintf("%s %s", sqlbuilder.Escape(expr), orderBy.Direction.StringValue()))
|
||||
orderApplied = true
|
||||
}
|
||||
@@ -535,8 +538,9 @@ func (b *traceOperatorCTEBuilder) buildListQuery(ctx context.Context, selectFrom
|
||||
|
||||
sql, args := sb.BuildWithFlavor(sqlbuilder.ClickHouse)
|
||||
return &qbtypes.Statement{
|
||||
Query: sql,
|
||||
Args: args,
|
||||
Query: sql,
|
||||
Args: args,
|
||||
Warnings: querybuilder.AppendWarnings(nil, columnWarnings...),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -622,6 +626,7 @@ func (b *traceOperatorCTEBuilder) getKeySelectors() []*telemetrytypes.FieldKeySe
|
||||
}
|
||||
|
||||
func (b *traceOperatorCTEBuilder) buildTimeSeriesQuery(ctx context.Context, selectFromCTE string, keys map[string][]*telemetrytypes.TelemetryFieldKey) (*qbtypes.Statement, error) {
|
||||
var columnWarnings []string
|
||||
sb := sqlbuilder.NewSelectBuilder()
|
||||
|
||||
sb.Select(fmt.Sprintf(
|
||||
@@ -631,7 +636,7 @@ func (b *traceOperatorCTEBuilder) buildTimeSeriesQuery(ctx context.Context, sele
|
||||
|
||||
info := querybuilder.NewQueryInfo(ctx, b.orgID, b.stmtBuilder.fl, telemetrytypes.SignalTraces, nil, b.start, b.end)
|
||||
for _, gb := range b.operator.GroupBy {
|
||||
expr, err := querybuilder.ResolveColumn(ctx, info, b.stmtBuilder.storage, &gb.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
expr, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.stmtBuilder.storage, &gb.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
if err != nil {
|
||||
return nil, errors.NewInvalidInputf(
|
||||
errors.CodeInvalidInput,
|
||||
@@ -640,12 +645,13 @@ func (b *traceOperatorCTEBuilder) buildTimeSeriesQuery(ctx context.Context, sele
|
||||
err,
|
||||
)
|
||||
}
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
sb.SelectMore(sqlbuilder.Escape(fmt.Sprintf("toString(%s) AS %s", expr, clickhousesql.Identifier(gb.Name))))
|
||||
}
|
||||
|
||||
var allAggChArgs []any
|
||||
for i, agg := range b.operator.Aggregations {
|
||||
rewritten, chArgs, err := b.stmtBuilder.aggExprRewriter.Rewrite(
|
||||
rewritten, chArgs, aggWarnings, err := b.stmtBuilder.aggExprRewriter.Rewrite(
|
||||
ctx,
|
||||
b.orgID,
|
||||
b.start,
|
||||
@@ -662,6 +668,7 @@ func (b *traceOperatorCTEBuilder) buildTimeSeriesQuery(ctx context.Context, sele
|
||||
err,
|
||||
)
|
||||
}
|
||||
columnWarnings = append(columnWarnings, aggWarnings...)
|
||||
allAggChArgs = append(allAggChArgs, chArgs...)
|
||||
|
||||
alias := fmt.Sprintf("__result_%d", i)
|
||||
@@ -700,8 +707,9 @@ func (b *traceOperatorCTEBuilder) buildTimeSeriesQuery(ctx context.Context, sele
|
||||
|
||||
sql, args := sb.BuildWithFlavor(sqlbuilder.ClickHouse, combinedArgs...)
|
||||
return &qbtypes.Statement{
|
||||
Query: sql,
|
||||
Args: args,
|
||||
Query: sql,
|
||||
Args: args,
|
||||
Warnings: querybuilder.AppendWarnings(nil, columnWarnings...),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -722,13 +730,14 @@ func (b *traceOperatorCTEBuilder) buildTraceSummaryCTE(selectFromCTE string) {
|
||||
}
|
||||
|
||||
func (b *traceOperatorCTEBuilder) buildTraceQuery(ctx context.Context, selectFromCTE string, keys map[string][]*telemetrytypes.TelemetryFieldKey) (*qbtypes.Statement, error) {
|
||||
var columnWarnings []string
|
||||
b.buildTraceSummaryCTE(selectFromCTE)
|
||||
|
||||
sb := sqlbuilder.NewSelectBuilder()
|
||||
|
||||
info := querybuilder.NewQueryInfo(ctx, b.orgID, b.stmtBuilder.fl, telemetrytypes.SignalTraces, nil, b.start, b.end)
|
||||
for _, gb := range b.operator.GroupBy {
|
||||
expr, err := querybuilder.ResolveColumn(ctx, info, b.stmtBuilder.storage, &gb.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
expr, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.stmtBuilder.storage, &gb.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
if err != nil {
|
||||
return nil, errors.NewInvalidInputf(
|
||||
errors.CodeInvalidInput,
|
||||
@@ -737,6 +746,7 @@ func (b *traceOperatorCTEBuilder) buildTraceQuery(ctx context.Context, selectFro
|
||||
err,
|
||||
)
|
||||
}
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
sb.SelectMore(sqlbuilder.Escape(fmt.Sprintf("toString(%s) AS %s", expr, clickhousesql.Identifier(gb.Name))))
|
||||
}
|
||||
|
||||
@@ -744,7 +754,7 @@ func (b *traceOperatorCTEBuilder) buildTraceQuery(ctx context.Context, selectFro
|
||||
|
||||
var allAggChArgs []any
|
||||
for i, agg := range b.operator.Aggregations {
|
||||
rewritten, chArgs, err := b.stmtBuilder.aggExprRewriter.Rewrite(
|
||||
rewritten, chArgs, aggWarnings, err := b.stmtBuilder.aggExprRewriter.Rewrite(
|
||||
ctx,
|
||||
b.orgID,
|
||||
b.start,
|
||||
@@ -761,6 +771,7 @@ func (b *traceOperatorCTEBuilder) buildTraceQuery(ctx context.Context, selectFro
|
||||
err,
|
||||
)
|
||||
}
|
||||
columnWarnings = append(columnWarnings, aggWarnings...)
|
||||
allAggChArgs = append(allAggChArgs, chArgs...)
|
||||
|
||||
alias := fmt.Sprintf("__result_%d", i)
|
||||
@@ -845,17 +856,19 @@ func (b *traceOperatorCTEBuilder) buildTraceQuery(ctx context.Context, selectFro
|
||||
|
||||
sql, args := sb.BuildWithFlavor(sqlbuilder.ClickHouse, combinedArgs...)
|
||||
return &qbtypes.Statement{
|
||||
Query: sql,
|
||||
Args: args,
|
||||
Query: sql,
|
||||
Args: args,
|
||||
Warnings: querybuilder.AppendWarnings(nil, columnWarnings...),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (b *traceOperatorCTEBuilder) buildScalarQuery(ctx context.Context, selectFromCTE string, keys map[string][]*telemetrytypes.TelemetryFieldKey) (*qbtypes.Statement, error) {
|
||||
var columnWarnings []string
|
||||
sb := sqlbuilder.NewSelectBuilder()
|
||||
|
||||
info := querybuilder.NewQueryInfo(ctx, b.orgID, b.stmtBuilder.fl, telemetrytypes.SignalTraces, nil, b.start, b.end)
|
||||
for _, gb := range b.operator.GroupBy {
|
||||
expr, err := querybuilder.ResolveColumn(ctx, info, b.stmtBuilder.storage, &gb.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
expr, keyWarnings, err := querybuilder.ResolveColumn(ctx, info, b.stmtBuilder.storage, &gb.TelemetryFieldKey, telemetrytypes.FieldDataTypeString, keys)
|
||||
if err != nil {
|
||||
return nil, errors.NewInvalidInputf(
|
||||
errors.CodeInvalidInput,
|
||||
@@ -864,12 +877,13 @@ func (b *traceOperatorCTEBuilder) buildScalarQuery(ctx context.Context, selectFr
|
||||
err,
|
||||
)
|
||||
}
|
||||
columnWarnings = append(columnWarnings, keyWarnings...)
|
||||
sb.SelectMore(sqlbuilder.Escape(fmt.Sprintf("toString(%s) AS %s", expr, clickhousesql.Identifier(gb.Name))))
|
||||
}
|
||||
|
||||
var allAggChArgs []any
|
||||
for i, agg := range b.operator.Aggregations {
|
||||
rewritten, chArgs, err := b.stmtBuilder.aggExprRewriter.Rewrite(
|
||||
rewritten, chArgs, aggWarnings, err := b.stmtBuilder.aggExprRewriter.Rewrite(
|
||||
ctx,
|
||||
b.orgID,
|
||||
b.start,
|
||||
@@ -886,6 +900,7 @@ func (b *traceOperatorCTEBuilder) buildScalarQuery(ctx context.Context, selectFr
|
||||
err,
|
||||
)
|
||||
}
|
||||
columnWarnings = append(columnWarnings, aggWarnings...)
|
||||
allAggChArgs = append(allAggChArgs, chArgs...)
|
||||
|
||||
alias := fmt.Sprintf("__result_%d", i)
|
||||
@@ -931,8 +946,9 @@ func (b *traceOperatorCTEBuilder) buildScalarQuery(ctx context.Context, selectFr
|
||||
|
||||
sql, args := sb.BuildWithFlavor(sqlbuilder.ClickHouse, combinedArgs...)
|
||||
return &qbtypes.Statement{
|
||||
Query: sql,
|
||||
Args: args,
|
||||
Query: sql,
|
||||
Args: args,
|
||||
Warnings: querybuilder.AppendWarnings(nil, columnWarnings...),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -782,7 +782,7 @@ func TestIntrinsicColumnFirst(t *testing.T) {
|
||||
|
||||
t.Run("declared scope path selects without a literal spelling", func(t *testing.T) {
|
||||
key := telemetrytypes.TelemetryFieldKey{Name: "scope.version", FieldContext: telemetrytypes.FieldContextScope}
|
||||
expr, err := querybuilder.ResolveColumn(ctx, q, storage, &key, telemetrytypes.FieldDataTypeUnspecified, map[string][]*telemetrytypes.TelemetryFieldKey{})
|
||||
expr, _, err := querybuilder.ResolveColumn(ctx, q, storage, &key, telemetrytypes.FieldDataTypeUnspecified, map[string][]*telemetrytypes.TelemetryFieldKey{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "multiIf(scope.version::String <> '', scope.version::String, NULL)", expr)
|
||||
})
|
||||
|
||||
@@ -228,7 +228,7 @@ func TestColumnExpressionForFamilyGroupBy(t *testing.T) {
|
||||
fl := familyFlagOn(t)
|
||||
storage := NewStorage(nil)
|
||||
|
||||
expr, err := querybuilder.ResolveColumn(context.Background(), querybuilder.NewQueryInfo(context.Background(), valuer.UUID{}, fl, telemetrytypes.SignalTraces, nil, startNs, endNs), storage, &telemetrytypes.TelemetryFieldKey{Name: "deployment.environment.name"}, telemetrytypes.FieldDataTypeString, fieldKeys)
|
||||
expr, _, err := querybuilder.ResolveColumn(context.Background(), querybuilder.NewQueryInfo(context.Background(), valuer.UUID{}, fl, telemetrytypes.SignalTraces, nil, startNs, endNs), storage, &telemetrytypes.TelemetryFieldKey{Name: "deployment.environment.name"}, telemetrytypes.FieldDataTypeString, fieldKeys)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "multiIf((multiIf(resource.`deployment.environment.name` IS NOT NULL, resource.`deployment.environment.name`::String, mapContains(resources_string, 'deployment.environment.name'), resources_string['deployment.environment.name'], NULL) IS NOT NULL OR multiIf(resource.`deployment.environment` IS NOT NULL, resource.`deployment.environment`::String, mapContains(resources_string, 'deployment.environment'), resources_string['deployment.environment'], NULL) IS NOT NULL), COALESCE(NULLIF(multiIf(resource.`deployment.environment.name` IS NOT NULL, resource.`deployment.environment.name`::String, mapContains(resources_string, 'deployment.environment.name'), resources_string['deployment.environment.name'], NULL), ''), NULLIF(multiIf(resource.`deployment.environment` IS NOT NULL, resource.`deployment.environment`::String, mapContains(resources_string, 'deployment.environment'), resources_string['deployment.environment'], NULL), ''), ''), NULL)", expr)
|
||||
}
|
||||
|
||||
@@ -288,14 +288,14 @@ func TestColumnExpressionForAttributeJSON(t *testing.T) {
|
||||
|
||||
t.Run("group by string", func(t *testing.T) {
|
||||
key := attrKey("user.id", telemetrytypes.FieldDataTypeString, evo)
|
||||
got, err := querybuilder.ResolveColumn(ctx, qbtypes.QueryInfo{StartNs: attrWindowAfter[0], EndNs: attrWindowAfter[1], TraceAttrsJSONOn: true}, storage, &key, telemetrytypes.FieldDataTypeString, nil)
|
||||
got, _, err := querybuilder.ResolveColumn(ctx, qbtypes.QueryInfo{StartNs: attrWindowAfter[0], EndNs: attrWindowAfter[1], TraceAttrsJSONOn: true}, storage, &key, telemetrytypes.FieldDataTypeString, nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "multiIf(attributes.`user.id` IS NOT NULL, attributes.`user.id`::String, mapContains(attributes_string, 'attribute.user.id'), attributes_string['attribute.user.id'], NULL)", got)
|
||||
})
|
||||
|
||||
t.Run("aggregation numeric", func(t *testing.T) {
|
||||
key := attrKey("latency", telemetrytypes.FieldDataTypeNumber, evo)
|
||||
got, err := querybuilder.ResolveColumn(ctx, qbtypes.QueryInfo{StartNs: attrWindowAfter[0], EndNs: attrWindowAfter[1], TraceAttrsJSONOn: true}, storage, &key, telemetrytypes.FieldDataTypeFloat64, nil)
|
||||
got, _, err := querybuilder.ResolveColumn(ctx, qbtypes.QueryInfo{StartNs: attrWindowAfter[0], EndNs: attrWindowAfter[1], TraceAttrsJSONOn: true}, storage, &key, telemetrytypes.FieldDataTypeFloat64, nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "multiIf(toFloat64OrNull(attributes.`latency`::String) IS NOT NULL, toFloat64OrNull(attributes.`latency`::String), mapContains(attributes_number, 'attribute.latency'), toFloat64(attributes_number['attribute.latency']), NULL)", got)
|
||||
})
|
||||
@@ -362,7 +362,7 @@ func TestColumnExpressionForAttributeJSONTypeCollision(t *testing.T) {
|
||||
}
|
||||
|
||||
ref := attrKey("http.status_code", telemetrytypes.FieldDataTypeUnspecified, nil)
|
||||
got, err := querybuilder.ResolveColumn(ctx, qbtypes.QueryInfo{StartNs: attrWindowAfter[0], EndNs: attrWindowAfter[1], TraceAttrsJSONOn: true}, storage, &ref, telemetrytypes.FieldDataTypeString, fieldKeys)
|
||||
got, _, err := querybuilder.ResolveColumn(ctx, qbtypes.QueryInfo{StartNs: attrWindowAfter[0], EndNs: attrWindowAfter[1], TraceAttrsJSONOn: true}, storage, &ref, telemetrytypes.FieldDataTypeString, fieldKeys)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t,
|
||||
"multiIf(attributes.`http.status_code` IS NOT NULL, attributes.`http.status_code`::String, toFloat64OrNull(attributes.`http.status_code`::String) IS NOT NULL, toString(toFloat64OrNull(attributes.`http.status_code`::String)), NULL)",
|
||||
@@ -386,7 +386,7 @@ func TestColumnExpressionForAttributeJSONTypeCollisionNumericAgg(t *testing.T) {
|
||||
}
|
||||
|
||||
ref := attrKey("http.status_code", telemetrytypes.FieldDataTypeUnspecified, nil)
|
||||
got, err := querybuilder.ResolveColumn(ctx, qbtypes.QueryInfo{StartNs: attrWindowAfter[0], EndNs: attrWindowAfter[1], TraceAttrsJSONOn: true}, storage, &ref, telemetrytypes.FieldDataTypeFloat64, fieldKeys)
|
||||
got, _, err := querybuilder.ResolveColumn(ctx, qbtypes.QueryInfo{StartNs: attrWindowAfter[0], EndNs: attrWindowAfter[1], TraceAttrsJSONOn: true}, storage, &ref, telemetrytypes.FieldDataTypeFloat64, fieldKeys)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t,
|
||||
"multiIf(toFloat64OrNull(attributes.`http.status_code`::String) IS NOT NULL, toFloat64OrNull(attributes.`http.status_code`::String), attributes.`http.status_code` IS NOT NULL, toFloat64OrNull(attributes.`http.status_code`::String), NULL)",
|
||||
|
||||
@@ -295,7 +295,7 @@ func TestColumnExpressionForTemporalColumn(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
storage := NewStorage(nil)
|
||||
result, err := querybuilder.ResolveColumn(ctx, qbtypes.QueryInfo{StartNs: tsStart, EndNs: tsEnd}, storage, &tc.key, tc.requiredDataType, nil)
|
||||
result, _, err := querybuilder.ResolveColumn(ctx, qbtypes.QueryInfo{StartNs: tsStart, EndNs: tsEnd}, storage, &tc.key, tc.requiredDataType, nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.expectedResult, result)
|
||||
})
|
||||
@@ -326,7 +326,7 @@ func TestColumnExpressionForTimestampAttributeCollision(t *testing.T) {
|
||||
|
||||
t.Run("bare timestamp resolves to the intrinsic column alone", func(t *testing.T) {
|
||||
bare := telemetrytypes.TelemetryFieldKey{Name: "timestamp"}
|
||||
result, err := querybuilder.ResolveColumn(ctx, qbtypes.QueryInfo{StartNs: tsStart, EndNs: tsEnd}, storage, &bare, telemetrytypes.FieldDataTypeFloat64, keys)
|
||||
result, _, err := querybuilder.ResolveColumn(ctx, qbtypes.QueryInfo{StartNs: tsStart, EndNs: tsEnd}, storage, &bare, telemetrytypes.FieldDataTypeFloat64, keys)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "timestamp", result)
|
||||
})
|
||||
@@ -337,7 +337,7 @@ func TestColumnExpressionForTimestampAttributeCollision(t *testing.T) {
|
||||
FieldContext: telemetrytypes.FieldContextAttribute,
|
||||
FieldDataType: telemetrytypes.FieldDataTypeNumber,
|
||||
}
|
||||
result, err := querybuilder.ResolveColumn(ctx, qbtypes.QueryInfo{StartNs: tsStart, EndNs: tsEnd}, storage, &attr, telemetrytypes.FieldDataTypeFloat64, keys)
|
||||
result, _, err := querybuilder.ResolveColumn(ctx, qbtypes.QueryInfo{StartNs: tsStart, EndNs: tsEnd}, storage, &attr, telemetrytypes.FieldDataTypeFloat64, keys)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result, "attributes_number['timestamp']")
|
||||
})
|
||||
@@ -432,7 +432,7 @@ func TestColumnExpressionForScopeDeclaredPath(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
storage := NewStorage(nil)
|
||||
result, err := querybuilder.ResolveColumn(ctx, qbtypes.QueryInfo{}, storage, &tc.key, telemetrytypes.FieldDataTypeUnspecified, tc.keys)
|
||||
result, _, err := querybuilder.ResolveColumn(ctx, qbtypes.QueryInfo{}, storage, &tc.key, telemetrytypes.FieldDataTypeUnspecified, tc.keys)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.expectedResult, result)
|
||||
})
|
||||
|
||||
@@ -214,8 +214,8 @@ type Resolved struct {
|
||||
|
||||
type AggExprRewriter interface {
|
||||
// Rewrite rewrites the aggregation expression to be used in the query.
|
||||
Rewrite(ctx context.Context, orgID valuer.UUID, startNs, endNs uint64, expr string, rateInterval uint64, keys map[string][]*telemetrytypes.TelemetryFieldKey) (string, []any, error)
|
||||
RewriteMulti(ctx context.Context, orgID valuer.UUID, startNs, endNs uint64, exprs []string, rateInterval uint64, keys map[string][]*telemetrytypes.TelemetryFieldKey) ([]string, [][]any, error)
|
||||
Rewrite(ctx context.Context, orgID valuer.UUID, startNs, endNs uint64, expr string, rateInterval uint64, keys map[string][]*telemetrytypes.TelemetryFieldKey) (string, []any, []string, error)
|
||||
RewriteMulti(ctx context.Context, orgID valuer.UUID, startNs, endNs uint64, exprs []string, rateInterval uint64, keys map[string][]*telemetrytypes.TelemetryFieldKey) ([]string, [][]any, []string, error)
|
||||
}
|
||||
|
||||
type Statement struct {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
from collections.abc import Callable
|
||||
from datetime import UTC, datetime, timedelta
|
||||
from http import HTTPStatus
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from fixtures import types
|
||||
from fixtures.auth import USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD
|
||||
@@ -10,10 +13,15 @@ from fixtures.querier import (
|
||||
Aggregation,
|
||||
BuilderQuery,
|
||||
MetricAggregation,
|
||||
OrderBy,
|
||||
RequestType,
|
||||
TelemetryFieldKey,
|
||||
get_all_warnings,
|
||||
make_query_request,
|
||||
)
|
||||
|
||||
ORG_ID_NOT_FOUND = "key `orgId` not found in metadata; querying the underlying data directly. If this is unexpected, check the key name for typos."
|
||||
|
||||
|
||||
def test_resource_default_warning(
|
||||
signoz: types.SigNoz,
|
||||
@@ -384,3 +392,45 @@ def test_no_warnings_for_meter_query(
|
||||
assert response.status_code == HTTPStatus.OK
|
||||
assert response.json()["status"] == "success"
|
||||
assert "warning" not in response.json()["data"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"request_type,query_args,expected_warnings",
|
||||
[
|
||||
pytest.param(RequestType.RAW, {"select_fields": [TelemetryFieldKey(name="orgId")]}, [ORG_ID_NOT_FOUND], id="select_field"),
|
||||
pytest.param(RequestType.RAW, {"order": [OrderBy(key=TelemetryFieldKey(name="orgId"))]}, [ORG_ID_NOT_FOUND], id="order_by"),
|
||||
pytest.param(RequestType.SCALAR, {"aggregations": [Aggregation(expression="count_distinct(orgId)")]}, [ORG_ID_NOT_FOUND], id="aggregation_argument"),
|
||||
pytest.param(RequestType.SCALAR, {"aggregations": [Aggregation(expression="countIf(orgId = 'acme')")]}, [ORG_ID_NOT_FOUND], id="aggregation_predicate"),
|
||||
pytest.param(
|
||||
RequestType.SCALAR,
|
||||
{"aggregations": [Aggregation(expression="count()")], "group_by": [TelemetryFieldKey(name="orgId")], "filter_expression": "orgId = 'acme'"},
|
||||
[ORG_ID_NOT_FOUND],
|
||||
id="filter_and_group_by",
|
||||
),
|
||||
pytest.param(RequestType.SCALAR, {"aggregations": [Aggregation(expression="count()")], "group_by": [TelemetryFieldKey(name="service.name")]}, [], id="known_key"),
|
||||
],
|
||||
)
|
||||
def test_logs_unknown_key_outside_the_filter_warns(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: None, # pylint: disable=unused-argument
|
||||
get_token: Callable[[str, str], str],
|
||||
insert_logs: Callable[[list[Logs]], None],
|
||||
request_type: str,
|
||||
query_args: dict[str, Any],
|
||||
expected_warnings: list[str],
|
||||
) -> None:
|
||||
now = datetime.now(tz=UTC)
|
||||
insert_logs([Logs(timestamp=now - timedelta(seconds=1), resources={"service.name": "java"}, body="checkout failed for orgId=acme")])
|
||||
token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
response = make_query_request(
|
||||
signoz,
|
||||
token,
|
||||
start_ms=int((now - timedelta(minutes=5)).timestamp() * 1000),
|
||||
end_ms=int(now.timestamp() * 1000),
|
||||
request_type=request_type,
|
||||
queries=[BuilderQuery(name="A", signal="logs", **query_args).to_dict()],
|
||||
)
|
||||
|
||||
assert response.status_code == HTTPStatus.OK, response.text
|
||||
assert get_all_warnings(response.json()) == [{"message": message} for message in expected_warnings], response.text
|
||||
|
||||
@@ -10,8 +10,8 @@ from fixtures.traces import TraceIdGenerator, Traces, TracesKind, TracesStatusCo
|
||||
|
||||
# Unknown-key resolution in the scalar shape (group-by -> one value per bucket). Logs/traces
|
||||
# synthesize an unknown key (attribute maps + body). Observed here: the *filter* path emits a
|
||||
# key-not-found warning and matches nothing (count 0); the *group-by* path silently buckets
|
||||
# every record into a single NULL bucket and emits no warning.
|
||||
# key-not-found warning and matches nothing (count 0); the *group-by* path buckets every record
|
||||
# into a single NULL bucket and emits the same warning.
|
||||
UNKNOWN = "totally.unknown.key"
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ def test_logs_scalar_group_by_unknown_key_null_bucket(
|
||||
insert_logs: Callable[[list[Logs]], None],
|
||||
) -> None:
|
||||
"""Grouping a scalar count() by an unknown bare key synthesizes a NULL column: all records
|
||||
collapse into one bucket (200), and — unlike the filter path — no key-not-found warning."""
|
||||
collapse into one bucket (200), with the same key-not-found warning as the filter path."""
|
||||
now = datetime.now(tz=UTC).replace(second=0, microsecond=0)
|
||||
service = "scalar-unknown-gb-logs"
|
||||
insert_logs([Logs(timestamp=now - timedelta(seconds=i + 1), resources={"service.name": service}, body=f"log {i}") for i in range(4)])
|
||||
@@ -106,7 +106,7 @@ def test_logs_scalar_group_by_unknown_key_null_bucket(
|
||||
)
|
||||
assert response.status_code == HTTPStatus.OK, response.text
|
||||
messages = [w.get("message", "") for w in get_all_warnings(response.json())]
|
||||
assert not any(UNKNOWN in m for m in messages), messages
|
||||
assert any(UNKNOWN in m and "not found" in m for m in messages), messages
|
||||
data = get_scalar_table_data(response.json())
|
||||
assert len(data) == 1, data
|
||||
assert data[0][-1] == 4, data
|
||||
@@ -163,7 +163,7 @@ def test_traces_scalar_group_by_unknown_key_null_bucket(
|
||||
insert_traces: Callable[[list[Traces]], None],
|
||||
) -> None:
|
||||
"""Grouping a scalar count() by an unknown bare key synthesizes a NULL column: all spans
|
||||
collapse into one bucket (200), and — unlike the filter path — no key-not-found warning."""
|
||||
collapse into one bucket (200), with the same key-not-found warning as the filter path."""
|
||||
now = datetime.now(tz=UTC).replace(second=0, microsecond=0)
|
||||
service = "scalar-unknown-gb-traces"
|
||||
insert_traces(
|
||||
@@ -198,7 +198,7 @@ def test_traces_scalar_group_by_unknown_key_null_bucket(
|
||||
)
|
||||
assert response.status_code == HTTPStatus.OK, response.text
|
||||
messages = [w.get("message", "") for w in get_all_warnings(response.json())]
|
||||
assert not any(UNKNOWN in m for m in messages), messages
|
||||
assert any(UNKNOWN in m and "not found" in m for m in messages), messages
|
||||
data = get_scalar_table_data(response.json())
|
||||
assert len(data) == 1, data
|
||||
assert data[0][-1] == 4, data
|
||||
|
||||
Reference in New Issue
Block a user