From 96e6524a7d68f3b341d66d940eff78723b9858ef Mon Sep 17 00:00:00 2001 From: Kyle Brandt Date: Mon, 26 Oct 2020 08:27:16 -0400 Subject: [PATCH] AzureMonitor: Support decimal (as float64) type in analytics/logs (#28480) loss of precision but will make the response work instead of erroring follows work already done in the ADX plugin fixes #28278 --- .../azure-log-analytics-table-frame.go | 39 +++++++++++++++++++ .../azure-log-analytics-table-frame_test.go | 3 +- .../7-log-analytics-all-types-table.json | 9 ++++- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/pkg/tsdb/azuremonitor/azure-log-analytics-table-frame.go b/pkg/tsdb/azuremonitor/azure-log-analytics-table-frame.go index 1cd38ae3df2..65add176731 100644 --- a/pkg/tsdb/azuremonitor/azure-log-analytics-table-frame.go +++ b/pkg/tsdb/azuremonitor/azure-log-analytics-table-frame.go @@ -69,6 +69,7 @@ var converterMap = map[string]data.FieldConverter{ "long": longConverter, "real": realConverter, "bool": boolConverter, + "decimal": decimalConverter, } var stringConverter = data.FieldConverter{ @@ -194,3 +195,41 @@ var longConverter = data.FieldConverter{ return &out, err }, } + +// decimalConverter converts the Kusto 128-bit type number to +// a float64. We do not have 128 bit numbers in our dataframe +// model yet (and even if we did, not sure how javascript would handle them). +// In the future, we may want to revisit storing this will proper precision, +// but for now it solves the case of people getting an error response. +// If we were to keep it a string, it would not work correctly with calls +// to functions like sdk's data.LongToWide. +var decimalConverter = data.FieldConverter{ + OutputFieldType: data.FieldTypeNullableFloat64, + Converter: func(v interface{}) (interface{}, error) { + var af *float64 + if v == nil { + return af, nil + } + + jS, sOk := v.(string) + if sOk { + out, err := strconv.ParseFloat(jS, 64) + if err != nil { + return nil, err + } + return &out, err + } + + // As far as I can tell this always comes in a string, but this is in the + // ADX code, so leaving this in case values do sometimes become a number somehow. + jN, nOk := v.(json.Number) + if !nOk { + return nil, fmt.Errorf("unexpected type, expected json.Number or string but got type %T with a value of %v", v, v) + } + out, err := jN.Float64() // Float64 calls strconv.ParseFloat64 + if err != nil { + return nil, err + } + return &out, nil + }, +} diff --git a/pkg/tsdb/azuremonitor/azure-log-analytics-table-frame_test.go b/pkg/tsdb/azuremonitor/azure-log-analytics-table-frame_test.go index acfcc7a95ef..ab4bbf2a057 100644 --- a/pkg/tsdb/azuremonitor/azure-log-analytics-table-frame_test.go +++ b/pkg/tsdb/azuremonitor/azure-log-analytics-table-frame_test.go @@ -112,10 +112,11 @@ func TestLogTableToFrame(t *testing.T) { data.NewField("XLong", nil, []*int64{pointer.Int64(9223372036854775807)}), data.NewField("XReal", nil, []*float64{pointer.Float64(1.797693134862315708145274237317043567981e+308)}), data.NewField("XTimeSpan", nil, []*string{pointer.String("00:00:00.0000001")}), + data.NewField("XDecimal", nil, []*float64{pointer.Float64(79228162514264337593543950335)}), ) frame.Meta = &data.FrameMeta{ Custom: &LogAnalyticsMeta{ColumnTypes: []string{"bool", "string", "datetime", - "dynamic", "guid", "int", "long", "real", "timespan"}}, + "dynamic", "guid", "int", "long", "real", "timespan", "decimal"}}, } return frame }, diff --git a/pkg/tsdb/azuremonitor/testdata/loganalytics/7-log-analytics-all-types-table.json b/pkg/tsdb/azuremonitor/testdata/loganalytics/7-log-analytics-all-types-table.json index 02340278b91..676c1a15102 100644 --- a/pkg/tsdb/azuremonitor/testdata/loganalytics/7-log-analytics-all-types-table.json +++ b/pkg/tsdb/azuremonitor/testdata/loganalytics/7-log-analytics-all-types-table.json @@ -38,6 +38,10 @@ { "name": "XTimeSpan", "type": "timespan" + }, + { + "name":"XDecimal", + "type":"decimal" } ], "rows": [ @@ -50,10 +54,11 @@ 2147483647, 9223372036854775807, 1.7976931348623157e+308, - "00:00:00.0000001" + "00:00:00.0000001", + "79228162514264337593543950335" ] ] } ] } - \ No newline at end of file +