2020-06-30 18:47:13 +03:00
|
|
|
package cloudmonitoring
|
2018-09-24 16:02:35 +02:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
2021-10-08 14:46:35 +02:00
|
|
|
"encoding/json"
|
2022-11-08 15:41:17 +01:00
|
|
|
"strconv"
|
2018-09-27 16:16:09 +02:00
|
|
|
"strings"
|
2022-05-19 13:52:52 -07:00
|
|
|
"time"
|
2018-09-24 16:02:35 +02:00
|
|
|
|
2021-10-08 14:46:35 +02:00
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
2018-09-24 16:02:35 +02:00
|
|
|
)
|
|
|
|
|
|
2022-05-19 13:52:52 -07:00
|
|
|
type annotationEvent struct {
|
|
|
|
|
Title string
|
|
|
|
|
Time time.Time
|
|
|
|
|
Tags string
|
|
|
|
|
Text string
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-10 09:30:47 +01:00
|
|
|
func (s *Service) executeAnnotationQuery(ctx context.Context, req *backend.QueryDataRequest, dsInfo datasourceInfo, queries []cloudMonitoringQueryExecutor) (
|
2021-10-08 14:46:35 +02:00
|
|
|
*backend.QueryDataResponse, error) {
|
|
|
|
|
resp := backend.NewQueryDataResponse()
|
2022-01-20 11:10:12 +01:00
|
|
|
queryRes, dr, _, err := queries[0].run(ctx, req, s, dsInfo, s.tracer)
|
2018-09-24 16:02:35 +02:00
|
|
|
if err != nil {
|
2021-10-08 14:46:35 +02:00
|
|
|
return resp, err
|
2018-09-24 16:02:35 +02:00
|
|
|
}
|
2020-09-08 19:18:41 +09:00
|
|
|
|
2023-07-21 21:42:42 +01:00
|
|
|
tslq := struct {
|
|
|
|
|
TimeSeriesList struct {
|
2022-05-19 13:52:52 -07:00
|
|
|
Title string `json:"title"`
|
|
|
|
|
Text string `json:"text"`
|
2023-07-21 21:42:42 +01:00
|
|
|
} `json:"timeSeriesList"`
|
2021-10-08 14:46:35 +02:00
|
|
|
}{}
|
2021-02-25 18:29:17 +02:00
|
|
|
|
2021-10-08 14:46:35 +02:00
|
|
|
firstQuery := req.Queries[0]
|
2023-07-21 21:42:42 +01:00
|
|
|
err = json.Unmarshal(firstQuery.JSON, &tslq)
|
2021-10-08 14:46:35 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return resp, nil
|
|
|
|
|
}
|
2023-08-18 11:14:43 -05:00
|
|
|
err = parseToAnnotations(req.Queries[0].RefID, queryRes, dr.(cloudMonitoringResponse), tslq.TimeSeriesList.Title, tslq.TimeSeriesList.Text)
|
2021-10-08 14:46:35 +02:00
|
|
|
resp.Responses[firstQuery.RefID] = *queryRes
|
2018-09-24 16:02:35 +02:00
|
|
|
|
2021-10-08 14:46:35 +02:00
|
|
|
return resp, err
|
2018-09-24 16:02:35 +02:00
|
|
|
}
|
|
|
|
|
|
2022-11-08 15:41:17 +01:00
|
|
|
func parseToAnnotations(refID string, dr *backend.DataResponse,
|
|
|
|
|
response cloudMonitoringResponse, title, text string) error {
|
|
|
|
|
frame := data.NewFrame(refID,
|
2022-05-19 13:52:52 -07:00
|
|
|
data.NewField("time", nil, []time.Time{}),
|
|
|
|
|
data.NewField("title", nil, []string{}),
|
|
|
|
|
data.NewField("tags", nil, []string{}),
|
|
|
|
|
data.NewField("text", nil, []string{}),
|
|
|
|
|
)
|
2022-11-08 15:41:17 +01:00
|
|
|
|
|
|
|
|
for _, series := range response.TimeSeries {
|
|
|
|
|
if len(series.Points) == 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 := &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)
|
|
|
|
|
}
|
2018-09-27 15:17:35 +02:00
|
|
|
}
|
2022-11-08 15:41:17 +01:00
|
|
|
dr.Frames = append(dr.Frames, frame)
|
|
|
|
|
|
|
|
|
|
return nil
|
2018-09-27 15:17:35 +02:00
|
|
|
}
|
|
|
|
|
|
2018-09-28 13:41:28 +02:00
|
|
|
func formatAnnotationText(annotationText string, pointValue string, metricType string, metricLabels map[string]string, resourceLabels map[string]string) string {
|
2018-09-27 16:16:09 +02:00
|
|
|
result := legendKeyFormat.ReplaceAllFunc([]byte(annotationText), func(in []byte) []byte {
|
|
|
|
|
metaPartName := strings.Replace(string(in), "{{", "", 1)
|
|
|
|
|
metaPartName = strings.Replace(metaPartName, "}}", "", 1)
|
|
|
|
|
metaPartName = strings.TrimSpace(metaPartName)
|
|
|
|
|
|
|
|
|
|
if metaPartName == "metric.type" {
|
|
|
|
|
return []byte(metricType)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
metricPart := replaceWithMetricPart(metaPartName, metricType)
|
|
|
|
|
|
|
|
|
|
if metricPart != nil {
|
|
|
|
|
return metricPart
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 14:55:39 +02:00
|
|
|
if metaPartName == "metric.value" {
|
2018-09-28 13:50:10 +02:00
|
|
|
return []byte(pointValue)
|
2018-09-27 16:16:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
metaPartName = strings.Replace(metaPartName, "metric.label.", "", 1)
|
|
|
|
|
|
|
|
|
|
if val, exists := metricLabels[metaPartName]; exists {
|
|
|
|
|
return []byte(val)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
metaPartName = strings.Replace(metaPartName, "resource.label.", "", 1)
|
|
|
|
|
|
|
|
|
|
if val, exists := resourceLabels[metaPartName]; exists {
|
|
|
|
|
return []byte(val)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return in
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return string(result)
|
|
|
|
|
}
|