Cloud Monitoring: Use new annotation API (#49026)

* remove angular code

* format annotation on backend

* format time with time type instead of string

* update annotation query tests

* update get alignment data function

* update annotation query editor

* add annotation query editor test

* update struct

* add tests

* remove extracted function

* remove non-null assertion

* remove stray commented out console.log

* fix jest haste map warning

* add alignment period

* add AnnotationMetricQuery type
This commit is contained in:
Kevin Yu
2022-05-19 13:52:52 -07:00
committed by GitHub
parent 26e98a6f1b
commit 0a95d493e3
18 changed files with 455 additions and 268 deletions

View File

@@ -4,11 +4,19 @@ import (
"context"
"encoding/json"
"strings"
"time"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/data"
)
type annotationEvent struct {
Title string
Time time.Time
Tags string
Text string
}
func (s *Service) executeAnnotationQuery(ctx context.Context, req *backend.QueryDataRequest, dsInfo datasourceInfo) (
*backend.QueryDataResponse, error) {
resp := backend.NewQueryDataResponse()
@@ -24,8 +32,10 @@ func (s *Service) executeAnnotationQuery(ctx context.Context, req *backend.Query
}
mq := struct {
Title string `json:"title"`
Text string `json:"text"`
MetricQuery struct {
Title string `json:"title"`
Text string `json:"text"`
} `json:"metricQuery"`
}{}
firstQuery := req.Queries[0]
@@ -33,32 +43,23 @@ func (s *Service) executeAnnotationQuery(ctx context.Context, req *backend.Query
if err != nil {
return resp, nil
}
err = queries[0].parseToAnnotations(queryRes, dr, mq.Title, mq.Text)
err = queries[0].parseToAnnotations(queryRes, dr, mq.MetricQuery.Title, mq.MetricQuery.Text)
resp.Responses[firstQuery.RefID] = *queryRes
return resp, err
}
func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) transformAnnotationToFrame(annotations []map[string]string, result *backend.DataResponse) {
frames := data.Frames{}
func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) transformAnnotationToFrame(annotations []*annotationEvent, result *backend.DataResponse) {
frame := data.NewFrame(timeSeriesQuery.RefID,
data.NewField("time", nil, []time.Time{}),
data.NewField("title", nil, []string{}),
data.NewField("tags", nil, []string{}),
data.NewField("text", nil, []string{}),
)
for _, a := range annotations {
frame := &data.Frame{
RefID: timeSeriesQuery.getRefID(),
Fields: []*data.Field{
data.NewField("time", nil, a["time"]),
data.NewField("title", nil, a["title"]),
data.NewField("tags", nil, a["tags"]),
data.NewField("text", nil, a["text"]),
},
Meta: &data.FrameMeta{
Custom: map[string]interface{}{
"rowCount": len(a),
},
},
}
frames = append(frames, frame)
frame.AppendRow(a.Time, a.Title, a.Tags, a.Text)
}
result.Frames = frames
result.Frames = append(result.Frames, frame)
slog.Info("anno", "len", len(annotations))
}

View File

@@ -20,10 +20,15 @@ func TestExecutor_parseToAnnotations(t *testing.T) {
"atext {{resource.label.zone}}")
require.NoError(t, err)
require.Len(t, res.Frames, 3)
require.Len(t, res.Frames, 1)
assert.Equal(t, "time", res.Frames[0].Fields[0].Name)
assert.Equal(t, "title", res.Frames[0].Fields[1].Name)
assert.Equal(t, "tags", res.Frames[0].Fields[2].Name)
assert.Equal(t, "text", res.Frames[0].Fields[3].Name)
assert.Equal(t, 9, res.Frames[0].Fields[0].Len())
assert.Equal(t, 9, res.Frames[0].Fields[1].Len())
assert.Equal(t, 9, res.Frames[0].Fields[2].Len())
assert.Equal(t, 9, res.Frames[0].Fields[3].Len())
}
func TestCloudMonitoringExecutor_parseToAnnotations_emptyTimeSeries(t *testing.T) {
@@ -37,7 +42,15 @@ func TestCloudMonitoringExecutor_parseToAnnotations_emptyTimeSeries(t *testing.T
err := query.parseToAnnotations(res, response, "atitle", "atext")
require.NoError(t, err)
require.Len(t, res.Frames, 0)
require.Len(t, res.Frames, 1)
assert.Equal(t, "time", res.Frames[0].Fields[0].Name)
assert.Equal(t, "title", res.Frames[0].Fields[1].Name)
assert.Equal(t, "tags", res.Frames[0].Fields[2].Name)
assert.Equal(t, "text", res.Frames[0].Fields[3].Name)
assert.Equal(t, 0, res.Frames[0].Fields[0].Len())
assert.Equal(t, 0, res.Frames[0].Fields[1].Len())
assert.Equal(t, 0, res.Frames[0].Fields[2].Len())
assert.Equal(t, 0, res.Frames[0].Fields[3].Len())
}
func TestCloudMonitoringExecutor_parseToAnnotations_noPointsInSeries(t *testing.T) {
@@ -53,5 +66,13 @@ func TestCloudMonitoringExecutor_parseToAnnotations_noPointsInSeries(t *testing.
err := query.parseToAnnotations(res, response, "atitle", "atext")
require.NoError(t, err)
require.Len(t, res.Frames, 0)
require.Len(t, res.Frames, 1)
assert.Equal(t, "time", res.Frames[0].Fields[0].Name)
assert.Equal(t, "title", res.Frames[0].Fields[1].Name)
assert.Equal(t, "tags", res.Frames[0].Fields[2].Name)
assert.Equal(t, "text", res.Frames[0].Fields[3].Name)
assert.Equal(t, 0, res.Frames[0].Fields[0].Len())
assert.Equal(t, 0, res.Frames[0].Fields[1].Len())
assert.Equal(t, 0, res.Frames[0].Fields[2].Len())
assert.Equal(t, 0, res.Frames[0].Fields[3].Len())
}

View File

@@ -250,33 +250,36 @@ func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) handleNonDistributionSe
func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) parseToAnnotations(dr *backend.DataResponse,
response cloudMonitoringResponse, title, text string) error {
frames := data.Frames{}
frame := data.NewFrame(timeSeriesFilter.RefID,
data.NewField("time", nil, []time.Time{}),
data.NewField("title", nil, []string{}),
data.NewField("tags", nil, []string{}),
data.NewField("text", nil, []string{}),
)
for _, series := range response.TimeSeries {
if len(series.Points) == 0 {
continue
}
annotation := make(map[string][]string)
for i := len(series.Points) - 1; i >= 0; i-- {
point := series.Points[i]
value := strconv.FormatFloat(point.Value.DoubleValue, 'f', 6, 64)
if series.ValueType == "STRING" {
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["tags"] = append(annotation["tags"], "")
annotation["text"] = append(annotation["text"], formatAnnotationText(text, value, series.Metric.Type,
series.Metric.Labels, series.Resource.Labels))
annotation := &annotationEvent{
Time: point.Interval.EndTime,
Title: formatAnnotationText(title, value, series.Metric.Type,
series.Metric.Labels, series.Resource.Labels),
Tags: "",
Text: formatAnnotationText(text, value, series.Metric.Type,
series.Metric.Labels, series.Resource.Labels),
}
frame.AppendRow(annotation.Time, annotation.Title, annotation.Tags, annotation.Text)
}
frames = append(frames, data.NewFrame(timeSeriesFilter.getRefID(),
data.NewField("time", nil, annotation["time"]),
data.NewField("title", nil, annotation["title"]),
data.NewField("tags", nil, annotation["tags"]),
data.NewField("text", nil, annotation["text"]),
))
}
dr.Frames = frames
dr.Frames = append(dr.Frames, frame)
return nil
}

View File

@@ -266,7 +266,7 @@ func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) parseResponse(queryRes *ba
func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) parseToAnnotations(queryRes *backend.DataResponse,
data cloudMonitoringResponse, title, text string) error {
annotations := make([]map[string]string, 0)
annotations := make([]*annotationEvent, 0)
for _, series := range data.TimeSeriesData {
metricLabels := make(map[string]string)
@@ -302,12 +302,12 @@ func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) parseToAnnotations(queryRe
if d.ValueType == "STRING" {
value = point.Values[n].StringValue
}
annotation := make(map[string]string)
annotation["time"] = point.TimeInterval.EndTime.UTC().Format(time.RFC3339)
annotation["title"] = formatAnnotationText(title, value, d.MetricKind, metricLabels, resourceLabels)
annotation["tags"] = ""
annotation["text"] = formatAnnotationText(text, value, d.MetricKind, metricLabels, resourceLabels)
annotations = append(annotations, annotation)
annotations = append(annotations, &annotationEvent{
Time: point.TimeInterval.EndTime,
Title: formatAnnotationText(title, value, d.MetricKind, metricLabels, resourceLabels),
Tags: "",
Text: formatAnnotationText(text, value, d.MetricKind, metricLabels, resourceLabels),
})
}
}
}