mirror of
https://github.com/grafana/grafana.git
synced 2024-11-25 02:10:45 -06:00
e18d029a24
* Improve error handling * More manual errorsource * Revert some changes from original PR * Update test
117 lines
3.2 KiB
Go
117 lines
3.2 KiB
Go
package cloudmonitoring
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"path"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
|
"github.com/grafana/grafana-plugin-sdk-go/experimental/errorsource"
|
|
"github.com/grafana/grafana/pkg/tsdb/cloud-monitoring/converter"
|
|
jsoniter "github.com/json-iterator/go"
|
|
)
|
|
|
|
func (promQLQ *cloudMonitoringProm) run(ctx context.Context, req *backend.QueryDataRequest,
|
|
s *Service, dsInfo datasourceInfo, logger log.Logger) (*backend.DataResponse, any, string, error) {
|
|
dr := &backend.DataResponse{}
|
|
projectName, err := s.ensureProject(ctx, dsInfo, promQLQ.parameters.ProjectName)
|
|
if err != nil {
|
|
dr.Error = err
|
|
return dr, backend.DataResponse{}, "", nil
|
|
}
|
|
r, err := createRequest(ctx, &dsInfo, path.Join("/v1/projects", projectName, "location/global/prometheus/api/v1/query_range"), nil)
|
|
if err != nil {
|
|
dr.Error = err
|
|
return dr, backend.DataResponse{}, "", nil
|
|
}
|
|
|
|
span := traceReq(ctx, req, dsInfo, r, "")
|
|
defer span.End()
|
|
|
|
requestBody := map[string]any{
|
|
"query": promQLQ.parameters.Expr,
|
|
"end": formatTime(promQLQ.timeRange.To),
|
|
"start": formatTime(promQLQ.timeRange.From),
|
|
"step": promQLQ.parameters.Step,
|
|
}
|
|
|
|
res, err := doRequestProm(r, dsInfo, requestBody)
|
|
if err != nil {
|
|
dr.Error = err
|
|
return dr, backend.DataResponse{}, "", nil
|
|
}
|
|
|
|
defer func() {
|
|
if err := res.Body.Close(); err != nil {
|
|
s.logger.Error("Failed to close response body", "err", err, "statusSource", backend.ErrorSourceDownstream)
|
|
}
|
|
}()
|
|
|
|
return dr, parseProm(res), r.URL.RawQuery, nil
|
|
}
|
|
|
|
func doRequestProm(r *http.Request, dsInfo datasourceInfo, body map[string]any) (*http.Response, error) {
|
|
if body != nil {
|
|
buf, err := json.Marshal(body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
r.Body = io.NopCloser(bytes.NewBuffer(buf))
|
|
r.Method = http.MethodPost
|
|
}
|
|
res, err := dsInfo.services[cloudMonitor].client.Do(r)
|
|
if err != nil {
|
|
return res, errorsource.DownstreamError(err, false)
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func parseProm(res *http.Response) backend.DataResponse {
|
|
iter := jsoniter.Parse(jsoniter.ConfigDefault, res.Body, 1024)
|
|
return converter.ReadPrometheusStyleResult(iter, converter.Options{
|
|
Dataplane: false,
|
|
})
|
|
}
|
|
|
|
// We are not parsing the response in this function. ReadPrometheusStyleResult needs an open reader and we cannot
|
|
// pass an open reader to this function because lint complains as it is unsafe
|
|
func (promQLQ *cloudMonitoringProm) parseResponse(queryRes *backend.DataResponse,
|
|
response any, executedQueryString string, logger log.Logger) error {
|
|
r := response.(backend.DataResponse)
|
|
// Add frame to attach metadata
|
|
if len(r.Frames) == 0 {
|
|
r.Frames = append(r.Frames, data.NewFrame(""))
|
|
}
|
|
|
|
*queryRes = r
|
|
return nil
|
|
}
|
|
|
|
func (promQLQ *cloudMonitoringProm) buildDeepLink() string {
|
|
return ""
|
|
}
|
|
|
|
func (promQLQ *cloudMonitoringProm) getRefID() string {
|
|
return promQLQ.refID
|
|
}
|
|
|
|
func (promQLQ *cloudMonitoringProm) getAliasBy() string {
|
|
return promQLQ.aliasBy
|
|
}
|
|
|
|
func (promQLQ *cloudMonitoringProm) getParameter(i string) string {
|
|
return ""
|
|
}
|
|
|
|
func formatTime(t time.Time) string {
|
|
return strconv.FormatFloat(float64(t.Unix())+float64(t.Nanosecond())/1e9, 'f', -1, 64)
|
|
}
|