a327fec8df
* split up data_query.go * split up response_parser * remove white space
171 lines
4.4 KiB
Go
171 lines
4.4 KiB
Go
package elasticsearch
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
|
)
|
|
|
|
// nameFields applies naming logic to data frame fields based on query configuration
|
|
func nameFields(queryResult backend.DataResponse, target *Query, keepLabelsInResponse bool) {
|
|
set := make(map[string]struct{})
|
|
frames := queryResult.Frames
|
|
for _, v := range frames {
|
|
for _, vv := range v.Fields {
|
|
if metricType, exists := vv.Labels["metric"]; exists {
|
|
if _, ok := set[metricType]; !ok {
|
|
set[metricType] = struct{}{}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
metricTypeCount := len(set)
|
|
for _, frame := range frames {
|
|
if frame.Meta != nil && frame.Meta.Type == data.FrameTypeTimeSeriesMulti {
|
|
// if it is a time-series-multi, it means it has two columns, one is "time",
|
|
// another is "number"
|
|
valueField := frame.Fields[1]
|
|
fieldName := getFieldName(*valueField, target, metricTypeCount)
|
|
// If we need to keep the labels in the response, to prevent duplication in names and to keep
|
|
// backward compatibility with alerting and expressions we use DisplayNameFromDS
|
|
if keepLabelsInResponse {
|
|
if valueField.Config == nil {
|
|
valueField.Config = &data.FieldConfig{}
|
|
}
|
|
valueField.Config.DisplayNameFromDS = fieldName
|
|
// If we don't need to keep labels (how frontend mode worked), we use frame.Name and remove labels
|
|
} else {
|
|
valueField.Labels = nil
|
|
frame.Name = fieldName
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// getFieldName generates a field name based on the data field and target configuration
|
|
func getFieldName(dataField data.Field, target *Query, metricTypeCount int) string {
|
|
metricType := dataField.Labels["metric"]
|
|
metricName := getMetricName(metricType)
|
|
delete(dataField.Labels, "metric")
|
|
|
|
field := ""
|
|
if v, ok := dataField.Labels["field"]; ok {
|
|
field = v
|
|
delete(dataField.Labels, "field")
|
|
}
|
|
|
|
if target.Alias != "" {
|
|
frameName := target.Alias
|
|
|
|
subMatches := aliasPatternRegex.FindAllStringSubmatch(target.Alias, -1)
|
|
for _, subMatch := range subMatches {
|
|
group := subMatch[0]
|
|
|
|
if len(subMatch) > 1 {
|
|
group = subMatch[1]
|
|
}
|
|
|
|
if strings.Index(group, "term ") == 0 {
|
|
frameName = strings.Replace(frameName, subMatch[0], dataField.Labels[group[5:]], 1)
|
|
}
|
|
if v, ok := dataField.Labels[group]; ok {
|
|
frameName = strings.Replace(frameName, subMatch[0], v, 1)
|
|
}
|
|
if group == "metric" {
|
|
frameName = strings.Replace(frameName, subMatch[0], metricName, 1)
|
|
}
|
|
if group == "field" {
|
|
frameName = strings.Replace(frameName, subMatch[0], field, 1)
|
|
}
|
|
}
|
|
|
|
return frameName
|
|
}
|
|
// todo, if field and pipelineAgg
|
|
if isPipelineAgg(metricType) {
|
|
if metricType != "" && isPipelineAggWithMultipleBucketPaths(metricType) {
|
|
metricID := ""
|
|
if v, ok := dataField.Labels["metricId"]; ok {
|
|
metricID = v
|
|
}
|
|
|
|
for _, metric := range target.Metrics {
|
|
if metric.ID == metricID {
|
|
metricName = metric.Settings.Get("script").MustString()
|
|
for name, pipelineAgg := range metric.PipelineVariables {
|
|
for _, m := range target.Metrics {
|
|
if m.ID == pipelineAgg {
|
|
metricName = strings.ReplaceAll(metricName, "params."+name, describeMetric(m.Type, m.Field))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if field != "" {
|
|
found := false
|
|
for _, metric := range target.Metrics {
|
|
if metric.ID == field {
|
|
metricName += " " + describeMetric(metric.Type, metric.Field)
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
metricName = "Unset"
|
|
}
|
|
}
|
|
}
|
|
} else if field != "" {
|
|
metricName += " " + field
|
|
}
|
|
|
|
delete(dataField.Labels, "metricId")
|
|
|
|
if len(dataField.Labels) == 0 {
|
|
return metricName
|
|
}
|
|
|
|
name := ""
|
|
for _, v := range getSortedLabelValues(dataField.Labels) {
|
|
name += v + " "
|
|
}
|
|
|
|
if metricTypeCount == 1 {
|
|
return strings.TrimSpace(name)
|
|
}
|
|
|
|
return strings.TrimSpace(name) + " " + metricName
|
|
}
|
|
|
|
// getSortedLabelValues sorts label keys and returns the label values in sorted order
|
|
func getSortedLabelValues(labels data.Labels) []string {
|
|
keys := make([]string, 0, len(labels))
|
|
for key := range labels {
|
|
keys = append(keys, key)
|
|
}
|
|
|
|
sort.Strings(keys)
|
|
|
|
values := make([]string, len(keys))
|
|
for i, key := range keys {
|
|
values[i] = labels[key]
|
|
}
|
|
|
|
return values
|
|
}
|
|
|
|
// getMetricName returns the display name for a metric type
|
|
func getMetricName(metric string) string {
|
|
if text, ok := metricAggType[metric]; ok {
|
|
return text
|
|
}
|
|
|
|
if text, ok := extendedStats[metric]; ok {
|
|
return text
|
|
}
|
|
|
|
return metric
|
|
}
|