Add a query router or multiplexer to your data source backend
Normally you implement the QueryData
method in your backend plugin for data queries. But what if you need to support different kinds of queries: metrics, logs, and traces, for instance? That’s where the usage of a query router (also known as a multiplexer) comes handy.
The plugin development requirement is that you need to populate the queryType
property of your query model client-side, see the DataQuery
interface.
With queryType
populated in queries and sent to your backend plugin below is an example of how you would use the datasource.QueryTypeMux
to multiplex or route different query types to separate query handlers.
Implemented in this way, each query handler can then json.Unmarshal
each query JSON field in DataQuery
to a certain Go struct as shown in this example:
package mydatasource
import (
"context"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
)
type MyDatasource struct {
queryHandler backend.QueryDataHandler
}
func New() *MyDatasource {
ds := &MyDatasource{}
queryTypeMux := datasource.NewQueryTypeMux()
queryTypeMux.HandleFunc("metrics", ds.handleMetricsQuery)
queryTypeMux.HandleFunc("logs", ds.handleLogsQuery)
queryTypeMux.HandleFunc("traces", ds.handleTracesQuery)
queryTypeMux.HandleFunc("", ds.handleQueryFallback)
ds.queryHandler := queryTypeMux
return ds
}
func (d *MyDatasource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
return d.queryHandler.QueryData(ctx, req)
}
// handleMetricsQuery handle queries of query type "metrics".
// All queries in backend.QueryDataRequest is guaranteed to only
// include queries with queryType "metrics".
func (d *MyDatasource) handleMetricsQuery(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
// implementation...
}
// handleLogsQuery handle queries of query type "logs".
// All queries in backend.QueryDataRequest is guaranteed to only
// include queries with queryType "logs".
func (d *MyDatasource) handleLogsQuery(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
// implementation...
}
// handleTracesQuery handle queries of query type "logs".
// All queries in backend.QueryDataRequest is guaranteed to only
// include queries with queryType "traces".
func (d *MyDatasource) handleTracesQuery(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
// implementation...
}
// handleQueryFallback handle queries without a matching query type handler registered.
func (d *MyDatasource) handleQueryFallback(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
// implementation...
}
Advanced usage​
An example of using QueryTypeMux
can be found for Grafana's built-in TestData data source. Refer to this code for examples of implementation:
- create query type multiplexer and calls registerScenarios
- registerScenarios method uses a helper method to register each query type handler. The latter also shows how you can wrap the actual handler in another handler to apply common functionality or middleware to all handlers. For example, logging and traces.