Skip to content

Commit

Permalink
Merge pull request #105 from circonus-labs/CIRC-9142
Browse files Browse the repository at this point in the history
CIRC-9142: Remove call to graphite_translate from alerting backend
  • Loading branch information
dhaifley authored Sep 20, 2022
2 parents 71291ae + 70b69ce commit 82112fd
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 77 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@

## 0.9.24

* Eliminates the need for a call to the graphite_translate IRONdb extension
in the alerting backend for Graphite style queries.
* Ensures that all CAQL queries issued via the API /caql endpoint by the
alerting backend contain a #min_period prefix if a min_period value has been
defined for the Grafana query object.
* Adds handling for the possibility of null or non-numeric data values being
returned to the alerting backend by its calls to the API /caql endpoint.

## 0.9.19

* Updates dependencies to latest versions.
Expand Down
4 changes: 2 additions & 2 deletions dist/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
{ "name": "Project site", "url": "https://www.circonus.com/irondb/" },
{ "name": "License", "url": "https://github.com/circonus-labs/circonusllhist/blob/master/LICENSE" }
],
"version": "0.9.23",
"updated": "2022-09-15"
"version": "0.9.24",
"updated": "2022-09-20"
},

"dependencies": {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "circonus-irondb-datasource",
"version": "0.9.23",
"version": "0.9.24",
"description": "IRONdb Data Source for Grafana.",
"scripts": {
"build": "grafana-toolkit plugin:build",
Expand Down
107 changes: 35 additions & 72 deletions pkg/irondb-backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,43 +210,11 @@ func (td *SampleDatasource) caqlQuery(ctx context.Context, q backend.DataQuery)
return nil, fmt.Errorf("key query missing from CAQL query: %w", err)
}

// If needed include min_period setting in the CAQL query.
if !strings.HasPrefix(query, "#min_period=") {
// Does the panel have a min_period set?
minPeriod, err := jsonp.GetString(q.JSON, "min_period")
if err != nil {
if err != jsonp.KeyPathNotFoundError {
log.DefaultLogger.Error("unable to parse CAQL query min_period",
"error", err)
return nil, fmt.Errorf("unable to parse CAQL query min_period: %w", err)
}
// Not set
} else {
if minPeriod != "" {
query = "#min_period=" + minPeriod + " " + query
}
}
}

log.DefaultLogger.Info("caqlQuery", "caql", query)

return td.caqlAPI(ctx, q, query)
}

// TranslateResponse values represent a response from the IRONdb graphite
// translator service
type TranslateResponse struct {
Input string `json:"input"`
CAQL string `json:"caql"`
Error string `json:"error"`
}

// TranslateRequest values represent a request to the IRONdb graphite
// translator service
type TranslateRequest struct {
Query string `json:"q"`
}

