mirror of
https://github.com/SigNoz/signoz.git
synced 2026-07-02 21:00:38 +01:00
fix: normalize telemetry field keys in query
This commit is contained in:
@@ -259,6 +259,7 @@ func (d *v1Decoder) mapV1SelectFields(w map[string]any) []telemetrytypes.Telemet
|
||||
if len(raw) == 0 {
|
||||
return nil
|
||||
}
|
||||
normalizePreV5FieldKeys(raw)
|
||||
fields, err := decodeTelemetryFields(raw)
|
||||
if err != nil {
|
||||
d.note("widget %q has malformed %s: %v", d.readString(w, "id"), field, err)
|
||||
|
||||
@@ -102,8 +102,8 @@ func (d *v1Decoder) collectV1QueryEnvelopes(widget map[string]any) ([]map[string
|
||||
var out []map[string]any
|
||||
var signal telemetrytypes.Signal
|
||||
for _, q := range d.readObjects(builder, "queryData") {
|
||||
normalizeV1Having(q)
|
||||
normalizeV1LogTraceAggregations(q)
|
||||
normalizePreV5Having(q)
|
||||
normalizePreV5LogTraceAggregations(q)
|
||||
name := d.readString(q, "queryName")
|
||||
out = append(out, qb.WrapInV5Envelope(name, q, string(qb.QueryTypeBuilder.StringValue())))
|
||||
if signal.IsZero() {
|
||||
@@ -111,12 +111,12 @@ func (d *v1Decoder) collectV1QueryEnvelopes(widget map[string]any) ([]map[string
|
||||
}
|
||||
}
|
||||
for _, f := range d.readObjects(builder, "queryFormulas") {
|
||||
normalizeV1Having(f)
|
||||
normalizePreV5Having(f)
|
||||
name := d.readString(f, "queryName")
|
||||
out = append(out, qb.WrapInV5Envelope(name, f, string(qb.QueryTypeFormula.StringValue())))
|
||||
}
|
||||
for _, op := range d.readObjects(builder, "queryTraceOperator") {
|
||||
normalizeV1Having(op)
|
||||
normalizePreV5Having(op)
|
||||
name := d.readString(op, "queryName")
|
||||
out = append(out, qb.WrapInV5Envelope(name, op, string(qb.QueryTypeTraceOperator.StringValue())))
|
||||
}
|
||||
|
||||
@@ -11,16 +11,16 @@ import (
|
||||
// Malformed-field normalization
|
||||
// ══════════════════════════════════════════════
|
||||
//
|
||||
// Reshape known-malformed v1 fields into their v5 form before decode. A common
|
||||
// case: a dashboard stamped version:"v5" whose bodies aren't actually v5-shaped
|
||||
// bypasses the v4→v5 migrator (pkg/transition) and then fails the strict v5
|
||||
// decode. These mirror the frontend, which normalizes by shape regardless of
|
||||
// the version tag.
|
||||
// Reshape known-malformed query-builder fields from their pre-v5 shape into the
|
||||
// v5 form before decode. A common case: a dashboard stamped version:"v5" whose
|
||||
// bodies aren't actually v5-shaped bypasses the v4→v5 migrator (pkg/transition)
|
||||
// and then fails the strict v5 decode. These mirror the frontend, which
|
||||
// normalizes by shape regardless of the version tag.
|
||||
//
|
||||
// Only reshape known field shapes here; leave genuinely corrupt input (e.g. an
|
||||
// empty required field) to fail validation rather than grow per-case fixups.
|
||||
|
||||
// normalizeV1Having rewrites a builder query's v4 having (an array of
|
||||
// normalizePreV5Having rewrites a builder query's v4 having (an array of
|
||||
// {columnName, op, value} clauses) into the v5 {"expression": ...} shape in
|
||||
// place. The v5 decoder wants an object, but a query can still carry the array
|
||||
// form — e.g. a dashboard stamped version:"v5" whose bodies predate v5, which
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
// convertHavingToExpression (QueryBuilderV2/utils.ts): each clause becomes
|
||||
// "columnName op value", clauses join with " AND ", array values render as
|
||||
// "[v1, v2]". A having that is already an object (or absent) is left untouched.
|
||||
func normalizeV1Having(query map[string]any) {
|
||||
func normalizePreV5Having(query map[string]any) {
|
||||
clauses, ok := query["having"].([]any)
|
||||
if !ok {
|
||||
return
|
||||
@@ -49,7 +49,7 @@ func normalizeV1Having(query map[string]any) {
|
||||
query["having"] = map[string]any{"expression": strings.Join(exprs, " AND ")}
|
||||
}
|
||||
|
||||
// normalizeV1LogTraceAggregations reshapes a logs/traces builder query's
|
||||
// normalizePreV5LogTraceAggregations reshapes a logs/traces builder query's
|
||||
// aggregations into the v5 {"expression", "alias"} form in place, dropping the
|
||||
// metric-only fields (metricName/temporality/timeAggregation/spaceAggregation/
|
||||
// reduceTo) that some dashboards carry on non-metric queries — a logs query
|
||||
@@ -59,7 +59,7 @@ func normalizeV1Having(query map[string]any) {
|
||||
// default an empty one to "count()". Metric queries are left untouched, since a
|
||||
// metric-shaped aggregation is correct for them. Idempotent on aggregations
|
||||
// that are already expression-only.
|
||||
func normalizeV1LogTraceAggregations(query map[string]any) {
|
||||
func normalizePreV5LogTraceAggregations(query map[string]any) {
|
||||
switch signalFromDataSource(query["dataSource"]) {
|
||||
case telemetrytypes.SignalLogs, telemetrytypes.SignalTraces:
|
||||
default:
|
||||
@@ -86,6 +86,33 @@ func normalizeV1LogTraceAggregations(query map[string]any) {
|
||||
}
|
||||
}
|
||||
|
||||
// normalizePreV5FieldKeys renames telemetry field keys from the pre-v5
|
||||
// query-builder shape ({key, dataType, type}) to the v5 one ({name,
|
||||
// fieldDataType, fieldContext}) in place — the same mapping WrapInV5Envelope
|
||||
// does for groupBy/orderBy. Without it an old-shape field decodes with an empty
|
||||
// name, which TelemetryFieldKey rejects. Entries already carrying "name" are
|
||||
// left as-is.
|
||||
func normalizePreV5FieldKeys(fields []any) {
|
||||
for _, f := range fields {
|
||||
field, ok := f.(map[string]any)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if _, hasName := field["name"]; hasName {
|
||||
continue
|
||||
}
|
||||
if key, ok := field["key"]; ok {
|
||||
field["name"] = key
|
||||
}
|
||||
if dataType, ok := field["dataType"]; ok {
|
||||
field["fieldDataType"] = dataType
|
||||
}
|
||||
if typ, ok := field["type"]; ok {
|
||||
field["fieldContext"] = typ
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// formatHavingValue renders a having clause value: an array as "[v1, v2]", any
|
||||
// scalar as its default string form.
|
||||
func formatHavingValue(value any) string {
|
||||
Reference in New Issue
Block a user