diff --git a/pkg/services/alerting/conditions/query.go b/pkg/services/alerting/conditions/query.go index 208527287f3..15db31838b0 100644 --- a/pkg/services/alerting/conditions/query.go +++ b/pkg/services/alerting/conditions/query.go @@ -111,7 +111,7 @@ func (c *QueryCondition) getRequestForAlertRule(datasource *m.DataSource, timera Queries: []*tsdb.Query{ { RefId: "A", - Query: c.Query.Model.Get("target").MustString(), + Model: c.Query.Model, DataSource: &tsdb.DataSourceInfo{ Id: datasource.Id, Name: datasource.Name, diff --git a/pkg/tsdb/graphite/graphite.go b/pkg/tsdb/graphite/graphite.go index 4042702378c..32e1ab4fa76 100644 --- a/pkg/tsdb/graphite/graphite.go +++ b/pkg/tsdb/graphite/graphite.go @@ -54,7 +54,7 @@ func (e *GraphiteExecutor) Execute(queries tsdb.QuerySlice, context *tsdb.QueryC } for _, query := range queries { - formData["target"] = []string{query.Query} + formData["target"] = []string{query.Model.Get("target").MustString()} } if setting.Env == setting.DEV { diff --git a/pkg/tsdb/models.go b/pkg/tsdb/models.go index 117b00efe3a..262be5cbd24 100644 --- a/pkg/tsdb/models.go +++ b/pkg/tsdb/models.go @@ -1,8 +1,11 @@ package tsdb +import "github.com/grafana/grafana/pkg/components/simplejson" + type Query struct { RefId string Query string + Model *simplejson.Json Depends []string DataSource *DataSourceInfo Results []*TimeSeries diff --git a/pkg/tsdb/prometheus/prometheus.go b/pkg/tsdb/prometheus/prometheus.go index 2b2ccd382af..d835d5a822c 100644 --- a/pkg/tsdb/prometheus/prometheus.go +++ b/pkg/tsdb/prometheus/prometheus.go @@ -3,6 +3,8 @@ package prometheus import ( "context" "net/http" + "regexp" + "strings" "time" "github.com/grafana/grafana/pkg/log" @@ -53,25 +55,52 @@ func (e *PrometheusExecutor) Execute(queries tsdb.QuerySlice, queryContext *tsdb from, _ := queryContext.TimeRange.FromTime() to, _ := queryContext.TimeRange.ToTime() + + query := parseQuery(queries) + timeRange := prometheus.Range{ Start: from, End: to, - Step: time.Second, + Step: query.Step, } - ctx := context.Background() - value, err := client.QueryRange(ctx, "counters_logins", timeRange) + value, err := client.QueryRange(context.Background(), query.Expr, timeRange) if err != nil { result.Error = err return result } - result.QueryResults = parseResponse(value) + result.QueryResults = parseResponse(value, query) return result } -func parseResponse(value pmodel.Value) map[string]*tsdb.QueryResult { +func formatLegend(metric pmodel.Metric, query PrometheusQuery) string { + r, _ := regexp.Compile(`\{\{\s*(.+?)\s*\}\}`) + + result := r.ReplaceAllFunc([]byte(query.LegendFormat), func(in []byte) []byte { + ind := strings.Replace(strings.Replace(string(in), "{{", "", 1), "}}", "", 1) + if val, exists := metric[pmodel.LabelName(ind)]; exists { + return []byte(val) + } + + return in + }) + + return string(result) +} + +func parseQuery(queries tsdb.QuerySlice) PrometheusQuery { + queryModel := queries[0] + + return PrometheusQuery{ + Expr: queryModel.Model.Get("expr").MustString(), + Step: time.Second * time.Duration(queryModel.Model.Get("step").MustInt64(1)), + LegendFormat: queryModel.Model.Get("legendFormat").MustString(), + } +} + +func parseResponse(value pmodel.Value, query PrometheusQuery) map[string]*tsdb.QueryResult { queryResults := make(map[string]*tsdb.QueryResult) queryRes := &tsdb.QueryResult{} @@ -86,7 +115,7 @@ func parseResponse(value pmodel.Value) map[string]*tsdb.QueryResult { } queryRes.Series = append(queryRes.Series, &tsdb.TimeSeries{ - Name: v.Metric.String(), + Name: formatLegend(v.Metric, query), Points: points, }) } diff --git a/pkg/tsdb/prometheus/prometheus_test.go b/pkg/tsdb/prometheus/prometheus_test.go new file mode 100644 index 00000000000..6edb6260a09 --- /dev/null +++ b/pkg/tsdb/prometheus/prometheus_test.go @@ -0,0 +1,26 @@ +package prometheus + +import ( + "testing" + + p "github.com/prometheus/common/model" + . "github.com/smartystreets/goconvey/convey" +) + +func TestPrometheus(t *testing.T) { + Convey("Prometheus", t, func() { + + Convey("converting metric name", func() { + metric := map[p.LabelName]p.LabelValue{ + p.LabelName("app"): p.LabelValue("backend"), + p.LabelName("device"): p.LabelValue("mobile"), + } + + query := PrometheusQuery{ + LegendFormat: "legend {{app}} {{device}} {{broken}}", + } + + So(formatLegend(metric, query), ShouldEqual, "legend backend mobile {{broken}}") + }) + }) +} diff --git a/pkg/tsdb/prometheus/types.go b/pkg/tsdb/prometheus/types.go index 7b1b4c03ead..67d9ae40670 100644 --- a/pkg/tsdb/prometheus/types.go +++ b/pkg/tsdb/prometheus/types.go @@ -1 +1,9 @@ package prometheus + +import "time" + +type PrometheusQuery struct { + Expr string + Step time.Duration + LegendFormat string +} diff --git a/public/app/plugins/datasource/prometheus/datasource.ts b/public/app/plugins/datasource/prometheus/datasource.ts index 53ce91144a4..1d4112789da 100644 --- a/public/app/plugins/datasource/prometheus/datasource.ts +++ b/public/app/plugins/datasource/prometheus/datasource.ts @@ -113,7 +113,6 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS throw response.error; } delete self.lastErrors.query; - _.each(response.data.data.result, function(metricData) { result.push(self.transformMetricData(metricData, activeTargets[index], start, end)); });