func (td *SampleDatasource) graphiteQuery(ctx context.Context, q backend.DataQuery) (*backend.DataResponse, error) {
query, err := jsonp.GetString(q.JSON, "query")
if err != nil {
Expand All @@ -255,55 +223,32 @@ func (td *SampleDatasource) graphiteQuery(ctx context.Context, q backend.DataQue
return nil, fmt.Errorf("key query missing from graphite query: %w", err)
}

// Convert the graphite query to CAQL using IRONdb graphite_translate.
graphiteURL := &url.URL{Path: "irondb/extension/lua/public/graphite_translate"}
query = strings.ReplaceAll(query, " ", "")
t := TranslateRequest{Query: query}

reqBody, err := json.Marshal(t)
if err != nil {
log.DefaultLogger.Error("unable to marshal graphite translate request",
"error", err, "request", graphiteURL.String(), "body", string(reqBody))
return nil, fmt.Errorf("unable to marshal graphite translate request: %w", err)
}

respData, err := td.circ.Post(graphiteURL.String(), reqBody)
if err != nil {
log.DefaultLogger.Error("error returned from graphite translate",
"error", err, "request", graphiteURL.String(), "body", string(reqBody))
return nil, fmt.Errorf("error returned from graphite translate: %w", err)
tagFilter, err := jsonp.GetString(q.JSON, "tagFilter")
if err != nil && err != jsonp.KeyPathNotFoundError {
log.DefaultLogger.Error("unable to get tagFilter for graphite query",
"error", err, "query", string(q.JSON))
return nil, fmt.Errorf("unable to get tagFilter for graphite query: %w", err)
}

var resp TranslateResponse
if err := json.Unmarshal(respData, &resp); err != nil {
log.DefaultLogger.Error("unable to unmarshal graphite translate response",
"error", err, "response", string(respData))
return nil, fmt.Errorf("unable to unmarshal graphite translate response: %w", err)
}
// Convert the graphite query to an equivalent CAQL query.
caqlQ := "graphite:find('" + strings.ReplaceAll(query, " ", "") + "'"

if resp.CAQL == "" {
err := fmt.Errorf("unable to translate graphite query: null CAQL response")
log.DefaultLogger.Error(err.Error(), "error", err, "response", string(respData))
return nil, err
if tagFilter != "" {
caqlQ += ",'" + tagFilter + "'"
}

if resp.Error != "" {
err := fmt.Errorf(resp.Error)
log.DefaultLogger.Error("error translating graphite query",
"error", err, "response", string(respData))
return nil, fmt.Errorf("error translating graphite query: %w", err)
}
caqlQ += ")"

log.DefaultLogger.Info("graphiteQuery", "graphite", query, "caql", resp.CAQL)
log.DefaultLogger.Info("graphiteQuery", "graphite", query, "caql", caqlQ)

return td.caqlAPI(ctx, q, resp.CAQL)
return td.caqlAPI(ctx, q, caqlQ)
}

type DF4Response struct {
Version string `json:"version"`
Data [][]float64 `json:"data"`
Meta []DF4Meta `json:"meta"`
Head DF4Head `json:"head"`
Version string `json:"version"`
Data [][]interface{} `json:"data"`
Meta []DF4Meta `json:"meta"`
Head DF4Head `json:"head"`
}

type DF4Head struct {
Expand All @@ -319,6 +264,19 @@ type DF4Meta struct {
}

func (td *SampleDatasource) caqlAPI(_ context.Context, q backend.DataQuery, query string) (*backend.DataResponse, error) {
// If needed include min_period setting in the CAQL query.
if !strings.HasPrefix(query, "#min_period=") {
minPeriod, err := jsonp.GetString(q.JSON, "min_period")
if err != nil && err != jsonp.KeyPathNotFoundError {
log.DefaultLogger.Error("unable to parse CAQL query min_period", "error", err)
return nil, fmt.Errorf("unable to parse CAQL query min_period: %w", err)
}

if minPeriod != "" {
query = "#min_period=" + minPeriod + " " + query
}
}

// https://docs.circonus.com/circonus/api/#/CAQL
qp := url.Values{}
qp.Set("query", query)
Expand Down Expand Up @@ -371,8 +329,13 @@ func (td *SampleDatasource) caqlAPI(_ context.Context, q backend.DataQuery, quer
ts := resp.Head.Start
for _, sample := range resp.Data[id] {
times = append(times, time.Unix(int64(ts), 0))
values = append(values, sample)
ts += resp.Head.Period

if val, ok := sample.(float64); ok {
values = append(values, val)
} else {
values = append(values, 0)
}
}
tags := make(map[string]string)
for _, tag := range meta.Tags {
Expand Down
4 changes: 2 additions & 2 deletions src/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
{ "name": "Project site", "url": "https://www.circonus.com/irondb/" },
{ "name": "License", "url": "https://github.com/circonus-labs/circonusllhist/blob/master/LICENSE" }
],
"version": "0.9.23",
"updated": "2022-09-15"
"version": "0.9.24",
"updated": "2022-09-20"
},

"dependencies": {
Expand Down

0 comments on commit 82112fd

Please sign in to comment.