Giter Club home page Giter Club logo

grafana-simple-grpc-datasource's Introduction

Grafana Simple gRPC Datasource Plugin

GitHub release (latest by date) Marketplace Downloads

What is this plugin?

This back-end Grafana datasource plugin provides a user-friendly grafana experience with only a handful simple and generic parameters to configure. It comes with a dedicated API specification that requires implementation in the data provider's back-end. Implementing this API helps to decouple the front-end visualisation solution from the back-end data-layer implementation, leaving developers with the necessary freedom to update and improve the back-end without breaking the end-user experience.

The protobuf API specification can be found in the pkg/proto directory. On configuring the datasource plugin, the end-user provides an endpoint URL and optionally an API key too. The datasource will attempt to establish a gRPC connection and emit calls to the given endpoint according to the API specification.

For more information on gRPC or protobuf, see the gRPC docs.

Why gRPC?

gRPC is a fast & efficient framework for inter-service communication and provides a fool-proof and streamlined workflow for API implementation through protobuf.

gRPC also supports all essential streaming capabilities, which can be implemented in future releases.

Security

The datasource plugin establishes a secure gRPC connection through TLS. Additionally, the datasource supports API-key authorization. The API-key will be included in each API call as part of the call metadata.

Usage

screenshot

Metric

The variable that is updated with new values as the stream of timeseries datapoints is appended.

Dimension

A dimension is an optional, identifying property of the measure. Each dimension is modeled as a key-value pair. A measure can have zero or many dimensions that collectively uniquely identify it.

Query Type

type description
Get Metric History gets historical timeseries values
Get Metric Aggregate gets aggregated timeseries
Get Metric Value gets the last known value

Getting started

  1. start a sample grpc server locally:
docker run -p 50051:50051 innius/sample-grpc-server
  1. install the innius-simple-grpc-datasource

  2. enable the datasource

    • configure the endpoint localhost:50051
  3. configure dashboards

Implement your own backend API

This datasource plugin expects a backend to implement the Simple or the Advanced interface.

The Simple API (GrafanaQueryAPI)

This API provides the following operations:

name description
ListDimensionKeys Returns a list of all available dimension keys
ListDimensionValues Returns a list of all available dimension values of a dimension key
ListMetrics Returns a list of all metrics for a combination of dimensions.
GetMetricValue Returns the last known value of a metric.
GetMetricHistory Returns historical values of a metric
GetMetricAggregate Returns aggregated metric values

A sample implementation can be found here.

This API has some limitations:

  • it only supports one metric per query
  • it does not support variables with multiple options
  • it does not support enhanced metadata for metrics (like unit, etc.)
  • it does not support flexible query options

The Advanced API (GrafanaQueryAPIV3)

This API provides almost the same operations as the Simple API but with one major difference: it supports multiple metrics for the same query. As a result this API integrates seamlessly with grafana templating capabilities. In addition, it supports enhanced metric metadata, like unit of measure. Another difference is that it supports grafana labels.

The advanced API supports dynamic query options which are defined by the backend system. This makes it possible to tailor the behavior of grafana queries for specific backends. An example of a custom option is the Aggregate of the GetMetricAggregate query. The v1 version of the API has a fixed number of Aggregates, defined by the plugin. It is not possible for a backend system to add a different option. With the V3 API, however, this is supported. Currently an option can be either an Enumeration or a Boolean type.

This API provides the following operations:

name description
ListDimensionKeys Returns a list of all available dimension keys
ListDimensionValues Returns a list of all available dimension values of a dimension key
ListMetrics Returns a list of all metrics for a combination of dimensions.
GetMetricValue Returns the last known value for one or more metrics.
GetMetricHistory Returns historical values for one or more metrics
GetMetricAggregate Returns aggregated values for one or more metrics
GetQueryOptions Returns the options for a selected query type

A sample implementation can be found here.

Example Use Cases:

  • different time series for the same metric with different labels. For example: the temperature measure is a room. The room has four zones: north, south, east and west. The V1 API does not support this unless there are four different metrics defined for each temperature / zone combination. The Advanced API does support this scenario by returning multiple time series for the same metric temperature, each annotated with different label zone.
  • different time series for different metrics. For example: a room has multiple temperature sensors. The V1 API supports this by defining multiple queries for each metric. The Advanced API can do this with a single query.

Important Note: in order to use the Advanced API the backend server needs to support gRPC Reflection. The plugin uses this to determine if a backend supports the V2 or V3 protocol. If not supported it falls back on the Simple API implementation.

Please note gRPC is programming language agnostic which makes it possible to implement a backend in the language of your choice. Checkout the gRPC documentation of your language.

Changes between (GrafanaQueryAPIV2) and (GravanaQueryAPIV3)

The most important difference is that the Aggregate types of the V2 API are not available by the V3 API unless they are defined in the backend.

The backend code has to implement something like this:

const (
    // this id is important because it matches the current v2 aggregate type option 
	AggregationTypeOptionID = iota
    // these enum values are important because they match the values of the V2 options 
	AggregationTypeAverage = 0
	AggregationTypeMax     = 1
	AggregationTypeMin     = 2
	AggregationTypeCount   = 3
)


