mirror of
https://github.com/grafana/grafana.git
synced 2024-11-27 03:11:01 -06:00
53175a41c9
Make tsdb dataframes response able to carry encoded and/or decoded frames
168 lines
4.5 KiB
Go
168 lines
4.5 KiB
Go
package tsdb
|
|
|
|
import (
|
|
"encoding/json"
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
|
"github.com/grafana/grafana/pkg/components/null"
|
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
|
"github.com/grafana/grafana/pkg/models"
|
|
)
|
|
|
|
// TsdbQuery contains all information about a query request.
|
|
type TsdbQuery struct {
|
|
TimeRange *TimeRange
|
|
Queries []*Query
|
|
Headers map[string]string
|
|
Debug bool
|
|
User *models.SignedInUser
|
|
}
|
|
|
|
type Query struct {
|
|
RefId string
|
|
Model *simplejson.Json
|
|
DataSource *models.DataSource
|
|
MaxDataPoints int64
|
|
IntervalMs int64
|
|
QueryType string
|
|
}
|
|
|
|
type Response struct {
|
|
Results map[string]*QueryResult `json:"results"`
|
|
Message string `json:"message,omitempty"`
|
|
}
|
|
|
|
type QueryResult struct {
|
|
Error error `json:"-"`
|
|
ErrorString string `json:"error,omitempty"`
|
|
RefId string `json:"refId"`
|
|
Meta *simplejson.Json `json:"meta,omitempty"`
|
|
Series TimeSeriesSlice `json:"series"`
|
|
Tables []*Table `json:"tables"`
|
|
Dataframes DataFrames `json:"dataframes"`
|
|
}
|
|
|
|
type TimeSeries struct {
|
|
Name string `json:"name"`
|
|
Points TimeSeriesPoints `json:"points"`
|
|
Tags map[string]string `json:"tags,omitempty"`
|
|
}
|
|
|
|
type Table struct {
|
|
Columns []TableColumn `json:"columns"`
|
|
Rows []RowValues `json:"rows"`
|
|
}
|
|
|
|
type TableColumn struct {
|
|
Text string `json:"text"`
|
|
}
|
|
|
|
type RowValues []interface{}
|
|
type TimePoint [2]null.Float
|
|
type TimeSeriesPoints []TimePoint
|
|
type TimeSeriesSlice []*TimeSeries
|
|
|
|
func NewQueryResult() *QueryResult {
|
|
return &QueryResult{
|
|
Series: make(TimeSeriesSlice, 0),
|
|
}
|
|
}
|
|
|
|
func NewTimePoint(value null.Float, timestamp float64) TimePoint {
|
|
return TimePoint{value, null.FloatFrom(timestamp)}
|
|
}
|
|
|
|
func NewTimeSeriesPointsFromArgs(values ...float64) TimeSeriesPoints {
|
|
points := make(TimeSeriesPoints, 0)
|
|
|
|
for i := 0; i < len(values); i += 2 {
|
|
points = append(points, NewTimePoint(null.FloatFrom(values[i]), values[i+1]))
|
|
}
|
|
|
|
return points
|
|
}
|
|
|
|
func NewTimeSeries(name string, points TimeSeriesPoints) *TimeSeries {
|
|
return &TimeSeries{
|
|
Name: name,
|
|
Points: points,
|
|
}
|
|
}
|
|
|
|
// DataFrames interface for retrieving encoded and decoded data frames.
|
|
//
|
|
// See NewDecodedDataFrames and NewEncodedDataFrames for more information.
|
|
type DataFrames interface {
|
|
// Encoded encodes Frames into a slice of []byte.
|
|
// If an error occurs [][]byte will be nil.
|
|
// The encoded result, if any, will be cached and returned next time Encoded is called.
|
|
Encoded() ([][]byte, error)
|
|
|
|
// Decoded decodes a slice of Arrow encoded frames to data.Frames ([]*data.Frame).
|
|
// If an error occurs Frames will be nil.
|
|
// The decoded result, if any, will be cached and returned next time Decoded is called.
|
|
Decoded() (data.Frames, error)
|
|
}
|
|
|
|
type dataFrames struct {
|
|
decoded data.Frames
|
|
encoded [][]byte
|
|
}
|
|
|
|
// NewDecodedDataFrames create new DataFrames from decoded frames.
|
|
//
|
|
// This should be the primary function for creating DataFrames if your implementing a plugin.
|
|
// In Grafana alerting scenario it needs to operate on decoded frames why this function is
|
|
// preferrable. When encoded data frames is needed, e.g. returned from Grafana HTTP API, it will
|
|
// happen automatically when MarshalJSON() is called.
|
|
func NewDecodedDataFrames(decodedFrames data.Frames) DataFrames {
|
|
return &dataFrames{
|
|
decoded: decodedFrames,
|
|
}
|
|
}
|
|
|
|
// NewEncodedDataFrames create new DataFrames from encoded frames.
|
|
//
|
|
// This one is primarily used for creating DataFrames when receiving encoded data frames from an external
|
|
// plugin or similar. This may allow the encoded data frames to be returned to Grafana UI without any additional
|
|
// decoding/encoding required. In Grafana alerting scenario it needs to operate on decoded data frames why encoded
|
|
// frames needs to be decoded before usage.
|
|
func NewEncodedDataFrames(encodedFrames [][]byte) DataFrames {
|
|
return &dataFrames{
|
|
encoded: encodedFrames,
|
|
}
|
|
}
|
|
|
|
func (df *dataFrames) Encoded() ([][]byte, error) {
|
|
if df.encoded == nil {
|
|
encoded, err := df.decoded.MarshalArrow()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
df.encoded = encoded
|
|
}
|
|
|
|
return df.encoded, nil
|
|
}
|
|
|
|
func (df *dataFrames) Decoded() (data.Frames, error) {
|
|
if df.decoded == nil {
|
|
decoded, err := data.UnmarshalArrowFrames(df.encoded)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
df.decoded = decoded
|
|
}
|
|
|
|
return df.decoded, nil
|
|
}
|
|
|
|
func (df *dataFrames) MarshalJSON() ([]byte, error) {
|
|
encoded, err := df.Encoded()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return json.Marshal(encoded)
|
|
}
|