From b66d94343ed12f713429a44d349322728e4bf29b Mon Sep 17 00:00:00 2001 From: bergquist Date: Fri, 30 Sep 2016 07:35:48 +0200 Subject: [PATCH 01/19] tech(tsdb): add basic skeleton for alerting --- pkg/tsdb/opentsdb/opentsdb.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 pkg/tsdb/opentsdb/opentsdb.go diff --git a/pkg/tsdb/opentsdb/opentsdb.go b/pkg/tsdb/opentsdb/opentsdb.go new file mode 100644 index 00000000000..57134657603 --- /dev/null +++ b/pkg/tsdb/opentsdb/opentsdb.go @@ -0,0 +1,30 @@ +package opentsdb + +import ( + "net/http" + + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/tsdb" +) + +type OpenTsdbExecutor struct { + *tsdb.DataSourceInfo +} + +func NewOpenTsdbExecutorExecutor(dsInfo *tsdb.DataSourceInfo) tsdb.Executor { + return &OpenTsdbExecutor{dsInfo} +} + +var ( + plog log.Logger + HttpClient http.Client +) + +func init() { + plog = log.New("tsdb.opentsdb") + tsdb.RegisterExecutor("opentsdb", NewOpenTsdbExecutorExecutor) +} + +func (e *OpenTsdbExecutor) Execute(queries tsdb.QuerySlice, queryContext *tsdb.QueryContext) *tsdb.BatchResult { + panic("Missing implementation") +} From 1226beba31e385f8d06614db6b489d9da90c8540 Mon Sep 17 00:00:00 2001 From: bergquist Date: Fri, 30 Sep 2016 16:50:50 +0200 Subject: [PATCH 02/19] feat(opentsdb): add alerting support to plugin.json --- public/app/plugins/datasource/opentsdb/plugin.json | 1 + 1 file changed, 1 insertion(+) diff --git a/public/app/plugins/datasource/opentsdb/plugin.json b/public/app/plugins/datasource/opentsdb/plugin.json index 02ba02e6e89..7de072c6948 100644 --- a/public/app/plugins/datasource/opentsdb/plugin.json +++ b/public/app/plugins/datasource/opentsdb/plugin.json @@ -6,6 +6,7 @@ "metrics": true, "defaultMatchFormat": "pipe", "annotations": true, + "alerting": true, "info": { "author": { From f4a834f84b7d07dffa12594bf93a927b62bbff62 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 3 Oct 2016 10:37:49 +0200 Subject: [PATCH 03/19] fix(opentsdb): add context to opentsdb executor --- pkg/tsdb/opentsdb/opentsdb.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/tsdb/opentsdb/opentsdb.go b/pkg/tsdb/opentsdb/opentsdb.go index 57134657603..0321e2e8786 100644 --- a/pkg/tsdb/opentsdb/opentsdb.go +++ b/pkg/tsdb/opentsdb/opentsdb.go @@ -1,6 +1,7 @@ package opentsdb import ( + "context" "net/http" "github.com/grafana/grafana/pkg/log" @@ -25,6 +26,6 @@ func init() { tsdb.RegisterExecutor("opentsdb", NewOpenTsdbExecutorExecutor) } -func (e *OpenTsdbExecutor) Execute(queries tsdb.QuerySlice, queryContext *tsdb.QueryContext) *tsdb.BatchResult { +func (e *OpenTsdbExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, queryContext *tsdb.QueryContext) *tsdb.BatchResult { panic("Missing implementation") } From 1606b74fcee1fc50a1e149efdd12d70f821ddd6f Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 3 Oct 2016 10:59:09 +0200 Subject: [PATCH 04/19] tech(opentsdb): add init ref for opentsdb --- pkg/cmd/grafana-server/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/cmd/grafana-server/main.go b/pkg/cmd/grafana-server/main.go index 6cd063f798f..aa519bfe308 100644 --- a/pkg/cmd/grafana-server/main.go +++ b/pkg/cmd/grafana-server/main.go @@ -20,6 +20,7 @@ import ( _ "github.com/grafana/grafana/pkg/services/alerting/conditions" _ "github.com/grafana/grafana/pkg/services/alerting/notifiers" _ "github.com/grafana/grafana/pkg/tsdb/graphite" + _ "github.com/grafana/grafana/pkg/tsdb/opentsdb" _ "github.com/grafana/grafana/pkg/tsdb/prometheus" _ "github.com/grafana/grafana/pkg/tsdb/testdata" ) From b8ec1ce9a28368885a04e11e8e2518944cf0a866 Mon Sep 17 00:00:00 2001 From: bergquist Date: Fri, 30 Sep 2016 07:35:48 +0200 Subject: [PATCH 05/19] tech(tsdb): add basic skeleton for alerting --- pkg/tsdb/opentsdb/opentsdb.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 pkg/tsdb/opentsdb/opentsdb.go diff --git a/pkg/tsdb/opentsdb/opentsdb.go b/pkg/tsdb/opentsdb/opentsdb.go new file mode 100644 index 00000000000..57134657603 --- /dev/null +++ b/pkg/tsdb/opentsdb/opentsdb.go @@ -0,0 +1,30 @@ +package opentsdb + +import ( + "net/http" + + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/tsdb" +) + +type OpenTsdbExecutor struct { + *tsdb.DataSourceInfo +} + +func NewOpenTsdbExecutorExecutor(dsInfo *tsdb.DataSourceInfo) tsdb.Executor { + return &OpenTsdbExecutor{dsInfo} +} + +var ( + plog log.Logger + HttpClient http.Client +) + +func init() { + plog = log.New("tsdb.opentsdb") + tsdb.RegisterExecutor("opentsdb", NewOpenTsdbExecutorExecutor) +} + +func (e *OpenTsdbExecutor) Execute(queries tsdb.QuerySlice, queryContext *tsdb.QueryContext) *tsdb.BatchResult { + panic("Missing implementation") +} From 998df2a1ac94bb2b62abf7cc8fba652b054538c5 Mon Sep 17 00:00:00 2001 From: bergquist Date: Fri, 30 Sep 2016 16:50:50 +0200 Subject: [PATCH 06/19] feat(opentsdb): add alerting support to plugin.json --- public/app/plugins/datasource/opentsdb/plugin.json | 1 + 1 file changed, 1 insertion(+) diff --git a/public/app/plugins/datasource/opentsdb/plugin.json b/public/app/plugins/datasource/opentsdb/plugin.json index 02ba02e6e89..7de072c6948 100644 --- a/public/app/plugins/datasource/opentsdb/plugin.json +++ b/public/app/plugins/datasource/opentsdb/plugin.json @@ -6,6 +6,7 @@ "metrics": true, "defaultMatchFormat": "pipe", "annotations": true, + "alerting": true, "info": { "author": { From 06f2047ced1a301027a26258bbe53ba095ac4c25 Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Fri, 7 Oct 2016 23:58:27 -0700 Subject: [PATCH 07/19] OpenTsdb alerting works with metric query --- pkg/cmd/grafana-server/main.go | 1 + pkg/tsdb/opentsdb/opentsdb.go | 134 +++++++++++++++++++++++++++++++-- pkg/tsdb/opentsdb/types.go | 17 +++++ 3 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 pkg/tsdb/opentsdb/types.go diff --git a/pkg/cmd/grafana-server/main.go b/pkg/cmd/grafana-server/main.go index caf9d2cb56f..263c7ae569c 100644 --- a/pkg/cmd/grafana-server/main.go +++ b/pkg/cmd/grafana-server/main.go @@ -22,6 +22,7 @@ import ( _ "github.com/grafana/grafana/pkg/tsdb/graphite" _ "github.com/grafana/grafana/pkg/tsdb/influxdb" _ "github.com/grafana/grafana/pkg/tsdb/prometheus" + _ "github.com/grafana/grafana/pkg/tsdb/opentsdb" _ "github.com/grafana/grafana/pkg/tsdb/testdata" ) diff --git a/pkg/tsdb/opentsdb/opentsdb.go b/pkg/tsdb/opentsdb/opentsdb.go index 57134657603..f8b51204ade 100644 --- a/pkg/tsdb/opentsdb/opentsdb.go +++ b/pkg/tsdb/opentsdb/opentsdb.go @@ -1,17 +1,30 @@ package opentsdb import ( - "net/http" + "fmt" + "path" + "strings" + "context" + "strconv" + + "net/url" + "net/http" + "io/ioutil" + //"net/http/httputil" + "encoding/json" + + "gopkg.in/guregu/null.v3" "github.com/grafana/grafana/pkg/log" - "github.com/grafana/grafana/pkg/tsdb" + "github.com/grafana/grafana/pkg/tsdb" + "github.com/grafana/grafana/pkg/setting" ) type OpenTsdbExecutor struct { *tsdb.DataSourceInfo } -func NewOpenTsdbExecutorExecutor(dsInfo *tsdb.DataSourceInfo) tsdb.Executor { +func NewOpenTsdbExecutor(dsInfo *tsdb.DataSourceInfo) tsdb.Executor { return &OpenTsdbExecutor{dsInfo} } @@ -22,9 +35,118 @@ var ( func init() { plog = log.New("tsdb.opentsdb") - tsdb.RegisterExecutor("opentsdb", NewOpenTsdbExecutorExecutor) + tsdb.RegisterExecutor("opentsdb", NewOpenTsdbExecutor) } -func (e *OpenTsdbExecutor) Execute(queries tsdb.QuerySlice, queryContext *tsdb.QueryContext) *tsdb.BatchResult { - panic("Missing implementation") +func (e *OpenTsdbExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, queryContext *tsdb.QueryContext) *tsdb.BatchResult { + result := &tsdb.BatchResult{} + + var tsdbQuery OpenTsdbQuery + + tsdbQuery.Start = queryContext.TimeRange.GetFromAsMsEpoch() + tsdbQuery.End = queryContext.TimeRange.GetToAsMsEpoch() + + for _, query := range queries { + tsdbQuery.Queries = []OpenTsdbMetric { + OpenTsdbMetric{ + Metric: query.Model.Get("metric").MustString(), + Aggregator: query.Model.Get("aggregator").MustString(), + }, + } + } + + if setting.Env == setting.DEV { + plog.Debug("OpenTsdb request", "params", tsdbQuery) + } + + req, err := e.createRequest(tsdbQuery) + if err != nil { + result.Error = err + return result + } + + res, err := HttpClient.Do(req) + if err != nil { + result.Error = err + return result + } + + queryResult, err := e.parseResponse(tsdbQuery, res) + if err != nil { + return result.WithError(err) + } + + result.QueryResults = queryResult + return result } + +func (e *OpenTsdbExecutor) createRequest(data OpenTsdbQuery) (*http.Request, error) { + u, _ := url.Parse(e.Url) + u.Path = path.Join(u.Path, "api/query") + + postData, err := json.Marshal(data) + + req, err := http.NewRequest(http.MethodPost, u.String(), strings.NewReader(string(postData))) + if err != nil { + plog.Info("Failed to create request", "error", err) + return nil, fmt.Errorf("Failed to create request. error: %v", err) + } + + req.Header.Set("Content-Type", "application/json") + if e.BasicAuth { + req.SetBasicAuth(e.BasicAuthUser, e.BasicAuthPassword) + } + + /* + requestDump, err := httputil.DumpRequest(req, true) + if err != nil { + fmt.Println(err) + } + fmt.Println(string(requestDump)) + */ + return req, err +} + +func (e *OpenTsdbExecutor) parseResponse(query OpenTsdbQuery, res *http.Response) (map[string]*tsdb.QueryResult, error) { + + queryResults := make(map[string]*tsdb.QueryResult) + queryRes := tsdb.NewQueryResult() + + body, err := ioutil.ReadAll(res.Body) + defer res.Body.Close() + if err != nil { + return nil, err + } + + if res.StatusCode/100 != 2 { + plog.Info("Request failed", "status", res.Status, "body", string(body)) + return nil, fmt.Errorf("Request failed status: %v", res.Status) + } + + var data []OpenTsdbResponse + err = json.Unmarshal(body, &data) + if err != nil { + plog.Info("Failed to unmarshal opentsdb response", "error", err, "status", res.Status, "body", string(body)) + return nil, err + } + + for _, val := range data { + series := tsdb.TimeSeries{ + Name: val.Metric, + } + + for timeString, value := range val.DataPoints { + timestamp, err := strconv.ParseFloat(timeString, 64) + if err != nil { + plog.Info("Failed to unmarshal opentsdb timestamp", "timestamp", timeString) + return nil, err + } + series.Points = append(series.Points, tsdb.NewTimePoint(null.FloatFrom(value), timestamp)) + } + + queryRes.Series = append(queryRes.Series, &series) + } + + queryResults["A"] = queryRes + return queryResults, nil +} \ No newline at end of file diff --git a/pkg/tsdb/opentsdb/types.go b/pkg/tsdb/opentsdb/types.go new file mode 100644 index 00000000000..473c797b2d4 --- /dev/null +++ b/pkg/tsdb/opentsdb/types.go @@ -0,0 +1,17 @@ +package opentsdb + +type OpenTsdbQuery struct { + Start int64 `json:"start"` + End int64 `json:"end"` + Queries []OpenTsdbMetric `json:"queries"` +} + +type OpenTsdbMetric struct { + Metric string `json:"metric"` + Aggregator string `json:"aggregator"` +} + +type OpenTsdbResponse struct { + Metric string `json:"metric"` + DataPoints map[string]float64 `json:"dps"` +} \ No newline at end of file From f44e360b0d8ed4b767a348564daa58ebc033ae80 Mon Sep 17 00:00:00 2001 From: bergquist Date: Fri, 14 Oct 2016 10:15:30 +0200 Subject: [PATCH 08/19] fix(opentsdb): fmt --- pkg/tsdb/opentsdb/opentsdb.go | 194 +++++++++++++++++----------------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/pkg/tsdb/opentsdb/opentsdb.go b/pkg/tsdb/opentsdb/opentsdb.go index 574c0f90d6d..bd1684397ce 100644 --- a/pkg/tsdb/opentsdb/opentsdb.go +++ b/pkg/tsdb/opentsdb/opentsdb.go @@ -1,23 +1,23 @@ package opentsdb import ( - "fmt" - "path" - "strings" - "context" - "strconv" + "context" + "fmt" + "path" + "strconv" + "strings" - "net/url" - "net/http" - "io/ioutil" - //"net/http/httputil" - "encoding/json" + "io/ioutil" + "net/http" + "net/url" + //"net/http/httputil" + "encoding/json" - "gopkg.in/guregu/null.v3" + "gopkg.in/guregu/null.v3" "github.com/grafana/grafana/pkg/log" - "github.com/grafana/grafana/pkg/tsdb" - "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/tsdb" ) type OpenTsdbExecutor struct { @@ -41,112 +41,112 @@ func init() { func (e *OpenTsdbExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, queryContext *tsdb.QueryContext) *tsdb.BatchResult { result := &tsdb.BatchResult{} - var tsdbQuery OpenTsdbQuery + var tsdbQuery OpenTsdbQuery - tsdbQuery.Start = queryContext.TimeRange.GetFromAsMsEpoch() - tsdbQuery.End = queryContext.TimeRange.GetToAsMsEpoch() + tsdbQuery.Start = queryContext.TimeRange.GetFromAsMsEpoch() + tsdbQuery.End = queryContext.TimeRange.GetToAsMsEpoch() - for _, query := range queries { - tsdbQuery.Queries = []OpenTsdbMetric { - OpenTsdbMetric{ - Metric: query.Model.Get("metric").MustString(), - Aggregator: query.Model.Get("aggregator").MustString(), - }, - } - } + for _, query := range queries { + tsdbQuery.Queries = []OpenTsdbMetric{ + OpenTsdbMetric{ + Metric: query.Model.Get("metric").MustString(), + Aggregator: query.Model.Get("aggregator").MustString(), + }, + } + } - if setting.Env == setting.DEV { - plog.Debug("OpenTsdb request", "params", tsdbQuery) - } + if setting.Env == setting.DEV { + plog.Debug("OpenTsdb request", "params", tsdbQuery) + } - req, err := e.createRequest(tsdbQuery) - if err != nil { - result.Error = err - return result - } + req, err := e.createRequest(tsdbQuery) + if err != nil { + result.Error = err + return result + } - res, err := HttpClient.Do(req) - if err != nil { - result.Error = err - return result - } + res, err := HttpClient.Do(req) + if err != nil { + result.Error = err + return result + } - queryResult, err := e.parseResponse(tsdbQuery, res) - if err != nil { - return result.WithError(err) - } + queryResult, err := e.parseResponse(tsdbQuery, res) + if err != nil { + return result.WithError(err) + } - result.QueryResults = queryResult - return result + result.QueryResults = queryResult + return result } func (e *OpenTsdbExecutor) createRequest(data OpenTsdbQuery) (*http.Request, error) { - u, _ := url.Parse(e.Url) - u.Path = path.Join(u.Path, "api/query") + u, _ := url.Parse(e.Url) + u.Path = path.Join(u.Path, "api/query") - postData, err := json.Marshal(data) + postData, err := json.Marshal(data) - req, err := http.NewRequest(http.MethodPost, u.String(), strings.NewReader(string(postData))) - if err != nil { - plog.Info("Failed to create request", "error", err) - return nil, fmt.Errorf("Failed to create request. error: %v", err) - } + req, err := http.NewRequest(http.MethodPost, u.String(), strings.NewReader(string(postData))) + if err != nil { + plog.Info("Failed to create request", "error", err) + return nil, fmt.Errorf("Failed to create request. error: %v", err) + } - req.Header.Set("Content-Type", "application/json") - if e.BasicAuth { - req.SetBasicAuth(e.BasicAuthUser, e.BasicAuthPassword) - } + req.Header.Set("Content-Type", "application/json") + if e.BasicAuth { + req.SetBasicAuth(e.BasicAuthUser, e.BasicAuthPassword) + } - /* - requestDump, err := httputil.DumpRequest(req, true) - if err != nil { - fmt.Println(err) - } - fmt.Println(string(requestDump)) - */ - return req, err + /* + requestDump, err := httputil.DumpRequest(req, true) + if err != nil { + fmt.Println(err) + } + fmt.Println(string(requestDump)) + */ + return req, err } func (e *OpenTsdbExecutor) parseResponse(query OpenTsdbQuery, res *http.Response) (map[string]*tsdb.QueryResult, error) { - - queryResults := make(map[string]*tsdb.QueryResult) - queryRes := tsdb.NewQueryResult() - body, err := ioutil.ReadAll(res.Body) - defer res.Body.Close() - if err != nil { - return nil, err - } + queryResults := make(map[string]*tsdb.QueryResult) + queryRes := tsdb.NewQueryResult() - if res.StatusCode/100 != 2 { - plog.Info("Request failed", "status", res.Status, "body", string(body)) - return nil, fmt.Errorf("Request failed status: %v", res.Status) - } + body, err := ioutil.ReadAll(res.Body) + defer res.Body.Close() + if err != nil { + return nil, err + } - var data []OpenTsdbResponse - err = json.Unmarshal(body, &data) - if err != nil { - plog.Info("Failed to unmarshal opentsdb response", "error", err, "status", res.Status, "body", string(body)) - return nil, err - } + if res.StatusCode/100 != 2 { + plog.Info("Request failed", "status", res.Status, "body", string(body)) + return nil, fmt.Errorf("Request failed status: %v", res.Status) + } - for _, val := range data { - series := tsdb.TimeSeries{ - Name: val.Metric, - } + var data []OpenTsdbResponse + err = json.Unmarshal(body, &data) + if err != nil { + plog.Info("Failed to unmarshal opentsdb response", "error", err, "status", res.Status, "body", string(body)) + return nil, err + } - for timeString, value := range val.DataPoints { - timestamp, err := strconv.ParseFloat(timeString, 64) - if err != nil { - plog.Info("Failed to unmarshal opentsdb timestamp", "timestamp", timeString) - return nil, err - } - series.Points = append(series.Points, tsdb.NewTimePoint(null.FloatFrom(value), timestamp)) - } + for _, val := range data { + series := tsdb.TimeSeries{ + Name: val.Metric, + } - queryRes.Series = append(queryRes.Series, &series) - } + for timeString, value := range val.DataPoints { + timestamp, err := strconv.ParseFloat(timeString, 64) + if err != nil { + plog.Info("Failed to unmarshal opentsdb timestamp", "timestamp", timeString) + return nil, err + } + series.Points = append(series.Points, tsdb.NewTimePoint(null.FloatFrom(value), timestamp)) + } - queryResults["A"] = queryRes - return queryResults, nil + queryRes.Series = append(queryRes.Series, &series) + } + + queryResults["A"] = queryRes + return queryResults, nil } From 5e0fa0f0adebfe53ebfa8363abce89c277a01a8d Mon Sep 17 00:00:00 2001 From: bergquist Date: Fri, 14 Oct 2016 10:21:47 +0200 Subject: [PATCH 09/19] feat(opentsdb): context aware http requests --- pkg/tsdb/opentsdb/opentsdb.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/pkg/tsdb/opentsdb/opentsdb.go b/pkg/tsdb/opentsdb/opentsdb.go index bd1684397ce..75d6e8f2711 100644 --- a/pkg/tsdb/opentsdb/opentsdb.go +++ b/pkg/tsdb/opentsdb/opentsdb.go @@ -2,10 +2,14 @@ package opentsdb import ( "context" + "crypto/tls" "fmt" "path" "strconv" "strings" + "time" + + "golang.org/x/net/context/ctxhttp" "io/ioutil" "net/http" @@ -30,12 +34,21 @@ func NewOpenTsdbExecutor(dsInfo *tsdb.DataSourceInfo) tsdb.Executor { var ( plog log.Logger - HttpClient http.Client + HttpClient *http.Client ) func init() { plog = log.New("tsdb.opentsdb") tsdb.RegisterExecutor("opentsdb", NewOpenTsdbExecutor) + + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + + HttpClient = &http.Client{ + Timeout: time.Duration(15 * time.Second), + Transport: tr, + } } func (e *OpenTsdbExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, queryContext *tsdb.QueryContext) *tsdb.BatchResult { @@ -65,7 +78,7 @@ func (e *OpenTsdbExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, return result } - res, err := HttpClient.Do(req) + res, err := ctxhttp.Do(ctx, HttpClient, req) if err != nil { result.Error = err return result From cc0a39f81662b28d64c9d7737995202ec71fef2c Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Sun, 16 Oct 2016 04:12:13 -0700 Subject: [PATCH 10/19] Added downsampling params to alerting --- pkg/tsdb/opentsdb/opentsdb.go | 33 ++++++++++++++++++++++++--------- pkg/tsdb/opentsdb/types.go | 11 +++-------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/pkg/tsdb/opentsdb/opentsdb.go b/pkg/tsdb/opentsdb/opentsdb.go index 75d6e8f2711..55b89fe3390 100644 --- a/pkg/tsdb/opentsdb/opentsdb.go +++ b/pkg/tsdb/opentsdb/opentsdb.go @@ -14,7 +14,7 @@ import ( "io/ioutil" "net/http" "net/url" - //"net/http/httputil" + "net/http/httputil" "encoding/json" "gopkg.in/guregu/null.v3" @@ -58,14 +58,29 @@ func (e *OpenTsdbExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, tsdbQuery.Start = queryContext.TimeRange.GetFromAsMsEpoch() tsdbQuery.End = queryContext.TimeRange.GetToAsMsEpoch() + tsdbQuery.Queries = make([]map[string]interface{}, len(queries)) - for _, query := range queries { - tsdbQuery.Queries = []OpenTsdbMetric{ - OpenTsdbMetric{ - Metric: query.Model.Get("metric").MustString(), - Aggregator: query.Model.Get("aggregator").MustString(), - }, + for i := 0; i < len(queries); i++ { + + metric := make(map[string]interface{}) + + metric["metric"] = queries[i].Model.Get("metric").MustString() + metric["aggregator"] = queries[i].Model.Get("aggregator").MustString() + + disableDownsampling := queries[i].Model.Get("disableDownsampling").MustBool() + + if !disableDownsampling { + downsampleInterval := queries[i].Model.Get("downsampleInterval").MustString() + if downsampleInterval == "" { + downsampleInterval = "1m" //default value for blank + } + downsample := downsampleInterval + "-" + queries[i].Model.Get("downsampleAggregator").MustString() + if queries[i].Model.Get("downsampleFillPolicy").MustString() != "none" { + metric["downsample"] = downsample + "-" + queries[i].Model.Get("downsampleFillPolicy").MustString() + } } + + tsdbQuery.Queries[i] = metric } if setting.Env == setting.DEV { @@ -110,13 +125,13 @@ func (e *OpenTsdbExecutor) createRequest(data OpenTsdbQuery) (*http.Request, err req.SetBasicAuth(e.BasicAuthUser, e.BasicAuthPassword) } - /* + requestDump, err := httputil.DumpRequest(req, true) if err != nil { fmt.Println(err) } fmt.Println(string(requestDump)) - */ + return req, err } diff --git a/pkg/tsdb/opentsdb/types.go b/pkg/tsdb/opentsdb/types.go index 473c797b2d4..abd216dc47d 100644 --- a/pkg/tsdb/opentsdb/types.go +++ b/pkg/tsdb/opentsdb/types.go @@ -1,14 +1,9 @@ package opentsdb type OpenTsdbQuery struct { - Start int64 `json:"start"` - End int64 `json:"end"` - Queries []OpenTsdbMetric `json:"queries"` -} - -type OpenTsdbMetric struct { - Metric string `json:"metric"` - Aggregator string `json:"aggregator"` + Start int64 `json:"start"` + End int64 `json:"end"` + Queries []map[string]interface{} `json:"queries"` } type OpenTsdbResponse struct { From 35f93f41171de843fb9b402d56df4041c49c31fc Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Sun, 16 Oct 2016 05:20:58 -0700 Subject: [PATCH 11/19] Added rate params to alerting --- pkg/tsdb/opentsdb/opentsdb.go | 39 ++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/pkg/tsdb/opentsdb/opentsdb.go b/pkg/tsdb/opentsdb/opentsdb.go index 55b89fe3390..be5ad75aa00 100644 --- a/pkg/tsdb/opentsdb/opentsdb.go +++ b/pkg/tsdb/opentsdb/opentsdb.go @@ -63,14 +63,15 @@ func (e *OpenTsdbExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, for i := 0; i < len(queries); i++ { metric := make(map[string]interface{}) - + + // Setting metric and aggregator metric["metric"] = queries[i].Model.Get("metric").MustString() metric["aggregator"] = queries[i].Model.Get("aggregator").MustString() + // Setting downsampling options disableDownsampling := queries[i].Model.Get("disableDownsampling").MustBool() - if !disableDownsampling { - downsampleInterval := queries[i].Model.Get("downsampleInterval").MustString() + downsampleInterval := queries[i].Model.Get("downsampleInterval").MustString() if downsampleInterval == "" { downsampleInterval = "1m" //default value for blank } @@ -80,6 +81,28 @@ func (e *OpenTsdbExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, } } + // Setting rate options + if queries[i].Model.Get("shouldComputeRate").MustBool() { + metric["rate"] = true + rateOptions := make(map[string]interface{}) + rateOptions["counter"] = queries[i].Model.Get("isCounter").MustBool() + counterMax, counterMaxCheck := queries[i].Model.CheckGet("counterMax") + if counterMaxCheck { + counterMaxVal, err := strconv.ParseFloat(counterMax.MustString(),64) + if err == nil { + rateOptions["counterMax"] = counterMaxVal + } + } + resetValue, resetValueCheck := queries[i].Model.CheckGet("counterResetValue") + if resetValueCheck { + resetValueVal, err := strconv.ParseFloat(resetValue.MustString(),64) + if err == nil { + rateOptions["resetValue"] = resetValueVal + } + } + metric["rateOptions"] = rateOptions + } + tsdbQuery.Queries[i] = metric } @@ -126,11 +149,11 @@ func (e *OpenTsdbExecutor) createRequest(data OpenTsdbQuery) (*http.Request, err } - requestDump, err := httputil.DumpRequest(req, true) - if err != nil { - fmt.Println(err) - } - fmt.Println(string(requestDump)) + requestDump, err := httputil.DumpRequest(req, true) + if err != nil { + fmt.Println(err) + } + fmt.Println(string(requestDump)) return req, err } From b7744b4928c74ad77a097e9f9c4253c0ef07fa30 Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Sun, 16 Oct 2016 10:55:07 -0700 Subject: [PATCH 12/19] Added tags and filters params to alerting --- pkg/tsdb/opentsdb/opentsdb.go | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/pkg/tsdb/opentsdb/opentsdb.go b/pkg/tsdb/opentsdb/opentsdb.go index be5ad75aa00..349592dcde8 100644 --- a/pkg/tsdb/opentsdb/opentsdb.go +++ b/pkg/tsdb/opentsdb/opentsdb.go @@ -14,7 +14,6 @@ import ( "io/ioutil" "net/http" "net/url" - "net/http/httputil" "encoding/json" "gopkg.in/guregu/null.v3" @@ -103,6 +102,18 @@ func (e *OpenTsdbExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, metric["rateOptions"] = rateOptions } + // Setting tags + tags, tagsCheck := queries[i].Model.CheckGet("tags") + if tagsCheck && len(tags.MustMap()) > 0 { + metric["tags"] = tags.MustMap() + } + + // Setting filters + filters, filtersCheck := queries[i].Model.CheckGet("filters") + if filtersCheck && len(filters.MustArray()) > 0 { + metric["filters"] = filters.MustArray() + } + tsdbQuery.Queries[i] = metric } @@ -147,13 +158,6 @@ func (e *OpenTsdbExecutor) createRequest(data OpenTsdbQuery) (*http.Request, err if e.BasicAuth { req.SetBasicAuth(e.BasicAuthUser, e.BasicAuthPassword) } - - - requestDump, err := httputil.DumpRequest(req, true) - if err != nil { - fmt.Println(err) - } - fmt.Println(string(requestDump)) return req, err } From ace81760eaef2ca8153120802e644acad9cb3023 Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Sun, 16 Oct 2016 12:10:13 -0700 Subject: [PATCH 13/19] Added tests file for writing tests --- pkg/tsdb/opentsdb/opentsdb_test.go | 1 + 1 file changed, 1 insertion(+) create mode 100644 pkg/tsdb/opentsdb/opentsdb_test.go diff --git a/pkg/tsdb/opentsdb/opentsdb_test.go b/pkg/tsdb/opentsdb/opentsdb_test.go new file mode 100644 index 00000000000..f28e2eb52cd --- /dev/null +++ b/pkg/tsdb/opentsdb/opentsdb_test.go @@ -0,0 +1 @@ +package opentsdb From 2374d0987766d96c1cd6be78898c95bae3652f27 Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Mon, 17 Oct 2016 14:50:53 -0700 Subject: [PATCH 14/19] Fixed query parsing bugs --- pkg/tsdb/opentsdb/opentsdb.go | 116 ++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 55 deletions(-) diff --git a/pkg/tsdb/opentsdb/opentsdb.go b/pkg/tsdb/opentsdb/opentsdb.go index 349592dcde8..bbd67c8658d 100644 --- a/pkg/tsdb/opentsdb/opentsdb.go +++ b/pkg/tsdb/opentsdb/opentsdb.go @@ -60,61 +60,8 @@ func (e *OpenTsdbExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, tsdbQuery.Queries = make([]map[string]interface{}, len(queries)) for i := 0; i < len(queries); i++ { - - metric := make(map[string]interface{}) - - // Setting metric and aggregator - metric["metric"] = queries[i].Model.Get("metric").MustString() - metric["aggregator"] = queries[i].Model.Get("aggregator").MustString() - - // Setting downsampling options - disableDownsampling := queries[i].Model.Get("disableDownsampling").MustBool() - if !disableDownsampling { - downsampleInterval := queries[i].Model.Get("downsampleInterval").MustString() - if downsampleInterval == "" { - downsampleInterval = "1m" //default value for blank - } - downsample := downsampleInterval + "-" + queries[i].Model.Get("downsampleAggregator").MustString() - if queries[i].Model.Get("downsampleFillPolicy").MustString() != "none" { - metric["downsample"] = downsample + "-" + queries[i].Model.Get("downsampleFillPolicy").MustString() - } - } - - // Setting rate options - if queries[i].Model.Get("shouldComputeRate").MustBool() { - metric["rate"] = true - rateOptions := make(map[string]interface{}) - rateOptions["counter"] = queries[i].Model.Get("isCounter").MustBool() - counterMax, counterMaxCheck := queries[i].Model.CheckGet("counterMax") - if counterMaxCheck { - counterMaxVal, err := strconv.ParseFloat(counterMax.MustString(),64) - if err == nil { - rateOptions["counterMax"] = counterMaxVal - } - } - resetValue, resetValueCheck := queries[i].Model.CheckGet("counterResetValue") - if resetValueCheck { - resetValueVal, err := strconv.ParseFloat(resetValue.MustString(),64) - if err == nil { - rateOptions["resetValue"] = resetValueVal - } - } - metric["rateOptions"] = rateOptions - } - - // Setting tags - tags, tagsCheck := queries[i].Model.CheckGet("tags") - if tagsCheck && len(tags.MustMap()) > 0 { - metric["tags"] = tags.MustMap() - } - - // Setting filters - filters, filtersCheck := queries[i].Model.CheckGet("filters") - if filtersCheck && len(filters.MustArray()) > 0 { - metric["filters"] = filters.MustArray() - } - - tsdbQuery.Queries[i] = metric + metric := e.buildMetric(queries[i]) + tsdbQuery.Queries[i] = metric } if setting.Env == setting.DEV { @@ -205,3 +152,62 @@ func (e *OpenTsdbExecutor) parseResponse(query OpenTsdbQuery, res *http.Response queryResults["A"] = queryRes return queryResults, nil } + +func (e *OpenTsdbExecutor) buildMetric(query *tsdb.Query) (map[string]interface{}) { + + metric := make(map[string]interface{}) + + // Setting metric and aggregator + metric["metric"] = query.Model.Get("metric").MustString() + metric["aggregator"] = query.Model.Get("aggregator").MustString() + + // Setting downsampling options + disableDownsampling := query.Model.Get("disableDownsampling").MustBool() + if !disableDownsampling { + downsampleInterval := query.Model.Get("downsampleInterval").MustString() + if downsampleInterval == "" { + downsampleInterval = "1m" //default value for blank + } + downsample := downsampleInterval + "-" + query.Model.Get("downsampleAggregator").MustString() + if query.Model.Get("downsampleFillPolicy").MustString() != "none" { + metric["downsample"] = downsample + "-" + query.Model.Get("downsampleFillPolicy").MustString() + } else { + metric["downsample"] = downsample + } + } + + // Setting rate options + if query.Model.Get("shouldComputeRate").MustBool() { + + metric["rate"] = true + rateOptions := make(map[string]interface{}) + rateOptions["counter"] = query.Model.Get("isCounter").MustBool() + + counterMax, counterMaxCheck := query.Model.CheckGet("counterMax") + if counterMaxCheck { + rateOptions["counterMax"] = counterMax.MustFloat64() + } + + resetValue, resetValueCheck := query.Model.CheckGet("counterResetValue") + if resetValueCheck { + rateOptions["resetValue"] = resetValue.MustFloat64() + } + + metric["rateOptions"] = rateOptions + } + + // Setting tags + tags, tagsCheck := query.Model.CheckGet("tags") + if tagsCheck && len(tags.MustMap()) > 0 { + metric["tags"] = tags.MustMap() + } + + // Setting filters + filters, filtersCheck := query.Model.CheckGet("filters") + if filtersCheck && len(filters.MustArray()) > 0 { + metric["filters"] = filters.MustArray() + } + + return metric + +} From 10d581dd0a290894a57fa7d204f00bcb1b6cb849 Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Mon, 17 Oct 2016 14:51:51 -0700 Subject: [PATCH 15/19] Added unit tests for query parsing --- pkg/tsdb/opentsdb/opentsdb_test.go | 175 +++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/pkg/tsdb/opentsdb/opentsdb_test.go b/pkg/tsdb/opentsdb/opentsdb_test.go index f28e2eb52cd..905c42b0633 100644 --- a/pkg/tsdb/opentsdb/opentsdb_test.go +++ b/pkg/tsdb/opentsdb/opentsdb_test.go @@ -1 +1,176 @@ package opentsdb + +import ( + "testing" + + "github.com/grafana/grafana/pkg/tsdb" + . "github.com/smartystreets/goconvey/convey" + "github.com/grafana/grafana/pkg/components/simplejson" +) + +func TestOpenTsdbExecutor(t *testing.T) { + Convey("OpenTsdb query testing", t, func() { + + exec := &OpenTsdbExecutor{} + + Convey("Build metric with downsampling enabled", func() { + + query := &tsdb.Query{ + Model: simplejson.New(), + } + + query.Model.Set("metric", "cpu.average.percent") + query.Model.Set("aggregator", "avg") + query.Model.Set("disableDownsampling", false) + query.Model.Set("downsampleInterval", "") + query.Model.Set("downsampleAggregator","avg") + query.Model.Set("downsampleFillPolicy","none") + + metric := exec.buildMetric(query) + + So(len(metric), ShouldEqual, 3) + So(metric["metric"], ShouldEqual, "cpu.average.percent") + So(metric["aggregator"], ShouldEqual, "avg") + So(metric["downsample"], ShouldEqual, "1m-avg") + + }) + + Convey("Build metric with downsampling diabled", func() { + + query := &tsdb.Query{ + Model: simplejson.New(), + } + + query.Model.Set("metric", "cpu.average.percent") + query.Model.Set("aggregator", "avg") + query.Model.Set("disableDownsampling", true) + query.Model.Set("downsampleInterval", "") + query.Model.Set("downsampleAggregator","avg") + query.Model.Set("downsampleFillPolicy","none") + + metric := exec.buildMetric(query) + + So(len(metric), ShouldEqual, 2) + So(metric["metric"], ShouldEqual, "cpu.average.percent") + So(metric["aggregator"], ShouldEqual, "avg") + + }) + + Convey("Build metric with downsampling enabled with params", func() { + + query := &tsdb.Query{ + Model: simplejson.New(), + } + + query.Model.Set("metric", "cpu.average.percent") + query.Model.Set("aggregator", "avg") + query.Model.Set("disableDownsampling", false) + query.Model.Set("downsampleInterval", "5m") + query.Model.Set("downsampleAggregator","sum") + query.Model.Set("downsampleFillPolicy","null") + + metric := exec.buildMetric(query) + + So(len(metric), ShouldEqual, 3) + So(metric["metric"], ShouldEqual, "cpu.average.percent") + So(metric["aggregator"], ShouldEqual, "avg") + So(metric["downsample"], ShouldEqual, "5m-sum-null") + }) + + Convey("Build metric with tags with downsampling disabled", func() { + + query := &tsdb.Query{ + Model: simplejson.New(), + } + + query.Model.Set("metric", "cpu.average.percent") + query.Model.Set("aggregator", "avg") + query.Model.Set("disableDownsampling", true) + query.Model.Set("downsampleInterval", "5m") + query.Model.Set("downsampleAggregator","sum") + query.Model.Set("downsampleFillPolicy","null") + + tags := simplejson.New() + tags.Set("env", "prod") + tags.Set("app", "grafana") + query.Model.Set("tags", tags.MustMap()) + + metric := exec.buildMetric(query) + + So(len(metric), ShouldEqual, 3) + So(metric["metric"], ShouldEqual, "cpu.average.percent") + So(metric["aggregator"], ShouldEqual, "avg") + So(metric["downsample"], ShouldEqual, nil) + So(len(metric["tags"].(map[string]interface{})), ShouldEqual, 2) + So(metric["tags"].(map[string]interface{})["env"], ShouldEqual, "prod") + So(metric["tags"].(map[string]interface{})["app"], ShouldEqual, "grafana") + So(metric["tags"].(map[string]interface{})["ip"], ShouldEqual, nil) + }) + + Convey("Build metric with rate enabled but counter disabled", func() { + + query := &tsdb.Query{ + Model: simplejson.New(), + } + + query.Model.Set("metric", "cpu.average.percent") + query.Model.Set("aggregator", "avg") + query.Model.Set("disableDownsampling", true) + query.Model.Set("shouldComputeRate", true) + query.Model.Set("isCounter",false) + + tags := simplejson.New() + tags.Set("env", "prod") + tags.Set("app", "grafana") + query.Model.Set("tags", tags.MustMap()) + + metric := exec.buildMetric(query) + + So(len(metric), ShouldEqual, 5) + So(metric["metric"], ShouldEqual, "cpu.average.percent") + So(metric["aggregator"], ShouldEqual, "avg") + So(len(metric["tags"].(map[string]interface{})), ShouldEqual, 2) + So(metric["tags"].(map[string]interface{})["env"], ShouldEqual, "prod") + So(metric["tags"].(map[string]interface{})["app"], ShouldEqual, "grafana") + So(metric["tags"].(map[string]interface{})["ip"], ShouldEqual, nil) + So(metric["rate"], ShouldEqual, true) + So(metric["rateOptions"].(map[string]interface{})["counter"], ShouldEqual, false) + }) + + Convey("Build metric with rate and counter enabled", func() { + + query := &tsdb.Query{ + Model: simplejson.New(), + } + + query.Model.Set("metric", "cpu.average.percent") + query.Model.Set("aggregator", "avg") + query.Model.Set("disableDownsampling", true) + query.Model.Set("shouldComputeRate", true) + query.Model.Set("isCounter",true) + query.Model.Set("counterMax",45) + query.Model.Set("counterResetValue",60) + + tags := simplejson.New() + tags.Set("env", "prod") + tags.Set("app", "grafana") + query.Model.Set("tags", tags.MustMap()) + + metric := exec.buildMetric(query) + + So(len(metric), ShouldEqual, 5) + So(metric["metric"], ShouldEqual, "cpu.average.percent") + So(metric["aggregator"], ShouldEqual, "avg") + So(len(metric["tags"].(map[string]interface{})), ShouldEqual, 2) + So(metric["tags"].(map[string]interface{})["env"], ShouldEqual, "prod") + So(metric["tags"].(map[string]interface{})["app"], ShouldEqual, "grafana") + So(metric["tags"].(map[string]interface{})["ip"], ShouldEqual, nil) + So(metric["rate"], ShouldEqual, true) + So(len(metric["rateOptions"].(map[string]interface{})), ShouldEqual, 3) + So(metric["rateOptions"].(map[string]interface{})["counter"], ShouldEqual, true) + So(metric["rateOptions"].(map[string]interface{})["counterMax"], ShouldEqual, 45) + So(metric["rateOptions"].(map[string]interface{})["resetValue"], ShouldEqual, 60) + }) + + }) +} \ No newline at end of file From 333a853948c051f1650f72da6ba0f64603891d3b Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Tue, 18 Oct 2016 08:47:45 -0700 Subject: [PATCH 16/19] Fixed for loop and append --- pkg/tsdb/opentsdb/opentsdb.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pkg/tsdb/opentsdb/opentsdb.go b/pkg/tsdb/opentsdb/opentsdb.go index bbd67c8658d..3ecd52ca723 100644 --- a/pkg/tsdb/opentsdb/opentsdb.go +++ b/pkg/tsdb/opentsdb/opentsdb.go @@ -57,11 +57,10 @@ func (e *OpenTsdbExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, tsdbQuery.Start = queryContext.TimeRange.GetFromAsMsEpoch() tsdbQuery.End = queryContext.TimeRange.GetToAsMsEpoch() - tsdbQuery.Queries = make([]map[string]interface{}, len(queries)) - for i := 0; i < len(queries); i++ { - metric := e.buildMetric(queries[i]) - tsdbQuery.Queries[i] = metric + for _ , query := range queries { + metric := e.buildMetric(query) + tsdbQuery.Queries = append(tsdbQuery.Queries, metric) } if setting.Env == setting.DEV { From 4c2f2eeb58dc284b54399047311bc8d727152635 Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 19 Oct 2016 11:45:39 +0200 Subject: [PATCH 17/19] feat(opentsdb): add mock method for detecting targets with template values --- public/app/plugins/datasource/opentsdb/datasource.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/app/plugins/datasource/opentsdb/datasource.js b/public/app/plugins/datasource/opentsdb/datasource.js index 8620817c83e..0713820afaa 100644 --- a/public/app/plugins/datasource/opentsdb/datasource.js +++ b/public/app/plugins/datasource/opentsdb/datasource.js @@ -102,6 +102,11 @@ function (angular, _, dateMath) { }.bind(this)); }; + this.targetContainsTemplate = function(target) { + console.log(target); + return false; + }; + this.performTimeSeriesQuery = function(queries, start, end) { var msResolution = false; if (this.tsdbResolution === 2) { From 62895114e1e88b0af7d8eb80f5f201f0e071a991 Mon Sep 17 00:00:00 2001 From: utkarshcmu Date: Wed, 19 Oct 2016 03:54:41 -0700 Subject: [PATCH 18/19] Implmented targetContainsTemplate for OpenTSDB --- .../plugins/datasource/opentsdb/datasource.js | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/public/app/plugins/datasource/opentsdb/datasource.js b/public/app/plugins/datasource/opentsdb/datasource.js index 0713820afaa..eb2f88f8067 100644 --- a/public/app/plugins/datasource/opentsdb/datasource.js +++ b/public/app/plugins/datasource/opentsdb/datasource.js @@ -103,8 +103,24 @@ function (angular, _, dateMath) { }; this.targetContainsTemplate = function(target) { - console.log(target); - return false; + // Checking for template variables in filters + if (target.filters.length > 0) { + for (var i = 0; i < target.filters.length; i++) { + if (templateSrv.variableExists(target.filters[i].filter)) { + return true; + } + } + } + // Checking for template variables in tags + else if (Object.keys(target.tags).length > 0) { + for (var tagKey in target.tags) { + if (templateSrv.variableExists(target.tags[tagKey])) { + return true; + } + } + } else { + return false; + } }; this.performTimeSeriesQuery = function(queries, start, end) { From 5fbab038e8bfeb7a7a56aebed1c61a264b0ad59d Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 19 Oct 2016 13:14:42 +0200 Subject: [PATCH 19/19] fix(opentsdb): can always return false --- public/app/plugins/datasource/opentsdb/datasource.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/public/app/plugins/datasource/opentsdb/datasource.js b/public/app/plugins/datasource/opentsdb/datasource.js index eb2f88f8067..d5034ce271f 100644 --- a/public/app/plugins/datasource/opentsdb/datasource.js +++ b/public/app/plugins/datasource/opentsdb/datasource.js @@ -103,24 +103,23 @@ function (angular, _, dateMath) { }; this.targetContainsTemplate = function(target) { - // Checking for template variables in filters - if (target.filters.length > 0) { + if (target.filters && target.filters.length > 0) { for (var i = 0; i < target.filters.length; i++) { if (templateSrv.variableExists(target.filters[i].filter)) { return true; } } } - // Checking for template variables in tags - else if (Object.keys(target.tags).length > 0) { + + if (target.tags && Object.keys(target.tags).length > 0) { for (var tagKey in target.tags) { if (templateSrv.variableExists(target.tags[tagKey])) { return true; } } - } else { - return false; } + + return false; }; this.performTimeSeriesQuery = function(queries, start, end) {