* loki: fixed param-name
* loki: handle datasource configs with path in the url
* lint fix
(cherry picked from commit ccc587dc0f)
This commit is contained in:
+12
-7
@@ -8,6 +8,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
@@ -68,12 +69,12 @@ func makeDataRequest(ctx context.Context, lokiDsUrl string, query lokiQuery, oau
|
|||||||
// precise, as Loki does not support step with float number
|
// precise, as Loki does not support step with float number
|
||||||
// and time-specifier, like "1.5s"
|
// and time-specifier, like "1.5s"
|
||||||
qs.Set("step", fmt.Sprintf("%dms", query.Step.Milliseconds()))
|
qs.Set("step", fmt.Sprintf("%dms", query.Step.Milliseconds()))
|
||||||
lokiUrl.Path = "/loki/api/v1/query_range"
|
lokiUrl.Path = path.Join(lokiUrl.Path, "/loki/api/v1/query_range")
|
||||||
}
|
}
|
||||||
case QueryTypeInstant:
|
case QueryTypeInstant:
|
||||||
{
|
{
|
||||||
qs.Set("time", strconv.FormatInt(query.End.UnixNano(), 10))
|
qs.Set("time", strconv.FormatInt(query.End.UnixNano(), 10))
|
||||||
lokiUrl.Path = "/loki/api/v1/query"
|
lokiUrl.Path = path.Join(lokiUrl.Path, "/loki/api/v1/query")
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("invalid QueryType: %v", query.QueryType)
|
return nil, fmt.Errorf("invalid QueryType: %v", query.QueryType)
|
||||||
@@ -169,18 +170,22 @@ func (api *LokiAPI) DataQuery(ctx context.Context, query lokiQuery) (data.Frames
|
|||||||
return res.Frames, nil
|
return res.Frames, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeRawRequest(ctx context.Context, lokiDsUrl string, resourceURL string, oauthToken string) (*http.Request, error) {
|
func makeRawRequest(ctx context.Context, lokiDsUrl string, resourcePath string, oauthToken string) (*http.Request, error) {
|
||||||
lokiUrl, err := url.Parse(lokiDsUrl)
|
lokiUrl, err := url.Parse(lokiDsUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
url, err := lokiUrl.Parse(resourceURL)
|
resourceUrl, err := url.Parse(resourcePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", url.String(), nil)
|
// we take the path and the query-string only
|
||||||
|
lokiUrl.RawQuery = resourceUrl.RawQuery
|
||||||
|
lokiUrl.Path = path.Join(lokiUrl.Path, resourceUrl.Path)
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", lokiUrl.String(), nil)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -191,8 +196,8 @@ func makeRawRequest(ctx context.Context, lokiDsUrl string, resourceURL string, o
|
|||||||
return req, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *LokiAPI) RawQuery(ctx context.Context, resourceURL string) ([]byte, error) {
|
func (api *LokiAPI) RawQuery(ctx context.Context, resourcePath string) ([]byte, error) {
|
||||||
req, err := makeRawRequest(ctx, api.url, resourceURL, api.oauthToken)
|
req, err := makeRawRequest(ctx, api.url, resourcePath, api.oauthToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,9 +33,13 @@ func (mockedRT *mockedRoundTripper) RoundTrip(req *http.Request) (*http.Response
|
|||||||
}
|
}
|
||||||
|
|
||||||
func makeMockedAPI(statusCode int, contentType string, responseBytes []byte, requestCallback mockRequestCallback) *LokiAPI {
|
func makeMockedAPI(statusCode int, contentType string, responseBytes []byte, requestCallback mockRequestCallback) *LokiAPI {
|
||||||
|
return makeMockedAPIWithUrl("http://localhost:9999", statusCode, contentType, responseBytes, requestCallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeMockedAPIWithUrl(url string, statusCode int, contentType string, responseBytes []byte, requestCallback mockRequestCallback) *LokiAPI {
|
||||||
client := http.Client{
|
client := http.Client{
|
||||||
Transport: &mockedRoundTripper{statusCode: statusCode, contentType: contentType, responseBytes: responseBytes, requestCallback: requestCallback},
|
Transport: &mockedRoundTripper{statusCode: statusCode, contentType: contentType, responseBytes: responseBytes, requestCallback: requestCallback},
|
||||||
}
|
}
|
||||||
|
|
||||||
return newLokiAPI(&client, "http://localhost:9999", log.New("test"), "")
|
return newLokiAPI(&client, url, log.New("test"), "")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
package loki
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestApiLogVolume(t *testing.T) {
|
||||||
|
response := []byte(`
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"data": {
|
||||||
|
"resultType" : "matrix",
|
||||||
|
"result": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
t.Run("log-volume queries should set log-volume http header", func(t *testing.T) {
|
||||||
|
called := false
|
||||||
|
api := makeMockedAPI(200, "application/json", response, func(req *http.Request) {
|
||||||
|
called = true
|
||||||
|
require.Equal(t, "Source=logvolhist", req.Header.Get("X-Query-Tags"))
|
||||||
|
})
|
||||||
|
|
||||||
|
_, err := api.DataQuery(context.Background(), lokiQuery{Expr: "", VolumeQuery: true, QueryType: QueryTypeRange})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, called)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("non-log-volume queries should not set log-volume http header", func(t *testing.T) {
|
||||||
|
called := false
|
||||||
|
api := makeMockedAPI(200, "application/json", response, func(req *http.Request) {
|
||||||
|
called = true
|
||||||
|
require.Equal(t, "", req.Header.Get("X-Query-Tags"))
|
||||||
|
})
|
||||||
|
|
||||||
|
_, err := api.DataQuery(context.Background(), lokiQuery{Expr: "", VolumeQuery: false, QueryType: QueryTypeRange})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, called)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApiUrlHandling(t *testing.T) {
|
||||||
|
response := []byte(`
|
||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"data": {
|
||||||
|
"resultType" : "matrix",
|
||||||
|
"result": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
queryTestData := []struct {
|
||||||
|
name string
|
||||||
|
dsUrl string
|
||||||
|
queryPrefix string
|
||||||
|
metaUrl string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no path in datasource-config",
|
||||||
|
dsUrl: "http://localhost:3100",
|
||||||
|
queryPrefix: "http://localhost:3100/loki/api/v1/query_range?",
|
||||||
|
metaUrl: "http://localhost:3100/loki/api/v1/labels?start=1&end=2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "just a slash path in datasource-config",
|
||||||
|
dsUrl: "http://localhost:3100/",
|
||||||
|
queryPrefix: "http://localhost:3100/loki/api/v1/query_range?",
|
||||||
|
metaUrl: "http://localhost:3100/loki/api/v1/labels?start=1&end=2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "when path-without-end-slash in datasource-config",
|
||||||
|
dsUrl: "http://localhost:3100/a/b/c",
|
||||||
|
queryPrefix: "http://localhost:3100/a/b/c/loki/api/v1/query_range?",
|
||||||
|
metaUrl: "http://localhost:3100/a/b/c/loki/api/v1/labels?start=1&end=2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "path-with-end-slash in datasource-config",
|
||||||
|
dsUrl: "http://localhost:3100/a/b/c/",
|
||||||
|
queryPrefix: "http://localhost:3100/a/b/c/loki/api/v1/query_range?",
|
||||||
|
metaUrl: "http://localhost:3100/a/b/c/loki/api/v1/labels?start=1&end=2",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range queryTestData {
|
||||||
|
t.Run("Loki should build the query URL correctly when "+test.name, func(t *testing.T) {
|
||||||
|
called := false
|
||||||
|
api := makeMockedAPIWithUrl(test.dsUrl, 200, "application/json", response, func(req *http.Request) {
|
||||||
|
called = true
|
||||||
|
urlString := req.URL.String()
|
||||||
|
wantedPrefix := test.queryPrefix
|
||||||
|
failMessage := fmt.Sprintf(`wanted prefix: [%s], got string [%s]`, wantedPrefix, urlString)
|
||||||
|
require.True(t, strings.HasPrefix(urlString, wantedPrefix), failMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
query := lokiQuery{
|
||||||
|
QueryType: QueryTypeRange,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := api.DataQuery(context.Background(), query)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, called)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range queryTestData {
|
||||||
|
t.Run("Loki should build the metadata query URL correctly when "+test.name, func(t *testing.T) {
|
||||||
|
called := false
|
||||||
|
api := makeMockedAPIWithUrl(test.dsUrl, 200, "application/json", response, func(req *http.Request) {
|
||||||
|
called = true
|
||||||
|
require.Equal(t, test.metaUrl, req.URL.String())
|
||||||
|
})
|
||||||
|
|
||||||
|
_, err := api.RawQuery(context.Background(), "/loki/api/v1/labels?start=1&end=2")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, called)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user