datasources: querier: better handling of timestamps (#108973)

* query: support query-local timestamps

* make it configurable

* lint fix

* corrected unit test

* fixed unit test
This commit is contained in:
Gábor Farkas
2025-08-05 08:35:57 +02:00
committed by GitHub
parent a7ba662b02
commit 0ccfdbdfae
5 changed files with 276 additions and 49 deletions
+26 -19
View File
@@ -2,7 +2,6 @@ package query
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
@@ -14,7 +13,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
"golang.org/x/sync/errgroup"
data "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/apimachinery/errutil"
"github.com/grafana/grafana/pkg/apimachinery/identity"
@@ -88,6 +86,7 @@ type ServiceImpl struct {
concurrentQueryLimit int
mtDatasourceClientBuilder mtdsclient.MTDatasourceClientBuilder
headers map[string]string
supportLocalTimeRange bool
}
// Run ServiceImpl.
@@ -105,7 +104,7 @@ func (s *ServiceImpl) QueryData(ctx context.Context, user identity.Requester, sk
}
}
// Parse the request into parsed queries grouped by datasource uid
parsedReq, err := s.parseMetricRequest(ctx, user, skipDSCache, reqDTO)
parsedReq, err := s.parseMetricRequest(ctx, user, skipDSCache, reqDTO, s.supportLocalTimeRange)
if err != nil {
return nil, err
}
@@ -224,6 +223,7 @@ func QueryData(ctx context.Context, log log.Logger, dscache datasources.CacheSer
mtDatasourceClientBuilder: mtDatasourceClientBuilder,
headers: headers,
concurrentQueryLimit: 16, // TODO: make it configurable
supportLocalTimeRange: true,
}
return s.QueryData(ctx, nil, false, reqDTO)
}
@@ -303,32 +303,32 @@ func (s *ServiceImpl) handleQuerySingleDatasource(ctx context.Context, user iden
return s.pluginClient.QueryData(ctx, req)
} else { // multi tenant flow
// transform request from backend.QueryDataRequest to k8s request
k8sReq := &data.QueryDataRequest{
TimeRange: data.TimeRange{
From: req.Queries[0].TimeRange.From.Format(time.RFC3339),
To: req.Queries[0].TimeRange.To.Format(time.RFC3339),
},
}
for _, q := range req.Queries {
var dataQuery data.DataQuery
err := json.Unmarshal(q.JSON, &dataQuery)
if err != nil {
return nil, err
}
k8sReq.Queries = append(k8sReq.Queries, dataQuery)
k8sReq, err := expr.ConvertBackendRequestToDataRequest(req)
if err != nil {
return nil, err
}
return mtDsClient.QueryData(ctx, *k8sReq)
}
}
func getTimeRange(query *simplejson.Json, globalFrom string, globalTo string) gtime.TimeRange {
from := query.Get("timeRange").Get("from").MustString("")
to := query.Get("timeRange").Get("to").MustString("")
if (from == "") && (to == "") {
from = globalFrom
to = globalTo
}
return gtime.NewTimeRange(from, to)
}
// parseRequest parses a request into parsed queries grouped by datasource uid
func (s *ServiceImpl) parseMetricRequest(ctx context.Context, user identity.Requester, skipDSCache bool, reqDTO dtos.MetricRequest) (*parsedRequest, error) {
func (s *ServiceImpl) parseMetricRequest(ctx context.Context, user identity.Requester, skipDSCache bool, reqDTO dtos.MetricRequest, supportLocalTimeRange bool) (*parsedRequest, error) {
if len(reqDTO.Queries) == 0 {
return nil, ErrNoQueriesFound
}
timeRange := gtime.NewTimeRange(reqDTO.From, reqDTO.To)
req := &parsedRequest{
hasExpression: false,
parsedQueries: make(map[string][]parsedQuery),
@@ -357,6 +357,13 @@ func (s *ServiceImpl) parseMetricRequest(ctx context.Context, user identity.Requ
req.parsedQueries[ds.UID] = []parsedQuery{}
}
var timeRange gtime.TimeRange
if supportLocalTimeRange {
timeRange = getTimeRange(query, reqDTO.From, reqDTO.To)
} else {
timeRange = gtime.NewTimeRange(reqDTO.From, reqDTO.To)
}
modelJSON, err := query.MarshalJSON()
if err != nil {
return nil, err