Skip to content

Commit

Permalink
fix: handle custom query params in annotation queries (#96)
Browse files Browse the repository at this point in the history

Co-authored-by: hagen1778 <[email protected]>
  • Loading branch information
Loori-R and hagen1778 authored Sep 4, 2023
1 parent 0441429 commit 23e35c8
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 14 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## tip

* BUGFIX: correctly handle custom query parameters in annotation queries. See [this issue](https://github.com/VictoriaMetrics/grafana-datasource/issues/95)

## [v0.3.0](https://github.com/VictoriaMetrics/grafana-datasource/releases/tag/v0.3.0)

* FEATURE: Improvements to WITH Templates (see [this comment](https://github.com/VictoriaMetrics/grafana-datasource/issues/35#issuecomment-1578649762)):
Expand Down
16 changes: 9 additions & 7 deletions pkg/plugin/datasource.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,21 @@ func (d *Datasource) query(ctx context.Context, query backend.DataQuery) backend
return newResponseError(err, backend.StatusBadRequest)
}

reqURL, err := q.getQueryURL(minInterval, d.settings.URL)
if err != nil {
err = fmt.Errorf("failed to create request url: %w", err)
return newResponseError(err, backend.StatusBadRequest)
}

httpMethod := http.MethodPost
var settingsData struct {
HTTPMethod string `json:"httpMethod"`
HTTPMethod string `json:"httpMethod"`
CustomQueryParameters string `json:"customQueryParameters"`
}
if err := json.Unmarshal(d.settings.JSONData, &settingsData); err == nil && settingsData.HTTPMethod != "" {
httpMethod = settingsData.HTTPMethod
}
customQueryParameters := settingsData.CustomQueryParameters

reqURL, err := q.getQueryURL(minInterval, d.settings.URL, customQueryParameters)
if err != nil {
err = fmt.Errorf("failed to create request url: %w", err)
return newResponseError(err, backend.StatusBadRequest)
}

req, err := http.NewRequestWithContext(ctx, httpMethod, reqURL, nil)
if err != nil {
Expand Down
27 changes: 22 additions & 5 deletions pkg/plugin/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"strconv"
"strings"
"time"

"github.com/grafana/grafana-plugin-sdk-go/backend/log"
)

const (
Expand Down Expand Up @@ -37,7 +39,7 @@ type TimeRange struct {

// GetQueryURL calculates step and clear expression from template variables,
// and after builds query url depends on query type
func (q *Query) getQueryURL(minInterval time.Duration, rawURL string) (string, error) {
func (q *Query) getQueryURL(minInterval time.Duration, rawURL string, customQueryParams string) (string, error) {
if rawURL == "" {
return "", fmt.Errorf("url can't be blank")
}
Expand All @@ -59,9 +61,9 @@ func (q *Query) getQueryURL(minInterval time.Duration, rawURL string) (string, e
}

if q.Instant {
return q.queryInstantURL(expr, step), nil
return q.queryInstantURL(expr, step, customQueryParams), nil
}
return q.queryRangeURL(expr, step), nil
return q.queryRangeURL(expr, step, customQueryParams), nil
}

// withIntervalVariable checks does query has interval variable
Expand All @@ -79,27 +81,29 @@ func (q *Query) calculateMinInterval() (time.Duration, error) {
}

// queryInstantURL prepare query url for instant query
func (q *Query) queryInstantURL(expr string, step time.Duration) string {
func (q *Query) queryInstantURL(expr string, step time.Duration, customQueryParams string) string {
q.url.Path = path.Join(q.url.Path, instantQueryPath)
values := q.url.Query()

values.Add("query", expr)
values.Add("time", strconv.FormatInt(q.TimeRange.To.Unix(), 10))
values.Add("step", step.String())
addCustomParams(values, customQueryParams)

q.url.RawQuery = values.Encode()
return q.url.String()
}

// queryRangeURL prepare query url for range query
func (q *Query) queryRangeURL(expr string, step time.Duration) string {
func (q *Query) queryRangeURL(expr string, step time.Duration, customQueryParams string) string {
q.url.Path = path.Join(q.url.Path, rangeQueryPath)
values := q.url.Query()

values.Add("query", expr)
values.Add("start", strconv.FormatInt(q.TimeRange.From.Unix(), 10))
values.Add("end", strconv.FormatInt(q.TimeRange.To.Unix(), 10))
values.Add("step", step.String())
addCustomParams(values, customQueryParams)

q.url.RawQuery = values.Encode()
return q.url.String()
Expand All @@ -115,3 +119,16 @@ func (q *Query) parseLegend() string {
}
return legend
}

func addCustomParams(values url.Values, customQueryParams string) url.Values {
params, err := url.ParseQuery(customQueryParams)
if err != nil {
log.DefaultLogger.Error("failed to parse custom query params", "err", err.Error())
}
for key, valueList := range params {
for _, value := range valueList {
values.Add(key, value)
}
}
return values
}
2 changes: 1 addition & 1 deletion pkg/plugin/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func TestQuery_getQueryURL(t *testing.T) {
TimeRange: tt.fields.getTimeRange(),
url: tt.fields.url,
}
got, err := q.getQueryURL(tt.args.minInterval, tt.args.rawURL)
got, err := q.getQueryURL(tt.args.minInterval, tt.args.rawURL, "")
if (err != nil) != tt.wantErr {
t.Errorf("getQueryURL() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down
2 changes: 1 addition & 1 deletion src/configuration/PromSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export const PromSettings = (props: Props) => {
<FormField
label="Custom query parameters"
labelWidth={14}
tooltip="Add Custom parameters to all Prometheus or Thanos queries."
tooltip="Add Custom parameters to all queries."
inputEl={
<Input
className="width-25"
Expand Down

0 comments on commit 23e35c8

Please sign in to comment.