mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
loki: send metadata requests through backend (#48063)
This commit is contained in:
parent
c5547123bc
commit
d8a754c4a0
@ -25,7 +25,7 @@ func newLokiAPI(client *http.Client, url string, log log.Logger) *LokiAPI {
|
|||||||
return &LokiAPI{client: client, url: url, log: log}
|
return &LokiAPI{client: client, url: url, log: log}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeRequest(ctx context.Context, lokiDsUrl string, query lokiQuery) (*http.Request, error) {
|
func makeDataRequest(ctx context.Context, lokiDsUrl string, query lokiQuery) (*http.Request, error) {
|
||||||
qs := url.Values{}
|
qs := url.Values{}
|
||||||
qs.Set("query", query.Expr)
|
qs.Set("query", query.Expr)
|
||||||
|
|
||||||
@ -135,8 +135,8 @@ func makeLokiError(body io.ReadCloser) error {
|
|||||||
return fmt.Errorf("%v", errorMessage)
|
return fmt.Errorf("%v", errorMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *LokiAPI) Query(ctx context.Context, query lokiQuery) (*loghttp.QueryResponse, error) {
|
func (api *LokiAPI) DataQuery(ctx context.Context, query lokiQuery) (*loghttp.QueryResponse, error) {
|
||||||
req, err := makeRequest(ctx, api.url, query)
|
req, err := makeDataRequest(ctx, api.url, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -164,3 +164,41 @@ func (api *LokiAPI) Query(ctx context.Context, query lokiQuery) (*loghttp.QueryR
|
|||||||
|
|
||||||
return &response, nil
|
return &response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeRawRequest(ctx context.Context, lokiDsUrl string, resourceURL string) (*http.Request, error) {
|
||||||
|
lokiUrl, err := url.Parse(lokiDsUrl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
url, err := lokiUrl.Parse(resourceURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.NewRequestWithContext(ctx, "GET", url.String(), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *LokiAPI) RawQuery(ctx context.Context, resourceURL string) ([]byte, error) {
|
||||||
|
req, err := makeRawRequest(ctx, api.url, resourceURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := api.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := resp.Body.Close(); err != nil {
|
||||||
|
api.log.Warn("Failed to close response body", "err", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if resp.StatusCode/100 != 2 {
|
||||||
|
return nil, makeLokiError(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
return io.ReadAll(resp.Body)
|
||||||
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
@ -25,8 +26,9 @@ type Service struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ backend.QueryDataHandler = (*Service)(nil)
|
_ backend.QueryDataHandler = (*Service)(nil)
|
||||||
_ backend.StreamHandler = (*Service)(nil)
|
_ backend.StreamHandler = (*Service)(nil)
|
||||||
|
_ backend.CallResourceHandler = (*Service)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProvideService(httpClientProvider httpclient.Provider, tracer tracing.Tracer) *Service {
|
func ProvideService(httpClientProvider httpclient.Provider, tracer tracing.Tracer) *Service {
|
||||||
@ -89,6 +91,40 @@ func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.Inst
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
|
||||||
|
url := req.URL
|
||||||
|
|
||||||
|
// a very basic is-this-url-valid check
|
||||||
|
if req.Method != "GET" {
|
||||||
|
return fmt.Errorf("invalid resource method: %s", req.Method)
|
||||||
|
}
|
||||||
|
if (!strings.HasPrefix(url, "/loki/api/v1/label?")) &&
|
||||||
|
(!strings.HasPrefix(url, "/loki/api/v1/label/")) && // the `/label/$label_name/values` form
|
||||||
|
(!strings.HasPrefix(url, "/loki/api/v1/series?")) {
|
||||||
|
return fmt.Errorf("invalid resource URL: %s", url)
|
||||||
|
}
|
||||||
|
|
||||||
|
dsInfo, err := s.getDSInfo(req.PluginContext)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
api := newLokiAPI(dsInfo.HTTPClient, dsInfo.URL, s.plog)
|
||||||
|
bytes, err := api.RawQuery(ctx, url)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sender.Send(&backend.CallResourceResponse{
|
||||||
|
Status: http.StatusOK,
|
||||||
|
Headers: map[string][]string{
|
||||||
|
"content-type": {"application/json"},
|
||||||
|
},
|
||||||
|
Body: bytes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
||||||
result := backend.NewQueryDataResponse()
|
result := backend.NewQueryDataResponse()
|
||||||
|
|
||||||
@ -129,7 +165,7 @@ func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest)
|
|||||||
|
|
||||||
// we extracted this part of the functionality to make it easy to unit-test it
|
// we extracted this part of the functionality to make it easy to unit-test it
|
||||||
func runQuery(ctx context.Context, api *LokiAPI, query *lokiQuery) (data.Frames, error) {
|
func runQuery(ctx context.Context, api *LokiAPI, query *lokiQuery) (data.Frames, error) {
|
||||||
value, err := api.Query(ctx, *query)
|
value, err := api.DataQuery(ctx, *query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return data.Frames{}, err
|
return data.Frames{}, err
|
||||||
}
|
}
|
||||||
|
@ -439,8 +439,13 @@ export class LokiDatasource
|
|||||||
}
|
}
|
||||||
|
|
||||||
async metadataRequest(url: string, params?: Record<string, string | number>) {
|
async metadataRequest(url: string, params?: Record<string, string | number>) {
|
||||||
const res = await lastValueFrom(this._request(url, params, { hideFromInspector: true }));
|
if (config.featureToggles.lokiBackendMode) {
|
||||||
return res.data.data || res.data.values || [];
|
const res = await this.getResource(url, params);
|
||||||
|
return res.data || res.values || [];
|
||||||
|
} else {
|
||||||
|
const res = await lastValueFrom(this._request(url, params, { hideFromInspector: true }));
|
||||||
|
return res.data.data || res.data.values || [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async metricFindQuery(query: string) {
|
async metricFindQuery(query: string) {
|
||||||
|
Loading…
Reference in New Issue
Block a user