From 2771d2e77429a1f78a7323e957a4076201393a11 Mon Sep 17 00:00:00 2001 From: Amol Umbark Date: Sun, 27 Nov 2022 00:59:09 -0800 Subject: [PATCH] fix: [alerts] [ch-query] added aliases in metric query result (#1760) * fix: [alerts] [ch-query] added aliases in metric query result * fix: added more column type support for target in ch query * fix: added error handling when data type is unexpected in metric result Co-authored-by: Pranay Prateek --- ee/query-service/app/db/metrics.go | 27 ++++++++++++ .../app/clickhouseReader/reader.go | 26 ++++++++++++ pkg/query-service/constants/constants.go | 5 +++ pkg/query-service/rules/thresholdRule.go | 41 +++++++++++++------ 4 files changed, 86 insertions(+), 13 deletions(-) diff --git a/ee/query-service/app/db/metrics.go b/ee/query-service/app/db/metrics.go index 77e7d50c9b..3bafc6a638 100644 --- a/ee/query-service/app/db/metrics.go +++ b/ee/query-service/app/db/metrics.go @@ -12,6 +12,7 @@ import ( "time" "go.signoz.io/signoz/ee/query-service/model" + baseconst "go.signoz.io/signoz/pkg/query-service/constants" basemodel "go.signoz.io/signoz/pkg/query-service/model" "go.signoz.io/signoz/pkg/query-service/utils" "go.uber.org/zap" @@ -91,6 +92,32 @@ func (r *ClickhouseReader) GetMetricResultEE(ctx context.Context, query string) metricPoint.Timestamp = v.UnixMilli() case *float64: metricPoint.Value = *v + case **float64: + // ch seems to return this type when column is derived from + // SELECT count(*)/ SELECT count(*) + floatVal := *v + if floatVal != nil { + metricPoint.Value = *floatVal + } + case *float32: + float32Val := float32(*v) + metricPoint.Value = float64(float32Val) + case *uint8, *uint64, *uint16, *uint32: + if _, ok := baseconst.ReservedColumnTargetAliases[colName]; ok { + metricPoint.Value = float64(reflect.ValueOf(v).Elem().Uint()) + } else { + groupBy = append(groupBy, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Uint())) + groupAttributes[colName] = fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Uint()) + } + case *int8, *int16, *int32, *int64: + if _, ok := baseconst.ReservedColumnTargetAliases[colName]; ok { + metricPoint.Value = float64(reflect.ValueOf(v).Elem().Int()) + } else { + groupBy = append(groupBy, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Int())) + groupAttributes[colName] = fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Int()) + } + default: + zap.S().Errorf("invalid var found in metric builder query result", v, colName) } } sort.Strings(groupBy) diff --git a/pkg/query-service/app/clickhouseReader/reader.go b/pkg/query-service/app/clickhouseReader/reader.go index 0ccb5cb73c..49c728c5f0 100644 --- a/pkg/query-service/app/clickhouseReader/reader.go +++ b/pkg/query-service/app/clickhouseReader/reader.go @@ -2916,6 +2916,32 @@ func (r *ClickHouseReader) GetMetricResult(ctx context.Context, query string) ([ metricPoint.Timestamp = v.UnixMilli() case *float64: metricPoint.Value = *v + case **float64: + // ch seems to return this type when column is derived from + // SELECT count(*)/ SELECT count(*) + floatVal := *v + if floatVal != nil { + metricPoint.Value = *floatVal + } + case *float32: + float32Val := float32(*v) + metricPoint.Value = float64(float32Val) + case *uint8, *uint64, *uint16, *uint32: + if _, ok := constants.ReservedColumnTargetAliases[colName]; ok { + metricPoint.Value = float64(reflect.ValueOf(v).Elem().Uint()) + } else { + groupBy = append(groupBy, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Uint())) + groupAttributes[colName] = fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Uint()) + } + case *int8, *int16, *int32, *int64: + if _, ok := constants.ReservedColumnTargetAliases[colName]; ok { + metricPoint.Value = float64(reflect.ValueOf(v).Elem().Int()) + } else { + groupBy = append(groupBy, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Int())) + groupAttributes[colName] = fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Int()) + } + default: + zap.S().Errorf("invalid var found in metric builder query result", v, colName) } } sort.Strings(groupBy) diff --git a/pkg/query-service/constants/constants.go b/pkg/query-service/constants/constants.go index d376b068e9..24690e542a 100644 --- a/pkg/query-service/constants/constants.go +++ b/pkg/query-service/constants/constants.go @@ -190,3 +190,8 @@ const ( "CAST((attributes_float64_key, attributes_float64_value), 'Map(String, Float64)') as attributes_float64," + "CAST((resources_string_key, resources_string_value), 'Map(String, String)') as resources_string " ) + +// ReservedColumnTargetAliases identifies result value from a user +// written clickhouse query. The column alias indcate which value is +// to be considered as final result (or target) +var ReservedColumnTargetAliases = map[string]bool{"result": true, "res": true, "value": true} diff --git a/pkg/query-service/rules/thresholdRule.go b/pkg/query-service/rules/thresholdRule.go index b468528335..c351d96b0f 100644 --- a/pkg/query-service/rules/thresholdRule.go +++ b/pkg/query-service/rules/thresholdRule.go @@ -422,25 +422,40 @@ func (r *ThresholdRule) runChQuery(ctx context.Context, db clickhouse.Conn, quer } case *float64: - if colName == "res" || colName == "value" { + if _, ok := constants.ReservedColumnTargetAliases[colName]; ok { sample.Point.V = *v - } else { lbls.Set(colName, fmt.Sprintf("%f", *v)) } - case *uint64: - intv := *v - if colName == "res" || colName == "value" { - sample.Point.V = float64(intv) - } else { - lbls.Set(colName, fmt.Sprintf("%d", intv)) + case **float64: + // ch seems to return this type when column is derived from + // SELECT count(*)/ SELECT count(*) + floatVal := *v + if floatVal != nil { + if _, ok := constants.ReservedColumnTargetAliases[colName]; ok { + sample.Point.V = *floatVal + } else { + lbls.Set(colName, fmt.Sprintf("%f", *floatVal)) + } } - case *uint8: - intv := *v - if colName == "res" || colName == "value" { - sample.Point.V = float64(intv) + case *float32: + float32Val := float32(*v) + if _, ok := constants.ReservedColumnTargetAliases[colName]; ok { + sample.Point.V = float64(float32Val) } else { - lbls.Set(colName, fmt.Sprintf("%d", intv)) + lbls.Set(colName, fmt.Sprintf("%f", float32Val)) + } + case *uint8, *uint64, *uint16, *uint32: + if _, ok := constants.ReservedColumnTargetAliases[colName]; ok { + sample.Point.V = float64(reflect.ValueOf(v).Elem().Uint()) + } else { + lbls.Set(colName, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Uint())) + } + case *int8, *int16, *int32, *int64: + if _, ok := constants.ReservedColumnTargetAliases[colName]; ok { + sample.Point.V = float64(reflect.ValueOf(v).Elem().Int()) + } else { + lbls.Set(colName, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Int())) } default: zap.S().Errorf("ruleId:", r.ID(), "\t error: invalid var found in query result", v, columnNames[i])