grafana/pkg/promlib/healthcheck.go
2024-03-26 16:36:39 +03:00

109 lines
2.7 KiB
Go

package promlib
import (
"context"
"encoding/json"
"errors"
"fmt"
"time"
"github.com/grafana/grafana-plugin-sdk-go/backend"
sdkapi "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1"
"github.com/grafana/grafana/pkg/promlib/models"
)
const (
refID = "__healthcheck__"
)
func (s *Service) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult,
error) {
ds, err := s.getInstance(ctx, req.PluginContext)
// check that the datasource exists
if err != nil {
return getHealthCheckMessage("error getting datasource info", err)
}
if ds == nil {
return getHealthCheckMessage("", errors.New("invalid datasource info received"))
}
logger := s.logger.FromContext(ctx)
hc, err := healthcheck(ctx, req, ds)
if err != nil {
logger.Warn("Error performing prometheus healthcheck", "err", err.Error())
return nil, err
}
heuristics, err := getHeuristics(ctx, ds, logger)
if err != nil {
logger.Warn("Failed to get prometheus heuristics", "err", err.Error())
} else {
jsonDetails, err := json.Marshal(heuristics)
if err != nil {
logger.Warn("Failed to marshal heuristics", "err", err)
} else {
hc.JSONDetails = jsonDetails
}
}
return hc, nil
}
func healthcheck(ctx context.Context, req *backend.CheckHealthRequest, i *instance) (*backend.CheckHealthResult, error) {
qm := models.QueryModel{
UtcOffsetSec: 0,
CommonQueryProperties: sdkapi.CommonQueryProperties{
RefID: refID,
},
PrometheusQueryProperties: models.PrometheusQueryProperties{
Expr: "1+1",
Instant: true,
},
}
b, _ := json.Marshal(&qm)
query := backend.DataQuery{
RefID: refID,
TimeRange: backend.TimeRange{
From: time.Unix(1, 0).UTC(),
To: time.Unix(4, 0).UTC(),
},
JSON: b,
}
resp, err := i.queryData.Execute(ctx, &backend.QueryDataRequest{
PluginContext: req.PluginContext,
Queries: []backend.DataQuery{query},
})
if err != nil {
return getHealthCheckMessage("There was an error returned querying the Prometheus API.", err)
}
if resp.Responses[refID].Error != nil {
return getHealthCheckMessage("There was an error returned querying the Prometheus API.",
errors.New(resp.Responses[refID].Error.Error()))
}
return getHealthCheckMessage("Successfully queried the Prometheus API.", nil)
}
func getHealthCheckMessage(message string, err error) (*backend.CheckHealthResult, error) {
if err == nil {
return &backend.CheckHealthResult{
Status: backend.HealthStatusOk,
Message: message,
}, nil
}
errorMessage := fmt.Sprintf("%s - %s", err.Error(), message)
return &backend.CheckHealthResult{
Status: backend.HealthStatusError,
Message: errorMessage,
}, nil
}