GoogleCloudMonitoring: Refactor types (#58644)

This commit is contained in:
Andres Martinez Gotor
2022-11-28 09:17:01 +01:00
committed by GitHub
parent 16af756d50
commit 64143ea7d0
8 changed files with 624 additions and 408 deletions
+110 -59
View File
@@ -62,7 +62,6 @@ const (
annotationQueryType = "annotation"
metricQueryType = "metrics"
sloQueryType = "slo"
mqlEditorMode = "mql"
crossSeriesReducerDefault = "REDUCE_NONE"
perSeriesAlignerDefault = "ALIGN_MEAN"
)
@@ -217,16 +216,20 @@ func migrateRequest(req *backend.QueryDataRequest) error {
if rawQuery["metricQuery"] == nil {
// migrate legacy query
var mq metricQuery
var mq timeSeriesList
err = json.Unmarshal(q.JSON, &mq)
if err != nil {
return err
}
q.QueryType = metricQueryType
gq := grafanaQuery{
TimeSeriesList: &mq,
}
if rawQuery["aliasBy"] != nil {
gq.AliasBy = rawQuery["aliasBy"].(string)
}
b, err := json.Marshal(grafanaQuery{
QueryType: metricQueryType,
MetricQuery: mq,
})
b, err := json.Marshal(gq)
if err != nil {
return err
}
@@ -237,6 +240,62 @@ func migrateRequest(req *backend.QueryDataRequest) error {
if rawQuery["type"] != nil && rawQuery["type"].(string) == "annotationQuery" {
q.QueryType = annotationQueryType
}
if rawQuery["queryType"] != nil {
q.QueryType = rawQuery["queryType"].(string)
}
// Metric query was divided between timeSeriesList and timeSeriesQuery API calls
if rawQuery["metricQuery"] != nil {
metricQuery := rawQuery["metricQuery"].(map[string]interface{})
if metricQuery["editorMode"] != nil && toString(metricQuery["editorMode"]) == "mql" {
rawQuery["timeSeriesQuery"] = &timeSeriesQuery{
ProjectName: toString(metricQuery["projectName"]),
Query: toString(metricQuery["query"]),
GraphPeriod: toString(metricQuery["graphPeriod"]),
}
} else {
rawQuery["timeSeriesList"] = metricQuery
}
if metricQuery["aliasBy"] != nil {
rawQuery["aliasBy"] = metricQuery["aliasBy"]
}
b, err := json.Marshal(rawQuery)
if err != nil {
return err
}
if q.QueryType == "" {
q.QueryType = metricQueryType
}
q.JSON = b
}
// SloQuery was merged into timeSeriesList
if rawQuery["sloQuery"] != nil {
if rawQuery["timeSeriesList"] == nil {
rawQuery["timeSeriesList"] = map[string]interface{}{}
}
tsl := rawQuery["timeSeriesList"].(map[string]interface{})
sloq := rawQuery["sloQuery"].(map[string]interface{})
if sloq["projectName"] != nil {
tsl["projectName"] = sloq["projectName"]
}
if sloq["alignmentPeriod"] != nil {
tsl["alignmentPeriod"] = sloq["alignmentPeriod"]
}
if sloq["perSeriesAligner"] != nil {
tsl["perSeriesAligner"] = sloq["perSeriesAligner"]
}
rawQuery["timeSeriesList"] = tsl
b, err := json.Marshal(rawQuery)
if err != nil {
return err
}
if q.QueryType == "" {
q.QueryType = sloQueryType
}
q.JSON = b
}
req.Queries[i] = q
}
@@ -315,58 +374,49 @@ func (s *Service) buildQueryExecutors(logger log.Logger, req *backend.QueryDataR
return nil, fmt.Errorf("could not unmarshal CloudMonitoringQuery json: %w", err)
}
q.MetricQuery.PreprocessorType = toPreprocessorType(q.MetricQuery.Preprocessor)
var target string
params := url.Values{}
params.Add("interval.startTime", startTime.UTC().Format(time.RFC3339))
params.Add("interval.endTime", endTime.UTC().Format(time.RFC3339))
var queryInterface cloudMonitoringQueryExecutor
cmtsf := &cloudMonitoringTimeSeriesFilter{
RefID: query.RefID,
GroupBys: []string{},
logger: logger,
cmtsf := &cloudMonitoringTimeSeriesList{
refID: query.RefID,
logger: logger,
aliasBy: q.AliasBy,
}
switch q.QueryType {
switch query.QueryType {
case metricQueryType, annotationQueryType:
if q.MetricQuery.EditorMode == mqlEditorMode {
if q.TimeSeriesQuery != nil {
queryInterface = &cloudMonitoringTimeSeriesQuery{
RefID: query.RefID,
ProjectName: q.MetricQuery.ProjectName,
Query: q.MetricQuery.Query,
IntervalMS: query.Interval.Milliseconds(),
AliasBy: q.MetricQuery.AliasBy,
timeRange: req.Queries[0].TimeRange,
GraphPeriod: q.MetricQuery.GraphPeriod,
refID: query.RefID,
aliasBy: q.AliasBy,
parameters: q.TimeSeriesQuery,
IntervalMS: query.Interval.Milliseconds(),
timeRange: req.Queries[0].TimeRange,
}
} else {
cmtsf.AliasBy = q.MetricQuery.AliasBy
cmtsf.ProjectName = q.MetricQuery.ProjectName
cmtsf.GroupBys = append(cmtsf.GroupBys, q.MetricQuery.GroupBys...)
if q.MetricQuery.View == "" {
q.MetricQuery.View = "FULL"
} else if q.TimeSeriesList != nil {
if q.TimeSeriesList.View == "" {
q.TimeSeriesList.View = "FULL"
}
params.Add("filter", buildFilterString(q.MetricQuery.MetricType, q.MetricQuery.Filters))
params.Add("view", q.MetricQuery.View)
setMetricAggParams(&params, &q.MetricQuery, durationSeconds, query.Interval.Milliseconds())
cmtsf.parameters = q.TimeSeriesList
params.Add("filter", buildFilterString(q.TimeSeriesList.MetricType, q.TimeSeriesList.Filters))
params.Add("view", q.TimeSeriesList.View)
setMetricAggParams(&params, q.TimeSeriesList, durationSeconds, query.Interval.Milliseconds())
queryInterface = cmtsf
} else {
return nil, fmt.Errorf("missing query info")
}
case sloQueryType:
cmtsf.AliasBy = q.SloQuery.AliasBy
cmtsf.ProjectName = q.SloQuery.ProjectName
cmtsf.Selector = q.SloQuery.SelectorName
cmtsf.Service = q.SloQuery.ServiceId
cmtsf.Slo = q.SloQuery.SloId
params.Add("filter", buildSLOFilterExpression(q.SloQuery))
setSloAggParams(&params, &q.SloQuery, durationSeconds, query.Interval.Milliseconds())
cmtsf.sloQ = q.SloQuery
cmtsf.parameters = q.TimeSeriesList
params.Add("filter", buildSLOFilterExpression(q.TimeSeriesList.ProjectName, q.SloQuery))
setSloAggParams(&params, q.SloQuery, q.TimeSeriesList.AlignmentPeriod, durationSeconds, query.Interval.Milliseconds())
queryInterface = cmtsf
default:
return nil, fmt.Errorf("unrecognized query type %q", q.QueryType)
return nil, fmt.Errorf("unrecognized query type %q", query.QueryType)
}
target = params.Encode()
cmtsf.Target = target
cmtsf.Params = params
cmtsf.params = params
if setting.Env == setting.Dev {
logger.Debug("CloudMonitoring request", "params", params)
@@ -428,8 +478,8 @@ func buildFilterString(metricType string, filterParts []string) string {
return strings.Trim(fmt.Sprintf(`metric.type="%s" %s`, metricType, filterString), " ")
}
func buildSLOFilterExpression(q sloQuery) string {
sloName := fmt.Sprintf("projects/%s/services/%s/serviceLevelObjectives/%s", q.ProjectName, q.ServiceId, q.SloId)
func buildSLOFilterExpression(projectName string, q *sloQuery) string {
sloName := fmt.Sprintf("projects/%s/services/%s/serviceLevelObjectives/%s", projectName, q.ServiceId, q.SloId)
if q.SelectorName == "select_slo_burn_rate" {
return fmt.Sprintf(`%s("%s", "%s")`, q.SelectorName, sloName, q.LookbackPeriod)
@@ -438,7 +488,7 @@ func buildSLOFilterExpression(q sloQuery) string {
}
}
func setMetricAggParams(params *url.Values, query *metricQuery, durationSeconds int, intervalMs int64) {
func setMetricAggParams(params *url.Values, query *timeSeriesList, durationSeconds int, intervalMs int64) {
if query.CrossSeriesReducer == "" {
query.CrossSeriesReducer = crossSeriesReducerDefault
}
@@ -452,7 +502,8 @@ func setMetricAggParams(params *url.Values, query *metricQuery, durationSeconds
// In case a preprocessor is defined, the preprocessor becomes the primary aggregation
// and the aggregation that is specified in the UI becomes the secondary aggregation
// Rules are specified in this issue: https://github.com/grafana/grafana/issues/30866
if query.PreprocessorType != PreprocessorTypeNone {
t := toPreprocessorType(query.Preprocessor)
if t != PreprocessorTypeNone {
params.Add("secondaryAggregation.alignmentPeriod", alignmentPeriod)
params.Add("secondaryAggregation.crossSeriesReducer", query.CrossSeriesReducer)
params.Add("secondaryAggregation.perSeriesAligner", query.PerSeriesAligner)
@@ -464,7 +515,7 @@ func setMetricAggParams(params *url.Values, query *metricQuery, durationSeconds
params.Add("aggregation.crossSeriesReducer", primaryCrossSeriesReducer)
aligner := "ALIGN_RATE"
if query.PreprocessorType == PreprocessorTypeDelta {
if t == PreprocessorTypeDelta {
aligner = "ALIGN_DELTA"
}
params.Add("aggregation.perSeriesAligner", aligner)
@@ -484,8 +535,8 @@ func setMetricAggParams(params *url.Values, query *metricQuery, durationSeconds
}
}
func setSloAggParams(params *url.Values, query *sloQuery, durationSeconds int, intervalMs int64) {
params.Add("aggregation.alignmentPeriod", calculateAlignmentPeriod(query.AlignmentPeriod, intervalMs, durationSeconds))
func setSloAggParams(params *url.Values, query *sloQuery, alignmentPeriod string, durationSeconds int, intervalMs int64) {
params.Add("aggregation.alignmentPeriod", calculateAlignmentPeriod(alignmentPeriod, intervalMs, durationSeconds))
if query.SelectorName == "select_slo_health" {
params.Add("aggregation.perSeriesAligner", "ALIGN_MEAN")
} else {
@@ -515,12 +566,12 @@ func calculateAlignmentPeriod(alignmentPeriod string, intervalMs int64, duration
}
func formatLegendKeys(metricType string, defaultMetricName string, labels map[string]string,
additionalLabels map[string]string, query *cloudMonitoringTimeSeriesFilter) string {
if query.AliasBy == "" {
additionalLabels map[string]string, query *cloudMonitoringTimeSeriesList) string {
if query.aliasBy == "" {
return defaultMetricName
}
result := legendKeyFormat.ReplaceAllFunc([]byte(query.AliasBy), func(in []byte) []byte {
result := legendKeyFormat.ReplaceAllFunc([]byte(query.aliasBy), func(in []byte) []byte {
metaPartName := strings.Replace(string(in), "{{", "", 1)
metaPartName = strings.Replace(metaPartName, "}}", "", 1)
metaPartName = strings.TrimSpace(metaPartName)
@@ -543,20 +594,20 @@ func formatLegendKeys(metricType string, defaultMetricName string, labels map[st
return []byte(val)
}
if metaPartName == "project" && query.ProjectName != "" {
return []byte(query.ProjectName)
if metaPartName == "project" && query.parameters.ProjectName != "" {
return []byte(query.parameters.ProjectName)
}
if metaPartName == "service" && query.Service != "" {
return []byte(query.Service)
if metaPartName == "service" && query.sloQ.ServiceId != "" {
return []byte(query.sloQ.ServiceId)
}
if metaPartName == "slo" && query.Slo != "" {
return []byte(query.Slo)
if metaPartName == "slo" && query.sloQ.SloId != "" {
return []byte(query.sloQ.SloId)
}
if metaPartName == "selector" && query.Selector != "" {
return []byte(query.Selector)
if metaPartName == "selector" && query.sloQ.SelectorName != "" {
return []byte(query.sloQ.SelectorName)
}
return in