func (backend *BackendServerV3) GetQueryOptions(ctx context.Context, in *v3.GetOptionsRequest) (*v3.GetOptionsResponse, error) {
	var Options []*v3.Option
	switch in.GetQueryType() {
	case v3.GetOptionsRequest_GetMetricAggregate:
		Options = append(Options, []*v3.Option{
			{
				Id:          strconv.Itoa(AggregationTypeOptionID),
				Label:       "Aggregate",
				Description: "Aggregate the query results",
				Type:        v3.Option_Enum,
				EnumValues: []*v3.EnumValue{
					{Label: "Average", Description: "Calculate the average of the values", Id: strconv.Itoa(AggregationTypeAverage)},
					{Label: "Min", Description: "Calculate the minimum of the values", Id: strconv.Itoa(AggregationTypeMin)},
					{Label: "Max", Description: "Calculate the maximum of the values", Id: strconv.Itoa(AggregationTypeMax)},
					{Label: "Count", Description: "Calculate the sum of the values", Id: strconv.Itoa(AggregationTypeCount)},
				},
			},
		}...)
	case v3.GetOptionsRequest_GetMetricValue:
        return &v3.GetOptionsResponse{}, nil
	case v3.GetOptionsRequest_GetMetricHistory:
        return &v3.GetOptionsResponse{}, nil
	}
	return &v3.GetOptionsResponse{Options: Options}, nil
}

A sample implementation of the V3 backend can be found here

Features

  • select multiple metrics in one query
  • flexible dimension selection
  • integrated with Grafana variables and templating
  • allow backend systems to provided additional metadata, like value mappings, unit of measure, etc.
  • supports notifications
  • supports pagination
  • supports retries for grpc calls if backend server is at maximum capacity
  • allow backend systems to define custom query options.

Roadmap

  • support annotations
  • support streaming queries

grafana-simple-grpc-datasource's People

Contributors

bmo-at avatar rvdwijngaard avatar wolfwfr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

grafana-simple-grpc-datasource's Issues

Expression as alert input

Hi,

I'm currently deploying your plugin, and it works like a charm. However, it's impossible to use an expression as an input to generate an alert. this is the displayed error : The datasource does not support alerting queries.

Would it be possible to implement this capability ?

Regards,

Fabien

Too many strings in API V2 responses

Hello, love the library so far!

Looking over the V2 API, I noticed that it's sending a lot of strings per response, and I'm concerned about efficiency and bandwidth.

For each Frame, the response includes the metric name and a collection of Fields. Each field also includes the name (I assume the metric name), and associated labels, config (which is unit of measure - also a string), and the value. That means that per data value I'm sending any number of strings (a name, a config, and an unbounded number of label keys and values).

Off the cuff, may I suggest something like:

message GetMetricValueResponse {
  repeated SingleValueField fields = 1;
}

message GetMetricHistoryResponse {
  repeated Field fields = 1;
}

message Sample {
  google.protobuf.Timestamp timestamp = 1;
  double value = 2;
}

message Field {
  string metric = 1;
  repeated Label labels = 2;
  repeated Sample data = 3;
}

// Or just reuse Field, with a single entry in 'data'
message SingleValueField {
  string metric = 1;
  repeated Label labels = 2;
  Sample data = 3;
}

I'd also suggest moving config entirely into the metric definition; that is, part of the ListMetricsResponse.Metric message.

Multiple values per unit time

Hi!

So I've been using your plugin to display data from our API, with a gRPC endpoint that I wrote according to the protobuf file.
One limitation I have come across is that given any metric, you can only ever return one value per timestamp.
The reason this is a limitation is that some APIs including ours return mutliple different datapoints per timestamp.
Consider the following use case:
An API that returns the state of webrequests. So for a given time span and a resolution it returns e.g. 5 minute buckets in which a set of http status codes might have occured, the corresponding data in JSON might look like this:

{ 
    "points": [
        {
            "timestamp": 1637155203278,
            "data": {
                "200": 589,
                "404": 23,
                ...
            }
        }, 
        {
            "timestamp": 1637154903278,
            "data": {
                "200": 367,
                "404": 16,
                "500": 4,
                ...
            }
        },
        ...
    ]
}

Now I'd like to send that over grpc and ideally have the plugin accept an ID of some sort (probably a string) in a MetricValue so that instead of the table view looking like this:
image
It could look like this:
image

One way around this would be to add queries for every status code but that would be a lot and making an exhaustive list isn't fun.
With a few changes to the proto file and the backend server I managed to get this running on my fork.
The question is, is there any will to consider this change? I'd be providing an implementation of it to merge upstream, if the change is welcome.

Greetings,
Jan-Robin Aumann

Filter for dimension values not refreshing for dashboard variable

Thanks for a great plugin, and I really like the new feature with dashboard variables for dimensions.

I use a dimension with a high number of values, and I return a limited number of values in ListDimensionValues. This works perfectly in the query editor where it calls ListDimensionValues on every filter change. But this is not the behavior in the dashboard variable for dimension, where is only calls ListDimensionValues initially on not on any filter change. Then the filter only works for the reduced values I returned in the first place.

Is it feasible to get this refreshed on every filter change?

[Suggestion] Send back already selected dimension keys/values as part of a ListDimensionKeysRequest/ListDimensionValuesRequest

Sometimes one might want to tailor the available dimensions or their values to what has already been selected.
For example, if the user has already selected a value for a dimension that the they should not be able to select twice, we might want to take that dimension out of the response for the next request. But currently, there is no way to know which dimensions the user has already selected.

Empty Metric in Explore from Dashboard

Summary

Activating Explore from a dashboard panel opens the Explore window with correct query configuration except that the Metric field shows empty metrics.

Screenshot from 2022-08-23 11-25-55

Steps to reproduce

  1. Configure a dashboard with a variable for metrics.
  2. Configure the datasource with this variable
  3. Refresh the dashboard and select Explore from the panel

dashboard.tar.gz

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.