Commit f6cbb261 by Kyle Brandt Committed by GitHub

BackendPlugin: Change QueryData response format (#23234)

* BackendPlugin: (wip) change response format
goes with https://github.com/grafana/grafana-plugin-sdk-go/pull/109

* fix error mapping in wrapper

* latest of my sdk branch

* latest of my sdk branch

* TransformWrapper fixes

* latest of sdk branch (removes extra meta)

* add metadata in wrappers

* also set error string

* sdk: v0.35.0
parent afd8ffde
...@@ -30,7 +30,7 @@ require ( ...@@ -30,7 +30,7 @@ require (
github.com/gorilla/websocket v1.4.1 github.com/gorilla/websocket v1.4.1
github.com/gosimple/slug v1.4.2 github.com/gosimple/slug v1.4.2
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4 github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4
github.com/grafana/grafana-plugin-sdk-go v0.33.0 github.com/grafana/grafana-plugin-sdk-go v0.35.0
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd
github.com/hashicorp/go-plugin v1.0.1 github.com/hashicorp/go-plugin v1.0.1
github.com/hashicorp/go-version v1.1.0 github.com/hashicorp/go-version v1.1.0
......
...@@ -128,8 +128,8 @@ github.com/gosimple/slug v1.4.2 h1:jDmprx3q/9Lfk4FkGZtvzDQ9Cj9eAmsjzeQGp24PeiQ= ...@@ -128,8 +128,8 @@ github.com/gosimple/slug v1.4.2 h1:jDmprx3q/9Lfk4FkGZtvzDQ9Cj9eAmsjzeQGp24PeiQ=
github.com/gosimple/slug v1.4.2/go.mod h1:ER78kgg1Mv0NQGlXiDe57DpCyfbNywXXZ9mIorhxAf0= github.com/gosimple/slug v1.4.2/go.mod h1:ER78kgg1Mv0NQGlXiDe57DpCyfbNywXXZ9mIorhxAf0=
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4 h1:SPdxCL9BChFTlyi0Khv64vdCW4TMna8+sxL7+Chx+Ag= github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4 h1:SPdxCL9BChFTlyi0Khv64vdCW4TMna8+sxL7+Chx+Ag=
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4/go.mod h1:nc0XxBzjeGcrMltCDw269LoWF9S8ibhgxolCdA1R8To= github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4/go.mod h1:nc0XxBzjeGcrMltCDw269LoWF9S8ibhgxolCdA1R8To=
github.com/grafana/grafana-plugin-sdk-go v0.33.0 h1:+eFcOV/KioHTTRNimENZeajlkw31B+m92RNRShooPEQ= github.com/grafana/grafana-plugin-sdk-go v0.35.0 h1:IxNaNq8hN3ShQ804FURFOd1ehbKOmFROztY+8vohhW8=
github.com/grafana/grafana-plugin-sdk-go v0.33.0/go.mod h1:4rVPIvfv7SzFC0AA/8T5tmDRxIsrvDJOF9p4SrQGS1M= github.com/grafana/grafana-plugin-sdk-go v0.35.0/go.mod h1:zX/Zz/HYDAkL1NxffOZeixqPqIVVoCTWI2AuFy4J+V4=
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd h1:rNuUHR+CvK1IS89MMtcF0EpcVMZtjKfPRp4MEmt/aTs= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd h1:rNuUHR+CvK1IS89MMtcF0EpcVMZtjKfPRp4MEmt/aTs=
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
github.com/hashicorp/go-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE= github.com/hashicorp/go-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE=
...@@ -180,6 +180,7 @@ github.com/linkedin/goavro/v2 v2.9.7 h1:Vd++Rb/RKcmNJjM0HP/JJFMEWa21eUBVKPYlKehO ...@@ -180,6 +180,7 @@ github.com/linkedin/goavro/v2 v2.9.7 h1:Vd++Rb/RKcmNJjM0HP/JJFMEWa21eUBVKPYlKehO
github.com/linkedin/goavro/v2 v2.9.7/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA= github.com/linkedin/goavro/v2 v2.9.7/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA=
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbatJuy3nvq/hRSvuBJrHHr+ybPPiNvHQ= github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbatJuy3nvq/hRSvuBJrHHr+ybPPiNvHQ=
github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VObJ7peltM+2n3PWOz7yTrfUuGbVFkzN0= github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VObJ7peltM+2n3PWOz7yTrfUuGbVFkzN0=
github.com/magefile/mage v1.9.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/mattetti/filebuffer v1.0.0 h1:ixTvQ0JjBTwWbdpDZ98lLrydo7KRi8xNRIi5RFszsbY= github.com/mattetti/filebuffer v1.0.0 h1:ixTvQ0JjBTwWbdpDZ98lLrydo7KRi8xNRIi5RFszsbY=
github.com/mattetti/filebuffer v1.0.0/go.mod h1:X6nyAIge2JGVmuJt2MFCqmHrb/5IHiphfHtot0s5cnI= github.com/mattetti/filebuffer v1.0.0/go.mod h1:X6nyAIge2JGVmuJt2MFCqmHrb/5IHiphfHtot0s5cnI=
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
......
...@@ -2,12 +2,13 @@ package wrapper ...@@ -2,12 +2,13 @@ package wrapper
import ( import (
"context" "context"
"fmt"
"time" "time"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/plugins/backendplugin" "github.com/grafana/grafana/pkg/plugins/backendplugin"
"github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2" "github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/tsdb" "github.com/grafana/grafana/pkg/tsdb"
...@@ -81,12 +82,24 @@ func (tw *DatasourcePluginWrapperV2) Query(ctx context.Context, ds *models.DataS ...@@ -81,12 +82,24 @@ func (tw *DatasourcePluginWrapperV2) Query(ctx context.Context, ds *models.DataS
return nil, err return nil, err
} }
return &tsdb.Response{ tR := &tsdb.Response{
Results: map[string]*tsdb.QueryResult{ Results: make(map[string]*tsdb.QueryResult, len(pbRes.Responses)),
"": { }
Dataframes: pbRes.Frames,
Meta: simplejson.NewFromAny(pbRes.Metadata), for refID, pRes := range pbRes.Responses {
}, qr := &tsdb.QueryResult{
}, RefId: refID,
}, nil Dataframes: pRes.Frames,
}
if len(pRes.JsonMeta) != 0 {
qr.Meta = simplejson.NewFromAny(pRes.JsonMeta)
}
if pRes.Error != "" {
qr.Error = fmt.Errorf(pRes.Error)
qr.ErrorString = pRes.Error
}
tR.Results[refID] = qr
}
return tR, nil
} }
...@@ -103,14 +103,25 @@ func (tw *TransformWrapper) Transform(ctx context.Context, query *tsdb.TsdbQuery ...@@ -103,14 +103,25 @@ func (tw *TransformWrapper) Transform(ctx context.Context, query *tsdb.TsdbQuery
return nil, err return nil, err
} }
return &tsdb.Response{ tR := &tsdb.Response{
Results: map[string]*tsdb.QueryResult{ Results: make(map[string]*tsdb.QueryResult, len(pbRes.Responses)),
"": { }
Dataframes: pbRes.Frames, for refID, res := range pbRes.Responses {
Meta: simplejson.NewFromAny(pbRes.Metadata), tRes := &tsdb.QueryResult{
}, RefId: refID,
}, Dataframes: res.Frames,
}, nil }
if len(res.JsonMeta) != 0 {
tRes.Meta = simplejson.NewFromAny(res.JsonMeta)
}
if res.Error != "" {
tRes.Error = fmt.Errorf(res.Error)
tRes.ErrorString = res.Error
}
tR.Results[refID] = tRes
}
return tR, nil
} }
type transformCallback struct { type transformCallback struct {
...@@ -168,18 +179,16 @@ func (s *transformCallback) QueryData(ctx context.Context, req *pluginv2.QueryDa ...@@ -168,18 +179,16 @@ func (s *transformCallback) QueryData(ctx context.Context, req *pluginv2.QueryDa
} }
// Convert tsdb results (map) to plugin-model/datasource (slice) results. // Convert tsdb results (map) to plugin-model/datasource (slice) results.
// Only error, tsdb.Series, and encoded Dataframes responses are mapped. // Only error, tsdb.Series, and encoded Dataframes responses are mapped.
responses := make(map[string]*pluginv2.DataResponse, len(tsdbRes.Results))
encodedFrames := [][]byte{}
for refID, res := range tsdbRes.Results { for refID, res := range tsdbRes.Results {
pRes := &pluginv2.DataResponse{}
if res.Error != nil { if res.Error != nil {
// TODO add Errors property to Frame pRes.Error = res.Error.Error()
encodedFrames = append(encodedFrames, nil)
continue
} }
if res.Dataframes != nil { if res.Dataframes != nil {
encodedFrames = append(encodedFrames, res.Dataframes...) pRes.Frames = res.Dataframes
responses[refID] = pRes
continue continue
} }
...@@ -193,8 +202,18 @@ func (s *transformCallback) QueryData(ctx context.Context, req *pluginv2.QueryDa ...@@ -193,8 +202,18 @@ func (s *transformCallback) QueryData(ctx context.Context, req *pluginv2.QueryDa
if err != nil { if err != nil {
return nil, err return nil, err
} }
encodedFrames = append(encodedFrames, encFrame) pRes.Frames = append(pRes.Frames, encFrame)
} }
if res.Meta != nil {
b, err := res.Meta.MarshalJSON()
if err != nil {
s.logger.Error("failed to marhsal json metadata", err)
}
pRes.JsonMeta = b
} }
return &pluginv2.QueryDataResponse{Frames: encodedFrames}, nil responses[refID] = pRes
}
return &pluginv2.QueryDataResponse{
Responses: responses,
}, nil
} }
...@@ -657,7 +657,7 @@ func UnmarshalArrow(b []byte) (*Frame, error) { ...@@ -657,7 +657,7 @@ func UnmarshalArrow(b []byte) (*Frame, error) {
if metaAsString, ok := getMDKey("meta", metaData); ok { if metaAsString, ok := getMDKey("meta", metaData); ok {
var err error var err error
frame.Meta, err = QueryResultMetaFromJSON(metaAsString) frame.Meta, err = FrameMetaFromJSON(metaAsString)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -692,3 +692,29 @@ func toJSONString(val interface{}) (string, error) { ...@@ -692,3 +692,29 @@ func toJSONString(val interface{}) (string, error) {
} }
return string(b), nil return string(b), nil
} }
// BytesSliceToFrames decodes a slice of encoded Arrow frames to a slice of *Frame.
func BytesSliceToFrames(bFrames [][]byte) ([]*Frame, error) {
frames := make([]*Frame, len(bFrames))
var err error
for i, encodedFrame := range bFrames {
frames[i], err = UnmarshalArrow(encodedFrame)
if err != nil {
return nil, err
}
}
return frames, nil
}
// FramesToBytesSlice encodes a slice of Frames into a slice of []byte.
func FramesToBytesSlice(frames []*Frame) ([][]byte, error) {
bs := make([][]byte, len(frames))
var err error
for i, frame := range frames {
bs[i], err = MarshalArrow(frame)
if err != nil {
return nil, err
}
}
return bs, nil
}
...@@ -28,7 +28,7 @@ type Frame struct { ...@@ -28,7 +28,7 @@ type Frame struct {
Fields []*Field Fields []*Field
RefID string RefID string
Meta *QueryResultMeta Meta *FrameMeta
Warnings []Warning Warnings []Warning
} }
...@@ -263,29 +263,13 @@ func FrameTestCompareOptions() []cmp.Option { ...@@ -263,29 +263,13 @@ func FrameTestCompareOptions() []cmp.Option {
if x == nil && y == nil { if x == nil && y == nil {
return true return true
} }
if y == nil { if y == nil && x != nil || y != nil && x == nil {
if math.IsNaN(float64(*x)) { return false
return true
}
if math.IsInf(float64(*x), 1) {
return true
} }
if math.IsInf(float64(*x), -1) { return (math.IsNaN(float64(*x)) && math.IsNaN(float64(*y))) ||
return true (math.IsInf(float64(*x), 1) && math.IsInf(float64(*y), 1)) ||
} (math.IsInf(float64(*x), -1) && math.IsInf(float64(*y), -1)) ||
} *x == *y
if x == nil {
if math.IsNaN(float64(*y)) {
return true
}
if math.IsInf(float64(*y), 1) {
return true
}
if math.IsInf(float64(*y), -1) {
return true
}
}
return *x == *y
}) })
f64s := cmp.Comparer(func(x, y float64) bool { f64s := cmp.Comparer(func(x, y float64) bool {
return (math.IsNaN(x) && math.IsNaN(y)) || return (math.IsNaN(x) && math.IsNaN(y)) ||
...@@ -297,29 +281,13 @@ func FrameTestCompareOptions() []cmp.Option { ...@@ -297,29 +281,13 @@ func FrameTestCompareOptions() []cmp.Option {
if x == nil && y == nil { if x == nil && y == nil {
return true return true
} }
if y == nil { if y == nil && x != nil || y != nil && x == nil {
if math.IsNaN(float64(*x)) { return false
return true
}
if math.IsInf(float64(*x), 1) {
return true
}
if math.IsInf(float64(*x), -1) {
return true
}
} }
if x == nil { return (math.IsNaN(float64(*x)) && math.IsNaN(float64(*y))) ||
if math.IsNaN(float64(*y)) { (math.IsInf(float64(*x), 1) && math.IsInf(float64(*y), 1)) ||
return true (math.IsInf(float64(*x), -1) && math.IsInf(float64(*y), -1)) ||
} *x == *y
if math.IsInf(float64(*y), 1) {
return true
}
if math.IsInf(float64(*y), -1) {
return true
}
}
return *x == *y
}) })
f32s := cmp.Comparer(func(x, y float32) bool { f32s := cmp.Comparer(func(x, y float32) bool {
return (math.IsNaN(float64(x)) && math.IsNaN(float64(y))) || return (math.IsNaN(float64(x)) && math.IsNaN(float64(y))) ||
...@@ -369,6 +337,8 @@ func (f *Frame) StringTable(maxFields, maxRows int) (string, error) { ...@@ -369,6 +337,8 @@ func (f *Frame) StringTable(maxFields, maxRows int) (string, error) {
sb := &strings.Builder{} sb := &strings.Builder{}
sb.WriteString(fmt.Sprintf("Name: %v\n", f.Name)) sb.WriteString(fmt.Sprintf("Name: %v\n", f.Name))
sb.WriteString(fmt.Sprintf("Dimensions: %v Fields by %v Rows\n", len(f.Fields), rowLen))
table := tablewriter.NewWriter(sb) table := tablewriter.NewWriter(sb)
// table formatting options // table formatting options
...@@ -377,9 +347,6 @@ func (f *Frame) StringTable(maxFields, maxRows int) (string, error) { ...@@ -377,9 +347,6 @@ func (f *Frame) StringTable(maxFields, maxRows int) (string, error) {
table.SetAutoWrapText(false) table.SetAutoWrapText(false)
table.SetAlignment(tablewriter.ALIGN_LEFT) table.SetAlignment(tablewriter.ALIGN_LEFT)
// (caption is below the table)
table.SetCaption(true, fmt.Sprintf("Field Count: %v\nRow Count: %v", len(f.Fields), rowLen))
// set table headers // set table headers
headers := make([]string, width) headers := make([]string, width)
for colIdx, field := range f.Fields { for colIdx, field := range f.Fields {
......
...@@ -2,24 +2,24 @@ package data ...@@ -2,24 +2,24 @@ package data
import "encoding/json" import "encoding/json"
// QueryResultMeta matches: // FrameMeta matches:
// https://github.com/grafana/grafana/blob/master/packages/grafana-data/src/types/data.ts#L11 // https://github.com/grafana/grafana/blob/master/packages/grafana-data/src/types/data.ts#L11
// NOTE -- in javascript this can accept any `[key: string]: any;` however // NOTE -- in javascript this can accept any `[key: string]: any;` however
// this interface only exposes the values we want to be exposed // this interface only exposes the values we want to be exposed
type QueryResultMeta struct { type FrameMeta struct {
// Used in Explore for highlighting
SearchWords []string `json:"searchWords,omitempty"`
// Used in Explore to show limit applied to search result
Limit int64 `json:"limit,omitempty"`
// Datasource specific values // Datasource specific values
Custom map[string]interface{} `json:"custom,omitempty"` Custom map[string]interface{} `json:"custom,omitempty"`
// Stats is TODO
Stats interface{} `json:"stats,omitempty"`
// Notices is TODO
Notices interface{} `json:"notices,omitempty"`
} }
// QueryResultMetaFromJSON creates a QueryResultMeta from a json string // FrameMetaFromJSON creates a QueryResultMeta from a json string
func QueryResultMetaFromJSON(jsonStr string) (*QueryResultMeta, error) { func FrameMetaFromJSON(jsonStr string) (*FrameMeta, error) {
var m QueryResultMeta var m FrameMeta
err := json.Unmarshal([]byte(jsonStr), &m) err := json.Unmarshal([]byte(jsonStr), &m)
if err != nil { if err != nil {
return nil, err return nil, err
......
...@@ -142,7 +142,7 @@ github.com/gosimple/slug ...@@ -142,7 +142,7 @@ github.com/gosimple/slug
# github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4 # github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4
github.com/grafana/grafana-plugin-model/go/datasource github.com/grafana/grafana-plugin-model/go/datasource
github.com/grafana/grafana-plugin-model/go/renderer github.com/grafana/grafana-plugin-model/go/renderer
# github.com/grafana/grafana-plugin-sdk-go v0.33.0 # github.com/grafana/grafana-plugin-sdk-go v0.35.0
github.com/grafana/grafana-plugin-sdk-go/backend/grpcplugin github.com/grafana/grafana-plugin-sdk-go/backend/grpcplugin
github.com/grafana/grafana-plugin-sdk-go/data github.com/grafana/grafana-plugin-sdk-go/data
github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2 github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment