Files
grafana/pkg/tsdb/graphite/graphite.go
2025-10-01 15:04:21 +02:00

137 lines
3.4 KiB
Go

package graphite
import (
"context"
"fmt"
"net/http"
"net/url"
"path"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
"go.opentelemetry.io/otel/trace"
)
type Service struct {
im instancemgmt.InstanceManager
tracer trace.Tracer
logger log.Logger
resourceHandler backend.CallResourceHandler
HTTPClient *http.Client
}
const (
TargetFullModelField = "targetFull"
TargetModelField = "target"
)
func ProvideService(httpClientProvider *httpclient.Provider, tracer trace.Tracer) *Service {
logger := backend.NewLoggerWith("logger", "graphite")
s := &Service{
im: datasource.NewInstanceManager(newInstanceSettings(httpClientProvider)),
tracer: tracer,
logger: logger,
}
s.resourceHandler = httpadapter.New(s.newResourceMux())
return s
}
type datasourceInfo struct {
HTTPClient *http.Client
URL string
Id int64
}
func newInstanceSettings(httpClientProvider *httpclient.Provider) datasource.InstanceFactoryFunc {
return func(ctx context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
opts, err := settings.HTTPClientOptions(ctx)
if err != nil {
return nil, err
}
client, err := httpClientProvider.New(opts)
if err != nil {
return nil, err
}
model := datasourceInfo{
HTTPClient: client,
URL: settings.URL,
Id: settings.ID,
}
return model, nil
}
}
func (s *Service) getDSInfo(ctx context.Context, pluginCtx backend.PluginContext) (*datasourceInfo, error) {
i, err := s.im.Get(ctx, pluginCtx)
if err != nil {
return nil, err
}
instance := i.(datasourceInfo)
return &instance, nil
}
func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
if len(req.Queries) == 0 {
return nil, fmt.Errorf("query contains no queries")
}
// get datasource info from context
dsInfo, err := s.getDSInfo(ctx, req.PluginContext)
if err != nil {
return nil, err
}
return s.RunQuery(ctx, req, dsInfo)
}
func (s *Service) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
return s.resourceHandler.CallResource(ctx, req, sender)
}
func (s *Service) createRequest(ctx context.Context, dsInfo *datasourceInfo, params URLParams) (*http.Request, error) {
u, err := url.Parse(dsInfo.URL)
if err != nil {
return nil, backend.DownstreamError(err)
}
if params.SubPath != "" {
u.Path = path.Join(u.Path, params.SubPath)
}
if params.QueryParams != nil {
queryValues := u.Query()
for key, values := range params.QueryParams {
for _, value := range values {
queryValues.Add(key, value)
}
}
u.RawQuery = queryValues.Encode()
}
method := params.Method
if method == "" {
method = http.MethodGet
}
req, err := http.NewRequestWithContext(ctx, method, u.String(), params.Body)
if err != nil {
s.logger.Info("Failed to create request", "error", err)
return nil, backend.PluginError(fmt.Errorf("failed to create request: %w", err))
}
for k, v := range params.Headers {
req.Header.Add(k, v)
}
return req, err
}