Back to godoc.org

Package data

v0.75.0
Latest Go to latest

The latest major version is .

Published: Jul 14, 2020 | License: Apache-2.0 | Module: github.com/grafana/grafana-plugin-sdk-go

Overview

Package data provides data structures that Grafana recognizes.

The Frame object represents a Grafana Dataframe which can represent data such as tables and time series.

Frames can be encoded using Apache Arrow (https://arrow.apache.org/) for transmission.

The corresponding Grafana frontend package the @grafana/data package (https://github.com/grafana/grafana/tree/master/packages/grafana-data).

Index

Examples

Constants

const (
	// VisTypeGraph indicates the response should be visualized using a graph.
	VisTypeGraph VisType = "graph"

	// VisTypeTable indicates the response should be visualized using a table.
	VisTypeTable = "table"

	// VisTypeLogs indicates the response should be visualized using a logs visualization.
	VisTypeLogs = "logs"
)

Variables

var AsStringFieldConverter = FieldConverter{
	OutputFieldType: FieldTypeString,
	Converter:       asStringConverter,
}

AsStringFieldConverter will always return a string a regardless of the input. This is done with fmt.Sprintf which uses reflection.

func FrameTestCompareOptions

func FrameTestCompareOptions() []cmp.Option

FrameTestCompareOptions returns go-cmp testing options to allow testing of Frame equivalence. Since the data within a Frame's Fields is not exported, this function allows the unexported values to be tested. The intent is to only use this for testing.

func GetMissing

func GetMissing(fillMissing *FillMissing, field *Field, previousRowIdx int) (interface{}, error)

GetMissing returns the value to be filled for a missing row field.

func SortWideFrameFields

func SortWideFrameFields(frame *Frame, keys ...string) error

SortWideFrameFields sorts the order of a wide time series Frame's Fields. It the frame is not a WideFrame, than an error is returned.

The Time that is the time index (the first time field of the original frame) is sorted first. Then Fields are sorted by their name followed by the order of the label keys provided. If no keys are provided, they are sorted by the string representation of their labels.

func ValidFieldType

func ValidFieldType(t interface{}) bool

ValidFieldType returns if a primitive slice is a valid supported Field type.

type ConfFloat64

type ConfFloat64 float64

ConfFloat64 is a float64. It Marshals float64 values of NaN of Inf to null.

func (*ConfFloat64) MarshalJSON

func (sf *ConfFloat64) MarshalJSON() ([]byte, error)

MarshalJSON fullfills the json.Marshaler interface.

func (*ConfFloat64) UnmarshalJSON

func (sf *ConfFloat64) UnmarshalJSON(data []byte) error

UnmarshalJSON fullfills the json.Unmarshaler interface.

type Converter

type Converter func(v interface{}) (interface{}, error)

Converter is a function type for converting values in a Frame. It is the consumers responsibility to the check the underlying interface types of the input and return types to avoid panics.

type DataLink struct {
	Title       string `json:"title,omitempty"`
	TargetBlank bool   `json:"targetBlank,omitempty"`
	URL         string `json:"url,omitempty"`
}

DataLink define what

type Field

type Field struct {
	// Name is default identifier of the field. The name does not have to be unique, but the combination
	// of name and Labels should be unique for proper behavior in all situations.
	Name string

	// Labels is an optional set of key=value pairs that in addition to the name, should uniquely
	// identify a Field within a Frame.
	Labels Labels

	// Config is optional display configuration information for Grafana
	Config *FieldConfig
	// contains filtered or unexported fields
}

Field represents a typed column of data within a Frame.

A Field is essentially a slice of various types with extra properties and methods. See NewField() for supported types.

The slice data in the Field is a not exported, so methods on the Field are used to to manipulate its data.

func NewField

func NewField(name string, labels Labels, values interface{}) *Field

NewField returns a instance of *Field. Supported types for values are:

Integers:

[]int8, []*int8, []int16, []*int16, []int32, []*int32, []int64, []*int64

Unsigned Integers:

[]uint8, []*uint8, []uint16, []*uint16, []uint32, []*uint32, []uint64, []*uint64

Floats:

[]float32, []*float32, []float64, []*float64

String, Bool, and Time:

[]string, []*string, []bool, []*bool, []time.Time, and []*time.Time.

If an unsupported values type is passed, NewField will panic.

func NewFieldFromFieldType

func NewFieldFromFieldType(p FieldType, n int) *Field

NewFieldFromFieldType creates a new Field of the given FieldType of length n.

func (*Field) Append

func (f *Field) Append(e interface{})

Append appends element e to the Field. it will panic if the underlying type of e does not match the element type of the Field.

func (*Field) At

func (f *Field) At(idx int) interface{}

At returns the the element at index idx of the Field. It will panic if idx is out of range.

func (*Field) ConcreteAt

func (f *Field) ConcreteAt(idx int) (val interface{}, ok bool)

ConcreteAt returns the concrete value at the specified index idx. A non-pointer type is returned regardless if the underlying vector is a pointer type or not. If the value is a pointer type, and is nil, then the zero value is returned and ok will be false.

func (*Field) CopyAt

func (f *Field) CopyAt(idx int) interface{}

CopyAt returns a copy of the value of the specified index idx. It will panic if idx is out of range.

func (*Field) Delete

func (f *Field) Delete(idx int)

Delete delete element at index idx of the Field.

func (*Field) Extend

func (f *Field) Extend(i int)

Extend extends the Field length by i. Consider using Frame.Extend() when possible since all Fields within a Frame need to be of the same length before marshalling and transmission.

func (*Field) FloatAt

func (f *Field) FloatAt(idx int) (float64, error)

FloatAt returns a float64 at the specified index idx for all supported Field types. It will panic if idx is out of range.

If the Field type is numeric and the value at idx is nil, NaN is returned. Precision may be lost on large numbers.

If the Field type is a bool then 0 is return if false or nil, and 1 if true.

If the Field type is time.Time, then the millisecond epoch representation of the time is returned, or NaN is the value is nil.

If the Field type is a string, then strconv.ParseFloat is called on it and will return an error if ParseFloat errors. If the value is nil, NaN is returned.

func (*Field) Insert

func (f *Field) Insert(idx int, val interface{})

Insert extends the Field length by 1, shifts any existing field values at indices equal or greater to idx by one place and inserts val at index idx of the Field. If idx is equal to the Field length, then val will be appended. It idx exceeds the Field length, this method will panic.

func (*Field) Len

func (f *Field) Len() int

Len returns the number of elements in the Field.

func (*Field) Nullable

func (f *Field) Nullable() bool

Nullable returns if the the Field's elements are nullable.

func (*Field) PointerAt

func (f *Field) PointerAt(idx int) interface{}

PointerAt returns a pointer to the value at idx of the Field. It will panic if idx is out of range.

func (*Field) Set

func (f *Field) Set(idx int, val interface{})

Set sets the Field's value at index idx to val. It will panic if idx is out of range or if the underlying type of val does not match the element type of the Field.

func (*Field) SetConcrete

func (f *Field) SetConcrete(idx int, val interface{})

SetConcrete sets the Field's value at index idx to val. val must be a non-pointer type or a panic will occur. If the underlying FieldType is nullable it will set val as a pointer to val. If the FieldType is not nullable, then this method behaves the same as the Set method. It will panic if the underlying type of val does not match the element concrete type of the Field.

func (*Field) SetConfig

func (f *Field) SetConfig(conf *FieldConfig) *Field

SetConfig modifies the Field's Config property to be set to conf and returns the Field.

func (*Field) Type

func (f *Field) Type() FieldType

Type returns the FieldType of the Field, which indicates what type of slice it is.

type FieldConfig

type FieldConfig struct {
	DisplayName string `json:"displayName,omitempty"`
	Filterable  *bool  `json:"filterable,omitempty"` // indicates if the Field's data can be filtered by additional calls.

	// Numeric Options
	Unit     string       `json:"unit,omitempty"`     // is the string to display to represent the Field's unit, such as "Requests/sec"
	Decimals *uint16      `json:"decimals,omitempty"` // is the number of decimal places to display
	Min      *ConfFloat64 `json:"min,omitempty"`      // is the maximum value of fields in the column. When present the frontend can skip the calculation.
	Max      *ConfFloat64 `json:"max,omitempty"`      // see Min

	// Convert input values into a display string
	Mappings []ValueMapping `json:"mappings,omitempty"`

	// Map numeric values to states
	Thresholds *ThresholdsConfig `json:"thresholds,omitempty"`

	// Map values to a display color
	// NOTE: this interface is under development in the frontend... so simple map for now
	Color map[string]interface{} `json:"color,omitempty"`

	// Used when reducing field values
	NullValueMode NullValueMode `json:"nullValueMode,omitempty"`

	// The behavior when clicking on a result
	Links []DataLink `json:"links,omitempty"`

	// Alternative to empty string
	NoValue string `json:"noValue,omitempty"`

	// Panel Specific Values
	Custom map[string]interface{} `json:"custom,omitempty"`
}

FieldConfig represents the display properties for a Field.

func (*FieldConfig) SetDecimals

func (fc *FieldConfig) SetDecimals(v uint16) *FieldConfig

SetDecimals modifies the FieldConfig's Decimals property to be set to v and returns the FieldConfig. It is a convenience function since the Decimals property is a pointer.

func (*FieldConfig) SetFilterable

func (fc *FieldConfig) SetFilterable(b bool) *FieldConfig

SetFilterable modifies the FieldConfig's Filterable property to be set to b and returns the FieldConfig. It is a convenience function since the Filterable property is a pointer.

func (*FieldConfig) SetMax

func (fc *FieldConfig) SetMax(v float64) *FieldConfig

SetMax modifies the FieldConfig's Max property to be set to v and returns the FieldConfig. It is a convenience function since the Min property is a pointer.

func (*FieldConfig) SetMin

func (fc *FieldConfig) SetMin(v float64) *FieldConfig

SetMin modifies the FieldConfig's Min property to be set to v and returns the FieldConfig. It is a convenience function since the Min property is a pointer.

type FieldConverter

type FieldConverter struct {
	// OutputFieldType is the type of Field that will be created.
	OutputFieldType FieldType

	// Converter is a conversion function that is called when setting Field values with a FrameInputConverter.
	// Care must be taken that the type returned by the conversion function matches the member type of the FieldType,
	// and that the input type matches the expected input type for the Converter function, or panics can occur.
	// If the Converter is nil, no conversion is performed when calling methods to set values.
	Converter Converter
}

A FieldConverter is a type to support building Frame fields of a different type than one's input data.

type FieldType

type FieldType int

FieldType indicates the Go type underlying the Field.

const (
	// FieldTypeInt8 indicates the underlying primitive is a []int8.
	FieldTypeInt8 FieldType = iota
	// FieldTypeNullableInt8 indicates the underlying primitive is a []*int8.
	FieldTypeNullableInt8

	// FieldTypeInt16 indicates the underlying primitive is a []Int16.
	FieldTypeInt16
	// FieldTypeNullableInt16 indicates the underlying primitive is a []*Int16.
	FieldTypeNullableInt16

	// FieldTypeInt32 indicates the underlying primitive is a []int32.
	FieldTypeInt32
	// FieldTypeNullableInt32 indicates the underlying primitive is a []*int32.
	FieldTypeNullableInt32

	// FieldTypeInt64 indicates the underlying primitive is a []int64.
	FieldTypeInt64
	// FieldTypeNullableInt64 indicates the underlying primitive is a []*int64.
	FieldTypeNullableInt64

	// FieldTypeUint8 indicates the underlying primitive is a []int8.
	FieldTypeUint8
	// FieldTypeNullableUint8 indicates the underlying primitive is a []*int8.
	FieldTypeNullableUint8

	// FieldTypeUint16 indicates the underlying primitive is a []uint16.
	FieldTypeUint16
	// FieldTypeNullableUint16 indicates the underlying primitive is a []*uint16.
	FieldTypeNullableUint16

	// FieldTypeUint32 indicates the underlying primitive is a []uint32.
	FieldTypeUint32
	// FieldTypeNullableUint32 indicates the underlying primitive is a []*uint32.
	FieldTypeNullableUint32

	// FieldTypeUint64 indicates the underlying primitive is a []uint64.
	FieldTypeUint64
	// FieldTypeNullableUint64 indicates the underlying primitive is a []*uint64.
	FieldTypeNullableUint64

	// FieldTypeFloat32 indicates the underlying primitive is a []float32.
	FieldTypeFloat32
	// FieldTypeNullableFloat32 indicates the underlying primitive is a []*float32.
	FieldTypeNullableFloat32

	// FieldTypeFloat64 indicates the underlying primitive is a []float64.
	FieldTypeFloat64
	// FieldTypeNullableFloat64 indicates the underlying primitive is a []*float64.
	FieldTypeNullableFloat64

	// FieldTypeString indicates the underlying primitive is a []string.
	FieldTypeString
	// FieldTypeNullableString indicates the underlying primitive is a []*string.
	FieldTypeNullableString

	// FieldTypeBool indicates the underlying primitive is a []bool.
	FieldTypeBool
	// FieldTypeNullableBool indicates the underlying primitive is a []*bool.
	FieldTypeNullableBool

	// FieldTypeTime indicates the underlying primitive is a []time.Time.
	FieldTypeTime
	// FieldTypeNullableTime indicates the underlying primitive is a []*time.Time.
	FieldTypeNullableTime
)

func NumericFieldTypes

func NumericFieldTypes() []FieldType

NumericFieldTypes returns a slice of FieldTypes that are numeric.

func (FieldType) ItemTypeString

func (p FieldType) ItemTypeString() string

ItemTypeString returns the string representation of the type of element within in the vector

func (FieldType) Nullable

func (p FieldType) Nullable() bool

Nullable returns if Field type is a nullable type

func (FieldType) NullableType

func (p FieldType) NullableType() FieldType

NullableType converts the FieldType to the corresponding nullable type.

func (FieldType) Numeric

func (p FieldType) Numeric() bool

Numeric returns if Field type is a nullable type.

func (FieldType) String

func (p FieldType) String() string

func (FieldType) Time

func (p FieldType) Time() bool

Time returns if Field type is a time type (FieldTypeTime or FieldTypeNullableTime).

type Fields

type Fields []*Field

Fields is a slice of Field pointers.

type FillMissing

type FillMissing struct {
	Mode  FillMode
	Value float64
}

FillMissing is a struct containing the fill mode and the fill value if fill mode is FillModeValue

type FillMode

type FillMode int

FillMode is an integer type denoting how missing values should be filled.

const (
	// FillModePrevious fills with the last seen value unless that does not exist, in which case it fills with null.
	FillModePrevious FillMode = iota
	// FillModeNull fills with null
	FillModeNull
	// FillModeValue fills with a specific value
	FillModeValue
)

type Frame

type Frame struct {
	// Name is used in some Grafana visualizations.
	Name string

	// Fields are the columns of a frame.
	// All Fields must be of the same the length when marshalling the Frame for transmission.
	Fields []*Field

	// RefID is a property that can be set to match a Frame to its orginating query.
	RefID string

	// Meta is metadata about the Frame, and includes space for custom metadata.
	Meta *FrameMeta
}

Frame is a columnar data structure where each column is a Field.

Each Field is well typed by its FieldType and supports optional Labels.

A Frame is a general data container for Grafana. A Frame can be table data or time series data depending on its content and field types.

Example (TSDBTimeSeriesDifferentTimeIndices)

Code:

package main

import (
	"fmt"
	"github.com/grafana/grafana-plugin-sdk-go/data"
	"time"
)

type mockPoint struct {
	Time  time.Time
	Value float64
}

type mockSeries struct {
	Name   string
	Labels map[string]string
	Points []mockPoint
}

type mockResponse struct {
	Series []mockSeries
}

func main() {
	// A common tsdb response pattern is to return a collection
	// of time series where each time series is uniquely identified
	// by a Name and a set of key value pairs (Labels (a.k.a Tags)).

	// In the case where the responses does not share identical time values and length (a single time index),
	// then the proper representation is Frames ([]*Frame). Where each Frame has a Time type field and one or more
	// Number fields.

	// Each Frame should have its value sorted by time in ascending order.

	res := mockResponse{
		[]mockSeries{
			{
				Name:   "cpu",
				Labels: map[string]string{"host": "a"},
				Points: []mockPoint{
					{
						time.Date(2020, 1, 2, 3, 4, 0, 0, time.UTC), 3,
					},
					{
						time.Date(2020, 1, 2, 3, 5, 0, 0, time.UTC), 6,
					},
				},
			},
			{
				Name:   "cpu",
				Labels: map[string]string{"host": "b"},
				Points: []mockPoint{
					{
						time.Date(2020, 1, 2, 3, 4, 1, 0, time.UTC), 4,
					},
					{
						time.Date(2020, 1, 2, 3, 5, 1, 0, time.UTC), 7,
					},
				},
			},
		},
	}

	frames := make([]*data.Frame, len(res.Series))
	for i, series := range res.Series {
		frames[i] = data.NewFrame(series.Name,
			data.NewField("time", nil, make([]time.Time, len(series.Points))),
			data.NewField(series.Name, series.Labels, make([]float64, len(series.Points))),
		)
		for pIdx, point := range series.Points {
			frames[i].Set(0, pIdx, point.Time)
			frames[i].Set(1, pIdx, point.Value)
		}
	}

	for _, frame := range frames {
		st, _ := frame.StringTable(-1, -1)
		fmt.Println(st)
	}
}
Name: cpu
Dimensions: 2 Fields by 2 Rows
+-------------------------------+-----------------+
| Name: time                    | Name: cpu       |
| Labels:                       | Labels: host=a  |
| Type: []time.Time             | Type: []float64 |
+-------------------------------+-----------------+
| 2020-01-02 03:04:00 +0000 UTC | 3               |
| 2020-01-02 03:05:00 +0000 UTC | 6               |
+-------------------------------+-----------------+

Name: cpu
Dimensions: 2 Fields by 2 Rows
+-------------------------------+-----------------+
| Name: time                    | Name: cpu       |
| Labels:                       | Labels: host=b  |
| Type: []time.Time             | Type: []float64 |
+-------------------------------+-----------------+
| 2020-01-02 03:04:01 +0000 UTC | 4               |
| 2020-01-02 03:05:01 +0000 UTC | 7               |
+-------------------------------+-----------------+
Example (TSDBTimeSeriesSharedTimeIndex)

Code:

package main

import (
	"fmt"
	"github.com/grafana/grafana-plugin-sdk-go/data"
	"time"
)

type mockPoint struct {
	Time  time.Time
	Value float64
}

type mockSeries struct {
	Name   string
	Labels map[string]string
	Points []mockPoint
}

type mockResponse struct {
	Series []mockSeries
}

func main() {
	// In the case where you do know all the response will share the same time index, then
	// a "wide" dataframe can be created that holds all the responses. So your response is
	// all in a Single Frame.

	singleTimeIndexRes := mockResponse{
		[]mockSeries{
			{
				Name:   "cpu",
				Labels: map[string]string{"host": "a"},
				Points: []mockPoint{
					{
						time.Date(2020, 1, 2, 3, 4, 0, 0, time.UTC), 3,
					},
					{
						time.Date(2020, 1, 2, 3, 5, 0, 0, time.UTC), 6,
					},
				},
			},
			{
				Name:   "cpu",
				Labels: map[string]string{"host": "b"},
				Points: []mockPoint{
					{
						time.Date(2020, 1, 2, 3, 4, 0, 0, time.UTC), 4,
					},
					{
						time.Date(2020, 1, 2, 3, 5, 0, 0, time.UTC), 7,
					},
				},
			},
		},
	}

	frame := &data.Frame{Name: "Wide"}
	for i, series := range singleTimeIndexRes.Series {
		if i == 0 {
			frame.Fields = append(frame.Fields,
				data.NewField("time", nil, make([]time.Time, len(series.Points))),
			)
		}
		frame.Fields = append(frame.Fields,
			data.NewField(series.Name, series.Labels, make([]float64, len(series.Points))),
		)
		for pIdx, point := range series.Points {
			if i == 0 {
				frame.Set(i, pIdx, point.Time)
			}
			frame.Set(i+1, pIdx, point.Value)
		}
	}

	st, _ := frame.StringTable(-1, -1)
	fmt.Println(st)
}
Name: Wide
Dimensions: 3 Fields by 2 Rows
+-------------------------------+-----------------+-----------------+
| Name: time                    | Name: cpu       | Name: cpu       |
| Labels:                       | Labels: host=a  | Labels: host=b  |
| Type: []time.Time             | Type: []float64 | Type: []float64 |
+-------------------------------+-----------------+-----------------+
| 2020-01-02 03:04:00 +0000 UTC | 3               | 4               |
| 2020-01-02 03:05:00 +0000 UTC | 6               | 7               |
+-------------------------------+-----------------+-----------------+
Example (TableLikeLongTimeSeries)

Code:

package main

import (
	"fmt"
	"github.com/grafana/grafana-plugin-sdk-go/data"
	"time"
)

func main() {
	// a common SQL or CSV like pattern is to have repeated times, multiple numbered value
	// columns, and string columns to identify a factors. This is a "Long" time series.

	// Presently the backend supports converting Long formatted series to "Wide" format
	// which the frontend understands. Goal is frontend support eventually
	// (https://github.com/grafana/grafana/issues/22219).

	type aTable struct {
		Headers []string
		Rows    [][]interface{}
	}

	iSlice := func(is ...interface{}) []interface{} {
		s := make([]interface{}, len(is))
		copy(s, is)
		return s
	}

	myLongTable := aTable{
		Headers: []string{"time", "aMetric", "bMetric", "SomeFactor"},
	}
	myLongTable.Rows = append(myLongTable.Rows,
		iSlice(time.Date(2020, 1, 2, 3, 4, 0, 0, time.UTC), 2.0, 10.0, "foo"),
		iSlice(time.Date(2020, 1, 2, 3, 4, 0, 0, time.UTC), 5.0, 15.0, "bar"),

		iSlice(time.Date(2020, 1, 2, 3, 5, 0, 0, time.UTC), 3.0, 11.0, "foo"),
		iSlice(time.Date(2020, 1, 2, 3, 5, 0, 0, time.UTC), 6.0, 16.0, "bar"),
	)

	frame := data.NewFrameOfFieldTypes("Long", 0,
		data.FieldTypeTime,
		data.FieldTypeFloat64, data.FieldTypeFloat64,
		data.FieldTypeString,
	)
	_ = frame.SetFieldNames(myLongTable.Headers...)
	for _, row := range myLongTable.Rows {
		frame.AppendRow(row...)
	}
	st, _ := frame.StringTable(-1, -1)
	fmt.Println(st)
	w, _ := data.LongToWide(frame, nil)
	w.Name = "Wide"
	st, _ = w.StringTable(-1, -1)
	fmt.Println(st)
}
Name: Long
Dimensions: 4 Fields by 4 Rows
+-------------------------------+-----------------+-----------------+------------------+
| Name: time                    | Name: aMetric   | Name: bMetric   | Name: SomeFactor |
| Labels:                       | Labels:         | Labels:         | Labels:          |
| Type: []time.Time             | Type: []float64 | Type: []float64 | Type: []string   |
+-------------------------------+-----------------+-----------------+------------------+
| 2020-01-02 03:04:00 +0000 UTC | 2               | 10              | foo              |
| 2020-01-02 03:04:00 +0000 UTC | 5               | 15              | bar              |
| 2020-01-02 03:05:00 +0000 UTC | 3               | 11              | foo              |
| 2020-01-02 03:05:00 +0000 UTC | 6               | 16              | bar              |
+-------------------------------+-----------------+-----------------+------------------+

Name: Wide
Dimensions: 5 Fields by 2 Rows
+-------------------------------+------------------------+------------------------+------------------------+------------------------+
| Name: time                    | Name: aMetric          | Name: aMetric          | Name: bMetric          | Name: bMetric          |
| Labels:                       | Labels: SomeFactor=bar | Labels: SomeFactor=foo | Labels: SomeFactor=bar | Labels: SomeFactor=foo |
| Type: []time.Time             | Type: []float64        | Type: []float64        | Type: []float64        | Type: []float64        |
+-------------------------------+------------------------+------------------------+------------------------+------------------------+
| 2020-01-02 03:04:00 +0000 UTC | 5                      | 2                      | 15                     | 10                     |
| 2020-01-02 03:05:00 +0000 UTC | 6                      | 3                      | 16                     | 11                     |
+-------------------------------+------------------------+------------------------+------------------------+------------------------+

func LongToWide

func LongToWide(longFrame *Frame, fillMissing *FillMissing) (*Frame, error)

LongToWide converts a Long formated time series Frame to a Wide format (see TimeSeriesType for descriptions). The first Field of type time.Time or *time.Time will be the time index for the series, and will be the first field of the outputted longFrame.

During conversion: String Fields in the longFrame become Labels on the Fields of wideFrame. The name of each string Field becomes a label key, and the values of that Field become label values. Each unique combination of value Fields and set of Label key/values become a Field of longFrame.

Additionally, if the time index is a *time.Time field, it will become time.Time Field. If a *string Field has nil values, they are equivalent to "" when converted into labels.

Finally, the Meta field of the result Wide Frame is pointing to the reference of the Meta field of the input Long Frame.

An error is returned if any of the following are true: The input frame is not a long formated time series frame. The input frame's Fields are of length 0. The time index is not sorted ascending by time. The time index has null values.

With a conversion of Long to Wide, and then back to Long via WideToLong(), the outputted Long Frame may not match the original inputted Long frame.

func NewFrame

func NewFrame(name string, fields ...*Field) *Frame

NewFrame returns a new instance of a Frame.

Example

Code:

package main

import (
	"fmt"
	"github.com/grafana/grafana-plugin-sdk-go/data"
	"math"
	"time"
)

func main() {
	aTime := time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC)
	var anInt64 int64 = 12
	frame := data.NewFrame("Frame Name",
		data.NewField("Time", nil, []time.Time{aTime, aTime.Add(time.Minute)}),
		data.NewField("Temp", data.Labels{"place": "Ecuador"}, []float64{1, math.NaN()}),
		data.NewField("Count", data.Labels{"place": "Ecuador"}, []*int64{&anInt64, nil}),
	)
	st, _ := frame.StringTable(-1, -1)
	fmt.Println(st)
}
Name: Frame Name
Dimensions: 3 Fields by 2 Rows
+-------------------------------+-----------------------+-----------------------+
| Name: Time                    | Name: Temp            | Name: Count           |
| Labels:                       | Labels: place=Ecuador | Labels: place=Ecuador |
| Type: []time.Time             | Type: []float64       | Type: []*int64        |
+-------------------------------+-----------------------+-----------------------+
| 2020-01-02 03:04:05 +0000 UTC | 1                     | 12                    |
| 2020-01-02 03:05:05 +0000 UTC | NaN                   | null                  |
+-------------------------------+-----------------------+-----------------------+

func NewFrameOfFieldTypes

func NewFrameOfFieldTypes(name string, fieldLen int, fTypes ...FieldType) *Frame

NewFrameOfFieldTypes returns a Frame where the Fields are initialized to the corresponding field type in fTypes. Each Field will be of length FieldLen.

func UnmarshalArrowFrame

func UnmarshalArrowFrame(b []byte) (*Frame, error)

UnmarshalArrowFrame converts a byte representation of an arrow table to a Frame.

func WideToLong

func WideToLong(wideFrame *Frame) (*Frame, error)

WideToLong converts a Wide formated time series Frame to a Long formated time series Frame (see TimeSeriesType for descriptions). The first Field of type time.Time or *time.Time in wideFrame will be the time index for the series, and will be the first field of the outputted wideFrame.

During conversion: All the unique keys in all of the Labels across the Fields of wideFrame become string Fields with the corresponding name in longFrame. The corresponding Labels values become values in those Fields of longFrame. For each unique non-timeIndex Field across the Fields of wideFrame (value fields), a Field of the same type is created in longFrame. For each unique set of Labels across the Fields of wideFrame, a row is added to longFrame, and then for each unique value Field, the corresponding value Field of longFrame is set.

Finally, the Meta field of the result Long Frame is pointing to the reference of the Meta field of the input Wide Frame.

An error is returned if any of the following are true: The input frame is not a wide formated time series frame. The input row has no rows. The time index not sorted ascending by time. The time index has null values. Two numeric Fields have the same name but different types.

With a conversion of Wide to Long, and then back to Wide via LongToWide(), the outputted Wide Frame may not match the original inputted Wide frame.

func (*Frame) AppendNotices

func (f *Frame) AppendNotices(notices ...Notice)

AppendNotices adds notices to Frame f's metadata (Frame.Meta.Notices). If f has no metadata, this method will initialize it before adding notices.

func (*Frame) AppendRow

func (f *Frame) AppendRow(vals ...interface{})

AppendRow adds a new row to the Frame by appending to each element of vals to the corresponding Field in the data. The Frame's Fields must be initialized or AppendRow will panic. The number of arguments must match the number of Fields in the Frame and each type must coorespond to the Field type or AppendRow will panic.

func (*Frame) At

func (f *Frame) At(fieldIdx int, rowIdx int) interface{}

At returns the value of the specified fieldIdx and rowIdx. It will panic if either the fieldIdx or rowIdx are out of range.

func (*Frame) ConcreteAt

func (f *Frame) ConcreteAt(fieldIdx int, rowIdx int) (val interface{}, ok bool)

ConcreteAt returns the concrete value at the specified fieldIdx and rowIdx. A non-pointer type is returned regardless if the underlying type is a pointer type or not. If the value is a pointer type, and is nil, then the zero value is returned and ok will be false.

func (*Frame) CopyAt

func (f *Frame) CopyAt(fieldIdx int, rowIdx int) interface{}

CopyAt returns a copy of the value of the specified fieldIdx and rowIdx. It will panic if either the fieldIdx or rowIdx are out of range.

func (*Frame) DeleteRow

func (f *Frame) DeleteRow(rowIdx int)

DeleteRow deletes row at index rowIdx of the Frame. DeleteRow calls each field's Delete If idx is out of range, this method will panic.

func (*Frame) EmptyCopy

func (f *Frame) EmptyCopy() *Frame

EmptyCopy returns a copy of Frame f but with Fields of zero length, and no copy of the FieldConfigs, Metadata, or Warnings.

func (*Frame) Extend

func (f *Frame) Extend(i int)

Extend extends all the Fields by length by i.

func (*Frame) FilterRowsByField

func (f *Frame) FilterRowsByField(fieldIdx int, filter func(i interface{}) (bool, error)) (*Frame, error)

FilterRowsByField returns a copy of frame f (as per EmptyCopy()) that includes rows where the filter returns true and no error. If filter returns an error, then an error is returned.

func (*Frame) FloatAt

func (f *Frame) FloatAt(fieldIdx int, rowIdx int) (float64, error)

FloatAt returns a float64 representation of value of the specified fieldIdx and rowIdx as per Field.FloatAt(). It will panic if either the fieldIdx or rowIdx are out of range.

func (*Frame) InsertRow

func (f *Frame) InsertRow(rowIdx int, vals ...interface{})

InsertRow adds a row at index rowIdx of the Frame. InsertRow calls each field's Insert which extends the Field length by 1, shifts any existing field values at indices equal or greater to rowIdx by one place and inserts the corresponding val at index rowIdx of the Field. If rowIdx is equal to the Frame RowLen, then val will be appended. If rowIdx exceeds the Field length, this method will panic.

func (*Frame) MarshalArrow

func (f *Frame) MarshalArrow() ([]byte, error)

MarshalArrow converts the Frame to an arrow table and returns a byte representation of that table. All fields of a Frame must be of the same length or an error is returned.

func (*Frame) RowCopy

func (f *Frame) RowCopy(rowIdx int) []interface{}

RowCopy returns an interface slice that contains the values of each Field for the given rowIdx.

func (*Frame) RowLen

func (f *Frame) RowLen() (int, error)

RowLen returns the the length of the Frame Fields. If the Length of all the Fields is not the same then error is returned.

func (*Frame) Rows

func (f *Frame) Rows() int

Rows returns the number of rows in the frame.

func (*Frame) Set

func (f *Frame) Set(fieldIdx int, rowIdx int, val interface{})

Set sets the val at the specified fieldIdx and rowIdx. It will panic if either the fieldIdx or rowIdx are out of range or if the underlying type of val does not match the element type of the Field.

func (*Frame) SetConcrete

func (f *Frame) SetConcrete(fieldIdx int, rowIdx int, val interface{})

SetConcrete sets the val at the specified fieldIdx and rowIdx. val must be a non-pointer type or a panic will occur. If the underlying FieldType is nullable it will set val as a pointer to val. If the FieldType is not nullable, then this method behaves the same as the Set method. It will panic if the underlying type of val does not match the element concrete type of the Field.

func (*Frame) SetFieldNames

func (f *Frame) SetFieldNames(names ...string) error

SetFieldNames sets each Field Name in the frame to the corresponding frame. If the number of provided names does not match the number of Fields in the frame an error is returned.

func (*Frame) SetMeta

func (f *Frame) SetMeta(m *FrameMeta) *Frame

SetMeta modifies the Frame's Meta Property to be set to m and returns the Frame.

func (*Frame) SetRow

func (f *Frame) SetRow(rowIdx int, vals ...interface{})

SetRow sets vals at the index rowIdx of the Frame. SetRow calls each field's Set which sets the Field's value at index idx to val.

func (*Frame) StringTable

func (f *Frame) StringTable(maxFields, maxRows int) (string, error)

StringTable prints a human readable table of the Frame. The output should not be used for programtic consumption or testing. The table's width is limited to maxFields and the length is limited to maxRows (a value of -1 is unlimited). If the width or length is excceded then last column or row displays "..." as the contents.

func (*Frame) TimeSeriesSchema

func (f *Frame) TimeSeriesSchema() (tsSchema TimeSeriesSchema)

TimeSeriesSchema returns the TimeSeriesSchema of the frame. The TimeSeriesSchema's Type value will be TimeSeriesNot if it is not a time series.

func (*Frame) TypeIndices

func (f *Frame) TypeIndices(fTypes ...FieldType) []int

TypeIndices returns a slice of Field index positions for the given fTypes.

type FrameInputConverter

type FrameInputConverter struct {
	Frame *Frame
	// contains filtered or unexported fields
}

FrameInputConverter is a type to support building a Frame while also doing conversion as data is added to the Frame.

func NewFrameInputConverter

func NewFrameInputConverter(fieldConvs []FieldConverter, rowLen int) (*FrameInputConverter, error)

NewFrameInputConverter returns a FrameInputConverter which is used to create a Frame from data that needs value conversions. The FrameInputConverter will create a new Frame with fields based on the FieldConverters' OutputFieldTypes of length rowLen.

Example

Code:

package main

import (
	"fmt"
	"github.com/grafana/grafana-plugin-sdk-go/data"
	"log"
	"strconv"
	"time"
)

func main() {
	inputData := struct { // inputData is a pretend table-like structure response from an API.
		ColumnTypes []string
		ColumnNames []string
		Rows        [][]string
	}{
		[]string{
			"Stringz",
			"Floatz",
			"Timez",
		},
		[]string{
			"Animal",
			"Weight (lbs)",
			"Time",
		},
		[][]string{
			{"sloth", "3.5", "1586014367"},
			{"sloth", "5.5", "1586100767"},
			{"sloth", "7", "1586187167"},
		},
	}

	// Build field converters appropriate for converting out pretend data structure.
	stringzFieldConverter := data.FieldConverter{
		OutputFieldType: data.FieldTypeString,
		// No Converter, string = string
	}
	floatzFieldConverter := data.FieldConverter{ // a converter appropriate for our pretend API's Floatz type.
		OutputFieldType: data.FieldTypeFloat64,
		Converter: func(v interface{}) (interface{}, error) {
			val, ok := v.(string)
			if !ok { // or return some default value instead of erroring
				return nil, fmt.Errorf("expected string input but got type %T", v)
			}
			return strconv.ParseFloat(val, 64)
		},
	}
	timezFieldConverter := data.FieldConverter{ // a converter appropriate for our pretend API's Timez type.
		OutputFieldType: data.FieldTypeTime,
		Converter: func(v interface{}) (interface{}, error) {
			val, ok := v.(string)
			if !ok { // or return some default value instead of erroring
				return nil, fmt.Errorf("expected string input but got type %T", v)
			}
			iV, err := strconv.ParseInt(val, 10, 64)
			if err != nil {
				return nil, fmt.Errorf("could not parse epoch time into an int64")
			}
			return time.Unix(iV, 0).UTC(), nil
		},
	}

	// a map of pretend API's types to converters
	converterMap := map[string]data.FieldConverter{
		"Stringz": stringzFieldConverter,
		"Floatz":  floatzFieldConverter,
		"Timez":   timezFieldConverter,
	}

	// build a slice of converters for Pretend API known types in the appropriate Field/Column order
	// for this specific response.
	converters := make([]data.FieldConverter, len(inputData.ColumnTypes))
	for i, cType := range inputData.ColumnTypes {
		fc, ok := converterMap[cType]
		if !ok {
			fc = data.AsStringFieldConverter
		}
		converters[i] = fc
	}

	// Get a new FrameInputConverter, which includes a Frame with appropriate Field types and length
	// for out input data.
	convBuilder, err := data.NewFrameInputConverter(converters, len(inputData.Rows))
	if err != nil {
		log.Fatal(err)
	}

	// Set field names
	err = convBuilder.Frame.SetFieldNames(inputData.ColumnNames...)
	if err != nil {
		log.Fatal(err)
	}

	// Insert data into the frame, passing data through the Converters before
	// writing to the frame.
	for rowIdx, row := range inputData.Rows {
		for fieldIdx, cell := range row {
			err = convBuilder.Set(fieldIdx, rowIdx, cell)
			if err != nil {
				log.Fatal(err)
			}
		}
	}
	convBuilder.Frame.Name = "Converted"

	st, _ := convBuilder.Frame.StringTable(-1, -1)
	fmt.Println(st)

}
Name: Converted
Dimensions: 3 Fields by 3 Rows
+----------------+--------------------+-------------------------------+
| Name: Animal   | Name: Weight (lbs) | Name: Time                    |
| Labels:        | Labels:            | Labels:                       |
| Type: []string | Type: []float64    | Type: []time.Time             |
+----------------+--------------------+-------------------------------+
| sloth          | 3.5                | 2020-04-04 15:32:47 +0000 UTC |
| sloth          | 5.5                | 2020-04-05 15:32:47 +0000 UTC |
| sloth          | 7                  | 2020-04-06 15:32:47 +0000 UTC |
+----------------+--------------------+-------------------------------+

func (*FrameInputConverter) Set

func (fic *FrameInputConverter) Set(fieldIdx, rowIdx int, val interface{}) error

Set sets val a FieldIdx and rowIdx of the frame. If the corresponding FieldConverter's Converter is not nil, then the Converter function is called before setting the value (otherwise Frame.Set is called directly). If an error is returned from the Converter function this function returns that error. Like Frame.Set and Field.Set, it will panic if fieldIdx or rowIdx are out of range.

type FrameMeta

type FrameMeta struct {
	// Datasource specific values
	Custom interface{} `json:"custom,omitempty"`

	// Stats is an array of query result statistics.
	Stats []QueryStat `json:"stats,omitempty"`

	// Notices provide additional information about the data in the Frame that
	// Grafana can display to the user in the user interface.
	Notices []Notice `json:"notices,omitempty"`

	// PreferredVisualisationType is currently used to show results in Explore only in preferred visualisation option.
	PreferredVisualization VisType `json:"preferredVisualisationType,omitempty"`

	// ExecutedQueryString is the raw query sent to the underlying system. All macros and templating
	// have been applied.  When metadata contains this value, it will be shown in the query inspector.
	ExecutedQueryString string `json:"executedQueryString,omitempty"`
}

FrameMeta matches: 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 this interface only exposes the values we want to be exposed

func FrameMetaFromJSON

func FrameMetaFromJSON(jsonStr string) (*FrameMeta, error)

FrameMetaFromJSON creates a QueryResultMeta from a json string

type Frames

type Frames []*Frame

Frames is a slice of Frame pointers. It is the main data container within a backend.DataResponse.

func UnmarshalArrowFrames

func UnmarshalArrowFrames(bFrames [][]byte) (Frames, error)

UnmarshalArrowFrames decodes a slice of Arrow encoded frames to Frames ([]*Frame) by calling the UnmarshalArrow function on each encoded frame. If an error occurs Frames will be nil. See Frames.UnMarshalArrow() for the inverse operation.

func (Frames) MarshalArrow

func (frames Frames) MarshalArrow() ([][]byte, error)

MarshalArrow encodes Frames into a slice of []byte using *Frame's MarshalArrow method on each Frame. If an error occurs [][]byte will be nil. See UnmarshalArrowFrames for the inverse operation.

type InspectType

type InspectType int

InspectType is a type for the Inspect property of a Notice.

const (
	// InspectTypeNone is no suggestion for a tab of the panel editor in Grafana's user interface.
	InspectTypeNone InspectType = iota

	// InspectTypeMeta suggests the "meta" tab of the panel editor in Grafana's user interface.
	InspectTypeMeta

	// InspectTypeError suggests the "error" tab of the panel editor in Grafana's user interface.
	InspectTypeError

	// InspectTypeData suggests the "data" tab of the panel editor in Grafana's user interface.
	InspectTypeData

	// InspectTypeStats suggests the "stats" tab of the panel editor in Grafana's user interface.
	InspectTypeStats
)

func (InspectType) String

func (n InspectType) String() string

type Labels

type Labels map[string]string

Labels are used to add metadata to an object.

func LabelsFromString

func LabelsFromString(s string) (Labels, error)

LabelsFromString parses the output of Labels.String() into a Labels object. It probably has some flaws.

func (Labels) Contains

func (l Labels) Contains(arg Labels) bool

Contains returns true if all k=v pairs of the argument are in the receiver.

func (Labels) Copy

func (l Labels) Copy() Labels

Copy returns a copy of the labels.

func (Labels) Equals

func (l Labels) Equals(arg Labels) bool

Equals returns true if the argument has the same k=v pairs as the receiver.

func (Labels) String

func (l Labels) String() string

type MappingType

type MappingType int8

MappingType value or range

const (
	// ValueToText map a value to text
	ValueToText MappingType = iota + 1

	// RangeToText map a range to text
	RangeToText
)

type Notice

type Notice struct {
	// Severity is the severity level of the notice: info, warning, or error.
	Severity NoticeSeverity `json:"severity,omitempty"`

	// Text is freeform descriptive text for the notice.
	Text string `json:"text"`

	// Link is an optional link for display in the user interface and can be an
	// absolute URL or a path relative to Grafana's root url.
	Link string `json:"link,omitempty"`

	// Inspect is an optional suggestion for which tab to display in the panel inspector
	// in Grafana's User interface. Can be meta, error, data, or stats.
	Inspect InspectType `json:"inspect,omitempty"`
}

Notice provides a structure for presenting notifications in Grafana's user interface.

type NoticeSeverity

type NoticeSeverity int

NoticeSeverity is a type for the Severity property of a Notice.

const (
	// NoticeSeverityInfo is informational severity.
	NoticeSeverityInfo NoticeSeverity = iota

	// NoticeSeverityWarning is warning severity.
	NoticeSeverityWarning

	// NoticeSeverityError is error severity.
	NoticeSeverityError
)

func (NoticeSeverity) MarshalJSON

func (n NoticeSeverity) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface.

func (NoticeSeverity) String

func (n NoticeSeverity) String() string

func (*NoticeSeverity) UnmarshalJSON

func (n *NoticeSeverity) UnmarshalJSON(b []byte) error

UnmarshalJSON implements the json.Unmarshaler interface.

type NullValueMode

type NullValueMode string

NullValueMode say how the UI should show null values

const (
	// NullValueModeNull displays null values
	NullValueModeNull NullValueMode = "null"
	// NullValueModeIgnore sets the display to ignore null values
	NullValueModeIgnore NullValueMode = "connected"
	// NullValueModeAsZero set the display show null values as zero
	NullValueModeAsZero NullValueMode = "null as zero"
)

type QueryStat

type QueryStat struct {
	FieldConfig

	Value float64 `json:"value"`
}

QueryStat is used for storing arbitrary statistics metadata related to a query and its result, e.g. total request time, data processing time. The embedded FieldConfig's display name must be set. It corresponds to the QueryResultMetaStat on the frontend (https://github.com/grafana/grafana/blob/master/packages/grafana-data/src/types/data.ts#L53).

type Threshold

type Threshold struct {
	Value ConfFloat64 `json:"value,omitempty"` // First value is always -Infinity serialize to null
	Color string      `json:"color,omitempty"`
	State string      `json:"state,omitempty"`
}

Threshold a single step on the threshold list

func NewThreshold

func NewThreshold(value float64, color, state string) Threshold

NewThreshold Creates a new Threshold object

type ThresholdsConfig

type ThresholdsConfig struct {
	Mode ThresholdsMode `json:"mode"`

	// Must be sorted by 'value', first value is always -Infinity
	Steps []Threshold `json:"steps"`
}

ThresholdsConfig setup thresholds

type ThresholdsMode

type ThresholdsMode string

ThresholdsMode absolute or percentage

const (
	// ThresholdsModeAbsolute pick thresholds based on absolute value
	ThresholdsModeAbsolute ThresholdsMode = "absolute"

	// ThresholdsModePercentage the threshold is relative to min/max
	ThresholdsModePercentage ThresholdsMode = "percentage"
)

type TimeSeriesSchema

type TimeSeriesSchema struct {
	Type           TimeSeriesType // the type of series, as determinted by frame.TimeSeriesSchema()
	TimeIndex      int            // Field index of the time series index
	TimeIsNullable bool           // true if the time index is nullable (of *time.Time)
	ValueIndices   []int          // Field indices of value columns (All fields excluding string fields and the time index)
	FactorIndices  []int          // Field indices of string or *string Fields
}

TimeSeriesSchema is information about a Frame's schema. It is populated from the Frame's TimeSeriesSchema() method.

type TimeSeriesType

type TimeSeriesType int

TimeSeriesType represents the type of time series the schema can be treated as (if any).

const (
	// TimeSeriesTypeNot means this Frame is not a valid time series. This means it lacks at least
	// one of a time Field and another (value) Field.
	TimeSeriesTypeNot TimeSeriesType = iota

	// TimeSeriesTypeLong means this Frame can be treated as a "Long" time series.
	//
	// A Long series has one or more string Fields, disregards Labels on Fields, and generally
	// repeated time values in the time index.
	TimeSeriesTypeLong

	// TimeSeriesTypeWide means this Frame can be treated as a "Wide" time series.
	//
	// A Wide series has no string fields, should not have repeated time values, and generally
	// uses labels.
	TimeSeriesTypeWide
)

TODO: Create and link to Grafana documentation on Long vs Wide

func (TimeSeriesType) String

func (t TimeSeriesType) String() string

type ValueMapping

type ValueMapping struct {
	ID       int16       `json:"id"`
	Operator string      `json:"operator"`
	Text     string      `json:"title"`
	Type     MappingType `json:"type"`

	// Only valid for MappingType == ValueMap
	Value string `json:"value,omitempty"`

	// Only valid for MappingType == RangeMap
	From string `json:"from,omitempty"`
	To   string `json:"to,omitempty"`
}

ValueMapping convert input value to something else

type VisType

type VisType string

VisType is used to indicate how the data should be visualized in explore.

Package Files

Documentation was rendered with GOOS=linux and GOARCH=amd64.

Jump to identifier

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to identifier