Introduce TSDB service (#31520)

* Introduce TSDB service

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

Co-authored-by: Erik Sundell <erik.sundell87@gmail.com>
Co-authored-by: Will Browne <will.browne@grafana.com>
Co-authored-by: Torkel Ödegaard <torkel@grafana.org>
Co-authored-by: Will Browne <wbrowne@users.noreply.github.com>
Co-authored-by: Zoltán Bedi <zoltan.bedi@gmail.com>
This commit is contained in:
Arve Knudsen
2021-03-08 07:02:49 +01:00
committed by GitHub
co-authored by Erik Sundell Will Browne Torkel Ödegaard Will Browne Zoltán Bedi
parent c899bf3592
commit b79e61656a
203 changed files with 5269 additions and 4776 deletions
+13 -12
View File
@@ -4,24 +4,25 @@ import (
"context"
"strings"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/plugins"
)
func (e *CloudMonitoringExecutor) executeAnnotationQuery(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
result := &tsdb.Response{
Results: make(map[string]*tsdb.QueryResult),
func (e *Executor) executeAnnotationQuery(ctx context.Context, tsdbQuery plugins.DataQuery) (
plugins.DataResponse, error) {
result := plugins.DataResponse{
Results: make(map[string]plugins.DataQueryResult),
}
firstQuery := tsdbQuery.Queries[0]
queries, err := e.buildQueryExecutors(tsdbQuery)
if err != nil {
return nil, err
return plugins.DataResponse{}, err
}
queryRes, resp, _, err := queries[0].run(ctx, tsdbQuery, e)
if err != nil {
return nil, err
return plugins.DataResponse{}, err
}
metricQuery := firstQuery.Model.Get("metricQuery")
@@ -29,16 +30,16 @@ func (e *CloudMonitoringExecutor) executeAnnotationQuery(ctx context.Context, ts
text := metricQuery.Get("text").MustString()
tags := metricQuery.Get("tags").MustString()
err = queries[0].parseToAnnotations(queryRes, resp, title, text, tags)
result.Results[firstQuery.RefId] = queryRes
err = queries[0].parseToAnnotations(&queryRes, resp, title, text, tags)
result.Results[firstQuery.RefID] = queryRes
return result, err
}
func transformAnnotationToTable(data []map[string]string, result *tsdb.QueryResult) {
table := &tsdb.Table{
Columns: make([]tsdb.TableColumn, 4),
Rows: make([]tsdb.RowValues, 0),
func transformAnnotationToTable(data []map[string]string, result *plugins.DataQueryResult) {
table := plugins.DataTable{
Columns: make([]plugins.DataTableColumn, 4),
Rows: make([]plugins.DataRowValues, 0),
}
table.Columns[0].Text = "time"
table.Columns[1].Text = "title"
@@ -4,23 +4,25 @@ import (
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/plugins"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestCloudMonitoringExecutor_parseToAnnotations(t *testing.T) {
func TestExecutor_parseToAnnotations(t *testing.T) {
d, err := loadTestFile("./test-data/2-series-response-no-agg.json")
require.NoError(t, err)
require.Len(t, d.TimeSeries, 3)
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "annotationQuery"}
res := &plugins.DataQueryResult{Meta: simplejson.New(), RefID: "annotationQuery"}
query := &cloudMonitoringTimeSeriesFilter{}
err = query.parseToAnnotations(res, d, "atitle {{metric.label.instance_name}} {{metric.value}}", "atext {{resource.label.zone}}", "atag")
err = query.parseToAnnotations(res, d, "atitle {{metric.label.instance_name}} {{metric.value}}",
"atext {{resource.label.zone}}", "atag")
require.NoError(t, err)
decoded, _ := res.Dataframes.Decoded()
decoded, err := res.Dataframes.Decoded()
require.NoError(t, err)
require.Len(t, decoded, 3)
assert.Equal(t, "title", decoded[0].Fields[1].Name)
assert.Equal(t, "tags", decoded[0].Fields[2].Name)
@@ -28,7 +30,7 @@ func TestCloudMonitoringExecutor_parseToAnnotations(t *testing.T) {
}
func TestCloudMonitoringExecutor_parseToAnnotations_emptyTimeSeries(t *testing.T) {
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "annotationQuery"}
res := &plugins.DataQueryResult{Meta: simplejson.New(), RefID: "annotationQuery"}
query := &cloudMonitoringTimeSeriesFilter{}
response := cloudMonitoringResponse{
@@ -38,12 +40,13 @@ func TestCloudMonitoringExecutor_parseToAnnotations_emptyTimeSeries(t *testing.T
err := query.parseToAnnotations(res, response, "atitle", "atext", "atag")
require.NoError(t, err)
decoded, _ := res.Dataframes.Decoded()
decoded, err := res.Dataframes.Decoded()
require.NoError(t, err)
require.Len(t, decoded, 0)
}
func TestCloudMonitoringExecutor_parseToAnnotations_noPointsInSeries(t *testing.T) {
res := &tsdb.QueryResult{Meta: simplejson.New(), RefId: "annotationQuery"}
res := &plugins.DataQueryResult{Meta: simplejson.New(), RefID: "annotationQuery"}
query := &cloudMonitoringTimeSeriesFilter{}
response := cloudMonitoringResponse{
+66 -41
View File
@@ -16,14 +16,16 @@ import (
"strings"
"time"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/manager"
"github.com/grafana/grafana/pkg/registry"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/api/pluginproxy"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb"
"golang.org/x/oauth2/google"
)
@@ -62,20 +64,35 @@ const (
mqlEditorMode string = "mql"
)
// CloudMonitoringExecutor executes queries for the CloudMonitoring datasource
type CloudMonitoringExecutor struct {
func init() {
registry.Register(&registry.Descriptor{
Name: "CloudMonitoringService",
InitPriority: registry.Low,
Instance: &Service{},
})
}
type Service struct {
}
func (s *Service) Init() error {
return nil
}
// Executor executes queries for the CloudMonitoring datasource.
type Executor struct {
httpClient *http.Client
dsInfo *models.DataSource
}
// NewCloudMonitoringExecutor initializes a http client
func NewCloudMonitoringExecutor(dsInfo *models.DataSource) (tsdb.TsdbQueryEndpoint, error) {
// NewExecutor returns an Executor.
func (s *Service) NewExecutor(dsInfo *models.DataSource) (plugins.DataPlugin, error) {
httpClient, err := dsInfo.GetHttpClient()
if err != nil {
return nil, err
}
return &CloudMonitoringExecutor{
return &Executor{
httpClient: httpClient,
dsInfo: dsInfo,
}, nil
@@ -83,14 +100,14 @@ func NewCloudMonitoringExecutor(dsInfo *models.DataSource) (tsdb.TsdbQueryEndpoi
func init() {
slog = log.New("tsdb.cloudMonitoring")
tsdb.RegisterTsdbQueryEndpoint("stackdriver", NewCloudMonitoringExecutor)
}
// Query takes in the frontend queries, parses them into the CloudMonitoring query format
// executes the queries against the CloudMonitoring API and parses the response into
// the time series or table format
func (e *CloudMonitoringExecutor) Query(ctx context.Context, dsInfo *models.DataSource, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
var result *tsdb.Response
func (e *Executor) DataQuery(ctx context.Context, dsInfo *models.DataSource, tsdbQuery plugins.DataQuery) (
plugins.DataResponse, error) {
var result plugins.DataResponse
var err error
queryType := tsdbQuery.Queries[0].Model.Get("type").MustString("")
@@ -108,32 +125,34 @@ func (e *CloudMonitoringExecutor) Query(ctx context.Context, dsInfo *models.Data
return result, err
}
func (e *CloudMonitoringExecutor) getGCEDefaultProject(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
result := &tsdb.Response{
Results: make(map[string]*tsdb.QueryResult),
func (e *Executor) getGCEDefaultProject(ctx context.Context, tsdbQuery plugins.DataQuery) (plugins.DataResponse, error) {
result := plugins.DataResponse{
Results: make(map[string]plugins.DataQueryResult),
}
refId := tsdbQuery.Queries[0].RefId
queryResult := &tsdb.QueryResult{Meta: simplejson.New(), RefId: refId}
refID := tsdbQuery.Queries[0].RefID
queryResult := plugins.DataQueryResult{Meta: simplejson.New(), RefID: refID}
gceDefaultProject, err := e.getDefaultProject(ctx)
if err != nil {
return nil, fmt.Errorf("failed to retrieve default project from GCE metadata server, error: %w", err)
return plugins.DataResponse{}, fmt.Errorf(
"failed to retrieve default project from GCE metadata server, error: %w", err)
}
queryResult.Meta.Set("defaultProject", gceDefaultProject)
result.Results[refId] = queryResult
result.Results[refID] = queryResult
return result, nil
}
func (e *CloudMonitoringExecutor) executeTimeSeriesQuery(ctx context.Context, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
result := &tsdb.Response{
Results: make(map[string]*tsdb.QueryResult),
func (e *Executor) executeTimeSeriesQuery(ctx context.Context, tsdbQuery plugins.DataQuery) (
plugins.DataResponse, error) {
result := plugins.DataResponse{
Results: make(map[string]plugins.DataQueryResult),
}
queryExecutors, err := e.buildQueryExecutors(tsdbQuery)
if err != nil {
return nil, err
return plugins.DataResponse{}, err
}
unit := e.resolvePanelUnitFromQueries(queryExecutors)
@@ -141,9 +160,9 @@ func (e *CloudMonitoringExecutor) executeTimeSeriesQuery(ctx context.Context, ts
for _, queryExecutor := range queryExecutors {
queryRes, resp, executedQueryString, err := queryExecutor.run(ctx, tsdbQuery, e)
if err != nil {
return nil, err
return plugins.DataResponse{}, err
}
err = queryExecutor.parseResponse(queryRes, resp, executedQueryString)
err = queryExecutor.parseResponse(&queryRes, resp, executedQueryString)
if err != nil {
queryRes.Error = err
}
@@ -158,7 +177,7 @@ func (e *CloudMonitoringExecutor) executeTimeSeriesQuery(ctx context.Context, ts
}
frames[i].Fields[1].Config.Unit = unit
}
queryRes.Dataframes = tsdb.NewDecodedDataFrames(frames)
queryRes.Dataframes = plugins.NewDecodedDataFrames(frames)
}
result.Results[queryExecutor.getRefID()] = queryRes
}
@@ -166,7 +185,7 @@ func (e *CloudMonitoringExecutor) executeTimeSeriesQuery(ctx context.Context, ts
return result, nil
}
func (e *CloudMonitoringExecutor) resolvePanelUnitFromQueries(executors []cloudMonitoringQueryExecutor) string {
func (e *Executor) resolvePanelUnitFromQueries(executors []cloudMonitoringQueryExecutor) string {
if len(executors) == 0 {
return ""
}
@@ -186,7 +205,7 @@ func (e *CloudMonitoringExecutor) resolvePanelUnitFromQueries(executors []cloudM
return ""
}
func (e *CloudMonitoringExecutor) buildQueryExecutors(tsdbQuery *tsdb.TsdbQuery) ([]cloudMonitoringQueryExecutor, error) {
func (e *Executor) buildQueryExecutors(tsdbQuery plugins.DataQuery) ([]cloudMonitoringQueryExecutor, error) {
cloudMonitoringQueryExecutors := []cloudMonitoringQueryExecutor{}
startTime, err := tsdbQuery.TimeRange.ParseFrom()
@@ -201,10 +220,14 @@ func (e *CloudMonitoringExecutor) buildQueryExecutors(tsdbQuery *tsdb.TsdbQuery)
durationSeconds := int(endTime.Sub(startTime).Seconds())
for _, query := range tsdbQuery.Queries {
migrateLegacyQueryModel(query)
for i := range tsdbQuery.Queries {
migrateLegacyQueryModel(&tsdbQuery.Queries[i])
query := tsdbQuery.Queries[i]
q := grafanaQuery{}
model, _ := query.Model.MarshalJSON()
model, err := query.Model.MarshalJSON()
if err != nil {
return nil, err
}
if err := json.Unmarshal(model, &q); err != nil {
return nil, fmt.Errorf("could not unmarshal CloudMonitoringQuery json: %w", err)
}
@@ -215,20 +238,19 @@ func (e *CloudMonitoringExecutor) buildQueryExecutors(tsdbQuery *tsdb.TsdbQuery)
var queryInterface cloudMonitoringQueryExecutor
cmtsf := &cloudMonitoringTimeSeriesFilter{
RefID: query.RefId,
RefID: query.RefID,
GroupBys: []string{},
}
switch q.QueryType {
case metricQueryType:
if q.MetricQuery.EditorMode == mqlEditorMode {
queryInterface = &cloudMonitoringTimeSeriesQuery{
RefID: query.RefId,
RefID: query.RefID,
ProjectName: q.MetricQuery.ProjectName,
Query: q.MetricQuery.Query,
IntervalMS: query.IntervalMs,
IntervalMS: query.IntervalMS,
AliasBy: q.MetricQuery.AliasBy,
timeRange: tsdbQuery.TimeRange,
timeRange: *tsdbQuery.TimeRange,
}
} else {
cmtsf.AliasBy = q.MetricQuery.AliasBy
@@ -239,7 +261,7 @@ func (e *CloudMonitoringExecutor) buildQueryExecutors(tsdbQuery *tsdb.TsdbQuery)
}
params.Add("filter", buildFilterString(q.MetricQuery.MetricType, q.MetricQuery.Filters))
params.Add("view", q.MetricQuery.View)
setMetricAggParams(&params, &q.MetricQuery, durationSeconds, query.IntervalMs)
setMetricAggParams(&params, &q.MetricQuery, durationSeconds, query.IntervalMS)
queryInterface = cmtsf
}
case sloQueryType:
@@ -249,8 +271,10 @@ func (e *CloudMonitoringExecutor) buildQueryExecutors(tsdbQuery *tsdb.TsdbQuery)
cmtsf.Service = q.SloQuery.ServiceId
cmtsf.Slo = q.SloQuery.SloId
params.Add("filter", buildSLOFilterExpression(q.SloQuery))
setSloAggParams(&params, &q.SloQuery, durationSeconds, query.IntervalMs)
setSloAggParams(&params, &q.SloQuery, durationSeconds, query.IntervalMS)
queryInterface = cmtsf
default:
panic(fmt.Sprintf("Unrecognized query type %q", q.QueryType))
}
target = params.Encode()
@@ -268,7 +292,7 @@ func (e *CloudMonitoringExecutor) buildQueryExecutors(tsdbQuery *tsdb.TsdbQuery)
return cloudMonitoringQueryExecutors, nil
}
func migrateLegacyQueryModel(query *tsdb.Query) {
func migrateLegacyQueryModel(query *plugins.DataSubQuery) {
mq := query.Model.Get("metricQuery").MustMap()
if mq == nil {
migratedModel := simplejson.NewFromAny(map[string]interface{}{
@@ -402,7 +426,8 @@ func containsLabel(labels []string, newLabel string) bool {
return false
}
func formatLegendKeys(metricType string, defaultMetricName string, labels map[string]string, additionalLabels map[string]string, query *cloudMonitoringTimeSeriesFilter) string {
func formatLegendKeys(metricType string, defaultMetricName string, labels map[string]string,
additionalLabels map[string]string, query *cloudMonitoringTimeSeriesFilter) string {
if query.AliasBy == "" {
return defaultMetricName
}
@@ -488,7 +513,7 @@ func calcBucketBound(bucketOptions cloudMonitoringBucketOptions, n int) string {
return bucketBound
}
func (e *CloudMonitoringExecutor) createRequest(ctx context.Context, dsInfo *models.DataSource, proxyPass string, body io.Reader) (*http.Request, error) {
func (e *Executor) createRequest(ctx context.Context, dsInfo *models.DataSource, proxyPass string, body io.Reader) (*http.Request, error) {
u, err := url.Parse(dsInfo.Url)
if err != nil {
return nil, err
@@ -509,7 +534,7 @@ func (e *CloudMonitoringExecutor) createRequest(ctx context.Context, dsInfo *mod
req.Header.Set("User-Agent", fmt.Sprintf("Grafana/%s", setting.BuildVersion))
// find plugin
plugin, ok := plugins.DataSources[dsInfo.Type]
plugin, ok := manager.DataSources[dsInfo.Type]
if !ok {
return nil, errors.New("unable to find datasource plugin CloudMonitoring")
}
@@ -527,7 +552,7 @@ func (e *CloudMonitoringExecutor) createRequest(ctx context.Context, dsInfo *mod
return req, nil
}
func (e *CloudMonitoringExecutor) getDefaultProject(ctx context.Context) (string, error) {
func (e *Executor) getDefaultProject(ctx context.Context) (string, error) {
authenticationType := e.dsInfo.JsonData.Get("authenticationType").MustString(jwtAuthentication)
if authenticationType == gceAuthentication {
defaultCredentials, err := google.FindDefaultCredentials(ctx, "https://www.googleapis.com/auth/monitoring.read")
File diff suppressed because it is too large Load Diff
+26 -16
View File
@@ -12,13 +12,14 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/plugins"
"github.com/opentracing/opentracing-go"
"golang.org/x/net/context/ctxhttp"
)
func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) run(ctx context.Context, tsdbQuery *tsdb.TsdbQuery, e *CloudMonitoringExecutor) (*tsdb.QueryResult, cloudMonitoringResponse, string, error) {
queryResult := &tsdb.QueryResult{Meta: simplejson.New(), RefId: timeSeriesFilter.RefID}
func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) run(ctx context.Context, tsdbQuery plugins.DataQuery,
e *Executor) (plugins.DataQueryResult, cloudMonitoringResponse, string, error) {
queryResult := plugins.DataQueryResult{Meta: simplejson.New(), RefID: timeSeriesFilter.RefID}
projectName := timeSeriesFilter.ProjectName
if projectName == "" {
defaultProject, err := e.getDefaultProject(ctx)
@@ -78,7 +79,8 @@ func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) run(ctx context.Context
return queryResult, data, req.URL.RawQuery, nil
}
func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) parseResponse(queryRes *tsdb.QueryResult, response cloudMonitoringResponse, executedQueryString string) error {
func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) parseResponse(queryRes *plugins.DataQueryResult,
response cloudMonitoringResponse, executedQueryString string) error {
labels := make(map[string]map[string]bool)
frames := data.Frames{}
for _, series := range response.TimeSeries {
@@ -199,7 +201,8 @@ func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) parseResponse(queryRes
additionalLabels := data.Labels{"bucket": bucketBound}
timeField := data.NewField(data.TimeSeriesTimeFieldName, nil, []time.Time{})
valueField := data.NewField(data.TimeSeriesValueFieldName, nil, []float64{})
frameName := formatLegendKeys(series.Metric.Type, defaultMetricName, seriesLabels, additionalLabels, timeSeriesFilter)
frameName := formatLegendKeys(series.Metric.Type, defaultMetricName, seriesLabels,
additionalLabels, timeSeriesFilter)
valueField.Name = frameName
valueField.Labels = seriesLabels
setDisplayNameAsFieldName(valueField)
@@ -224,7 +227,7 @@ func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) parseResponse(queryRes
frames = addConfigData(frames, dl)
}
queryRes.Dataframes = tsdb.NewDecodedDataFrames(frames)
queryRes.Dataframes = plugins.NewDecodedDataFrames(frames)
labelsByKey := make(map[string][]string)
for key, values := range labels {
@@ -238,8 +241,9 @@ func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) parseResponse(queryRes
return nil
}
func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) handleNonDistributionSeries(series timeSeries, defaultMetricName string, seriesLabels map[string]string,
queryRes *tsdb.QueryResult, frame *data.Frame) {
func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) handleNonDistributionSeries(series timeSeries,
defaultMetricName string, seriesLabels map[string]string, queryRes *plugins.DataQueryResult,
frame *data.Frame) {
for i := 0; i < len(series.Points); i++ {
point := series.Points[i]
value := point.Value.DoubleValue
@@ -268,7 +272,8 @@ func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) handleNonDistributionSe
setDisplayNameAsFieldName(dataField)
}
func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) parseToAnnotations(queryRes *tsdb.QueryResult, response cloudMonitoringResponse, title string, text string, tags string) error {
func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) parseToAnnotations(queryRes *plugins.DataQueryResult,
response cloudMonitoringResponse, title string, text string, tags string) error {
frames := data.Frames{}
for _, series := range response.TimeSeries {
if len(series.Points) == 0 {
@@ -282,18 +287,20 @@ func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) parseToAnnotations(quer
value = point.Value.StringValue
}
annotation["time"] = append(annotation["time"], point.Interval.EndTime.UTC().Format(time.RFC3339))
annotation["title"] = append(annotation["title"], formatAnnotationText(title, value, series.Metric.Type, series.Metric.Labels, series.Resource.Labels))
annotation["title"] = append(annotation["title"], formatAnnotationText(title, value, series.Metric.Type,
series.Metric.Labels, series.Resource.Labels))
annotation["tags"] = append(annotation["tags"], tags)
annotation["text"] = append(annotation["text"], formatAnnotationText(text, value, series.Metric.Type, series.Metric.Labels, series.Resource.Labels))
annotation["text"] = append(annotation["text"], formatAnnotationText(text, value, series.Metric.Type,
series.Metric.Labels, series.Resource.Labels))
}
frames = append(frames, data.NewFrame(queryRes.RefId,
frames = append(frames, data.NewFrame(queryRes.RefID,
data.NewField("time", nil, annotation["time"]),
data.NewField("title", nil, annotation["title"]),
data.NewField("tags", nil, annotation["tags"]),
data.NewField("text", nil, annotation["text"]),
))
}
queryRes.Dataframes = tsdb.NewDecodedDataFrames(frames)
queryRes.Dataframes = plugins.NewDecodedDataFrames(frames)
return nil
}
@@ -313,7 +320,8 @@ func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) buildDeepLink() string
u, err := url.Parse("https://console.cloud.google.com/monitoring/metrics-explorer")
if err != nil {
slog.Error("Failed to generate deep link: unable to parse metrics explorer URL", "ProjectName", timeSeriesFilter.ProjectName, "query", timeSeriesFilter.RefID)
slog.Error("Failed to generate deep link: unable to parse metrics explorer URL", "ProjectName",
timeSeriesFilter.ProjectName, "query", timeSeriesFilter.RefID)
return ""
}
@@ -353,7 +361,8 @@ func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) buildDeepLink() string
blob, err := json.Marshal(pageState)
if err != nil {
slog.Error("Failed to generate deep link", "pageState", pageState, "ProjectName", timeSeriesFilter.ProjectName, "query", timeSeriesFilter.RefID)
slog.Error("Failed to generate deep link", "pageState", pageState, "ProjectName", timeSeriesFilter.ProjectName,
"query", timeSeriesFilter.RefID)
return ""
}
@@ -362,7 +371,8 @@ func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) buildDeepLink() string
accountChooserURL, err := url.Parse("https://accounts.google.com/AccountChooser")
if err != nil {
slog.Error("Failed to generate deep link: unable to parse account chooser URL", "ProjectName", timeSeriesFilter.ProjectName, "query", timeSeriesFilter.RefID)
slog.Error("Failed to generate deep link: unable to parse account chooser URL", "ProjectName",
timeSeriesFilter.ProjectName, "query", timeSeriesFilter.RefID)
return ""
}
accountChooserQuery := accountChooserURL.Query()
+16 -9
View File
@@ -13,13 +13,15 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/tsdb/interval"
"github.com/opentracing/opentracing-go"
"golang.org/x/net/context/ctxhttp"
)
func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) run(ctx context.Context, tsdbQuery *tsdb.TsdbQuery, e *CloudMonitoringExecutor) (*tsdb.QueryResult, cloudMonitoringResponse, string, error) {
queryResult := &tsdb.QueryResult{Meta: simplejson.New(), RefId: timeSeriesQuery.RefID}
func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) run(ctx context.Context, tsdbQuery plugins.DataQuery,
e *Executor) (plugins.DataQueryResult, cloudMonitoringResponse, string, error) {
queryResult := plugins.DataQueryResult{Meta: simplejson.New(), RefID: timeSeriesQuery.RefID}
projectName := timeSeriesQuery.ProjectName
if projectName == "" {
defaultProject, err := e.getDefaultProject(ctx)
@@ -41,8 +43,8 @@ func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) run(ctx context.Context, t
queryResult.Error = err
return queryResult, cloudMonitoringResponse{}, "", nil
}
intervalCalculator := tsdb.NewIntervalCalculator(&tsdb.IntervalOptions{})
interval := intervalCalculator.Calculate(tsdbQuery.TimeRange, time.Duration(timeSeriesQuery.IntervalMS/1000)*time.Second)
intervalCalculator := interval.NewCalculator(interval.CalculatorOptions{})
interval := intervalCalculator.Calculate(*tsdbQuery.TimeRange, time.Duration(timeSeriesQuery.IntervalMS/1000)*time.Second)
timeFormat := "2006/01/02-15:04:05"
timeSeriesQuery.Query += fmt.Sprintf(" | graph_period %s | within d'%s', d'%s'", interval.Text, from.UTC().Format(timeFormat), to.UTC().Format(timeFormat))
@@ -92,7 +94,8 @@ func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) run(ctx context.Context, t
return queryResult, data, timeSeriesQuery.Query, nil
}
func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) parseResponse(queryRes *tsdb.QueryResult, response cloudMonitoringResponse, executedQueryString string) error {
func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) parseResponse(queryRes *plugins.DataQueryResult,
response cloudMonitoringResponse, executedQueryString string) error {
labels := make(map[string]map[string]bool)
frames := data.Frames{}
for _, series := range response.TimeSeriesData {
@@ -157,7 +160,10 @@ func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) parseResponse(queryRes *ts
frame.SetRow(len(series.PointData)-1-i, series.PointData[i].TimeInterval.EndTime, value)
}
metricName := formatLegendKeys(d.Key, defaultMetricName, seriesLabels, nil, &cloudMonitoringTimeSeriesFilter{ProjectName: timeSeriesQuery.ProjectName, AliasBy: timeSeriesQuery.AliasBy})
metricName := formatLegendKeys(d.Key, defaultMetricName, seriesLabels, nil,
&cloudMonitoringTimeSeriesFilter{
ProjectName: timeSeriesQuery.ProjectName, AliasBy: timeSeriesQuery.AliasBy,
})
dataField := frame.Fields[1]
dataField.Name = metricName
dataField.Labels = seriesLabels
@@ -244,7 +250,7 @@ func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) parseResponse(queryRes *ts
frames = addConfigData(frames, dl)
}
queryRes.Dataframes = tsdb.NewDecodedDataFrames(frames)
queryRes.Dataframes = plugins.NewDecodedDataFrames(frames)
labelsByKey := make(map[string][]string)
for key, values := range labels {
@@ -258,7 +264,8 @@ func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) parseResponse(queryRes *ts
return nil
}
func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) parseToAnnotations(queryRes *tsdb.QueryResult, data cloudMonitoringResponse, title string, text string, tags string) error {
func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) parseToAnnotations(queryRes *plugins.DataQueryResult,
data cloudMonitoringResponse, title string, text string, tags string) error {
annotations := make([]map[string]string, 0)
for _, series := range data.TimeSeriesData {
+6 -5
View File
@@ -5,14 +5,15 @@ import (
"net/url"
"time"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/plugins"
)
type (
cloudMonitoringQueryExecutor interface {
run(ctx context.Context, tsdbQuery *tsdb.TsdbQuery, e *CloudMonitoringExecutor) (*tsdb.QueryResult, cloudMonitoringResponse, string, error)
parseResponse(queryRes *tsdb.QueryResult, data cloudMonitoringResponse, executedQueryString string) error
parseToAnnotations(queryRes *tsdb.QueryResult, data cloudMonitoringResponse, title string, text string, tags string) error
run(ctx context.Context, tsdbQuery plugins.DataQuery, e *Executor) (
plugins.DataQueryResult, cloudMonitoringResponse, string, error)
parseResponse(queryRes *plugins.DataQueryResult, data cloudMonitoringResponse, executedQueryString string) error
parseToAnnotations(queryRes *plugins.DataQueryResult, data cloudMonitoringResponse, title string, text string, tags string) error
buildDeepLink() string
getRefID() string
getUnit() string
@@ -39,7 +40,7 @@ type (
Query string
IntervalMS int64
AliasBy string
timeRange *tsdb.TimeRange
timeRange plugins.DataTimeRange
Unit string
}