Plugins: Enhanced plugin instrumentation (#90199)

* Plugins: Enhanced plugin instrumentation

* use backend.CallResourceResponseSenderFunc

* sdk v0.237.0

* support admission control

* cover all handlers in log and metrics middlewares

* fix after review
This commit is contained in:
Marcus Efraimsson
2024-07-09 15:03:46 +02:00
committed by GitHub
parent 2a4a73e03d
commit c8af659f02
40 changed files with 700 additions and 472 deletions
@@ -9,6 +9,7 @@ import (
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/instrumentationutils"
"github.com/grafana/grafana/pkg/plugins/manager/registry"
"github.com/grafana/grafana/pkg/plugins/pluginrequestmeta"
)
@@ -94,17 +95,18 @@ func (m *MetricsMiddleware) pluginTarget(ctx context.Context, pluginID, pluginVe
}
// instrumentPluginRequestSize tracks the size of the given request in the m.pluginRequestSize metric.
func (m *MetricsMiddleware) instrumentPluginRequestSize(ctx context.Context, pluginCtx backend.PluginContext, endpoint string, requestSize float64) error {
func (m *MetricsMiddleware) instrumentPluginRequestSize(ctx context.Context, pluginCtx backend.PluginContext, requestSize float64) error {
target, err := m.pluginTarget(ctx, pluginCtx.PluginID, pluginCtx.PluginVersion)
if err != nil {
return err
}
m.pluginRequestSize.WithLabelValues("grafana-backend", pluginCtx.PluginID, endpoint, target).Observe(requestSize)
endpoint := backend.EndpointFromContext(ctx)
m.pluginRequestSize.WithLabelValues("grafana-backend", pluginCtx.PluginID, string(endpoint), target).Observe(requestSize)
return nil
}
// instrumentPluginRequest increments the m.pluginRequestCounter metric and tracks the duration of the given request.
func (m *MetricsMiddleware) instrumentPluginRequest(ctx context.Context, pluginCtx backend.PluginContext, endpoint string, fn func(context.Context) (requestStatus, error)) error {
func (m *MetricsMiddleware) instrumentPluginRequest(ctx context.Context, pluginCtx backend.PluginContext, fn func(context.Context) (instrumentationutils.RequestStatus, error)) error {
target, err := m.pluginTarget(ctx, pluginCtx.PluginID, pluginCtx.PluginVersion)
if err != nil {
return err
@@ -116,10 +118,11 @@ func (m *MetricsMiddleware) instrumentPluginRequest(ctx context.Context, pluginC
elapsed := time.Since(start)
statusSource := pluginrequestmeta.StatusSourceFromContext(ctx)
endpoint := backend.EndpointFromContext(ctx)
pluginRequestDurationWithLabels := m.pluginRequestDuration.WithLabelValues(pluginCtx.PluginID, endpoint, target, string(statusSource))
pluginRequestCounterWithLabels := m.pluginRequestCounter.WithLabelValues(pluginCtx.PluginID, endpoint, status.String(), target, string(statusSource))
pluginRequestDurationSecondsWithLabels := m.pluginRequestDurationSeconds.WithLabelValues("grafana-backend", pluginCtx.PluginID, endpoint, status.String(), target, string(statusSource))
pluginRequestDurationWithLabels := m.pluginRequestDuration.WithLabelValues(pluginCtx.PluginID, string(endpoint), target, string(statusSource))
pluginRequestCounterWithLabels := m.pluginRequestCounter.WithLabelValues(pluginCtx.PluginID, string(endpoint), status.String(), target, string(statusSource))
pluginRequestDurationSecondsWithLabels := m.pluginRequestDurationSeconds.WithLabelValues("grafana-backend", pluginCtx.PluginID, string(endpoint), status.String(), target, string(statusSource))
if traceID := tracing.TraceIDFromContext(ctx, true); traceID != "" {
pluginRequestDurationWithLabels.(prometheus.ExemplarObserver).ObserveWithExemplar(
@@ -144,74 +147,108 @@ func (m *MetricsMiddleware) QueryData(ctx context.Context, req *backend.QueryDat
requestSize += float64(len(v.JSON))
}
if err := m.instrumentPluginRequestSize(ctx, req.PluginContext, endpointQueryData, requestSize); err != nil {
if err := m.instrumentPluginRequestSize(ctx, req.PluginContext, requestSize); err != nil {
return nil, err
}
var resp *backend.QueryDataResponse
err := m.instrumentPluginRequest(ctx, req.PluginContext, endpointQueryData, func(ctx context.Context) (status requestStatus, innerErr error) {
err := m.instrumentPluginRequest(ctx, req.PluginContext, func(ctx context.Context) (instrumentationutils.RequestStatus, error) {
var innerErr error
resp, innerErr = m.next.QueryData(ctx, req)
return requestStatusFromQueryDataResponse(resp, innerErr), innerErr
return instrumentationutils.RequestStatusFromQueryDataResponse(resp, innerErr), innerErr
})
return resp, err
}
func (m *MetricsMiddleware) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
if err := m.instrumentPluginRequestSize(ctx, req.PluginContext, endpointCallResource, float64(len(req.Body))); err != nil {
if err := m.instrumentPluginRequestSize(ctx, req.PluginContext, float64(len(req.Body))); err != nil {
return err
}
return m.instrumentPluginRequest(ctx, req.PluginContext, endpointCallResource, func(ctx context.Context) (requestStatus, error) {
return m.instrumentPluginRequest(ctx, req.PluginContext, func(ctx context.Context) (instrumentationutils.RequestStatus, error) {
innerErr := m.next.CallResource(ctx, req, sender)
return requestStatusFromError(innerErr), innerErr
return instrumentationutils.RequestStatusFromError(innerErr), innerErr
})
}
func (m *MetricsMiddleware) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
var result *backend.CheckHealthResult
err := m.instrumentPluginRequest(ctx, req.PluginContext, endpointCheckHealth, func(ctx context.Context) (status requestStatus, innerErr error) {
result, innerErr = m.next.CheckHealth(ctx, req)
return requestStatusFromError(innerErr), innerErr
var resp *backend.CheckHealthResult
err := m.instrumentPluginRequest(ctx, req.PluginContext, func(ctx context.Context) (instrumentationutils.RequestStatus, error) {
var innerErr error
resp, innerErr = m.next.CheckHealth(ctx, req)
return instrumentationutils.RequestStatusFromError(innerErr), innerErr
})
return result, err
return resp, err
}
func (m *MetricsMiddleware) CollectMetrics(ctx context.Context, req *backend.CollectMetricsRequest) (*backend.CollectMetricsResult, error) {
var result *backend.CollectMetricsResult
err := m.instrumentPluginRequest(ctx, req.PluginContext, endpointCollectMetrics, func(ctx context.Context) (status requestStatus, innerErr error) {
result, innerErr = m.next.CollectMetrics(ctx, req)
return requestStatusFromError(innerErr), innerErr
var resp *backend.CollectMetricsResult
err := m.instrumentPluginRequest(ctx, req.PluginContext, func(ctx context.Context) (instrumentationutils.RequestStatus, error) {
var innerErr error
resp, innerErr = m.next.CollectMetrics(ctx, req)
return instrumentationutils.RequestStatusFromError(innerErr), innerErr
})
return result, err
return resp, err
}
func (m *MetricsMiddleware) SubscribeStream(ctx context.Context, req *backend.SubscribeStreamRequest) (*backend.SubscribeStreamResponse, error) {
var resp *backend.SubscribeStreamResponse
err := m.instrumentPluginRequest(ctx, req.PluginContext, func(ctx context.Context) (instrumentationutils.RequestStatus, error) {
var innerErr error
resp, innerErr = m.next.SubscribeStream(ctx, req)
return instrumentationutils.RequestStatusFromError(innerErr), innerErr
})
return resp, err
}
func (m *MetricsMiddleware) PublishStream(ctx context.Context, req *backend.PublishStreamRequest) (*backend.PublishStreamResponse, error) {
var resp *backend.PublishStreamResponse
err := m.instrumentPluginRequest(ctx, req.PluginContext, func(ctx context.Context) (instrumentationutils.RequestStatus, error) {
var innerErr error
resp, innerErr = m.next.PublishStream(ctx, req)
return instrumentationutils.RequestStatusFromError(innerErr), innerErr
})
return resp, err
}
func (m *MetricsMiddleware) RunStream(ctx context.Context, req *backend.RunStreamRequest, sender *backend.StreamSender) error {
err := m.instrumentPluginRequest(ctx, req.PluginContext, func(ctx context.Context) (instrumentationutils.RequestStatus, error) {
innerErr := m.next.RunStream(ctx, req, sender)
return instrumentationutils.RequestStatusFromError(innerErr), innerErr
})
return err
}
func (m *MetricsMiddleware) ValidateAdmission(ctx context.Context, req *backend.AdmissionRequest) (*backend.ValidationResponse, error) {
var result *backend.ValidationResponse
err := m.instrumentPluginRequest(ctx, req.PluginContext, endpointMutateAdmission, func(ctx context.Context) (status requestStatus, innerErr error) {
result, innerErr = m.next.ValidateAdmission(ctx, req)
return requestStatusFromError(innerErr), innerErr
var resp *backend.ValidationResponse
err := m.instrumentPluginRequest(ctx, req.PluginContext, func(ctx context.Context) (instrumentationutils.RequestStatus, error) {
var innerErr error
resp, innerErr = m.next.ValidateAdmission(ctx, req)
return instrumentationutils.RequestStatusFromError(innerErr), innerErr
})
return result, err
return resp, err
}
func (m *MetricsMiddleware) MutateAdmission(ctx context.Context, req *backend.AdmissionRequest) (*backend.MutationResponse, error) {
var result *backend.MutationResponse
err := m.instrumentPluginRequest(ctx, req.PluginContext, endpointMutateAdmission, func(ctx context.Context) (status requestStatus, innerErr error) {
result, innerErr = m.next.MutateAdmission(ctx, req)
return requestStatusFromError(innerErr), innerErr
var resp *backend.MutationResponse
err := m.instrumentPluginRequest(ctx, req.PluginContext, func(ctx context.Context) (instrumentationutils.RequestStatus, error) {
var innerErr error
resp, innerErr = m.next.MutateAdmission(ctx, req)
return instrumentationutils.RequestStatusFromError(innerErr), innerErr
})
return result, err
return resp, err
}
func (m *MetricsMiddleware) ConvertObject(ctx context.Context, req *backend.ConversionRequest) (*backend.ConversionResponse, error) {
var result *backend.ConversionResponse
err := m.instrumentPluginRequest(ctx, req.PluginContext, endpointMutateAdmission, func(ctx context.Context) (status requestStatus, innerErr error) {
result, innerErr = m.next.ConvertObject(ctx, req)
return requestStatusFromError(innerErr), innerErr
var resp *backend.ConversionResponse
err := m.instrumentPluginRequest(ctx, req.PluginContext, func(ctx context.Context) (instrumentationutils.RequestStatus, error) {
var innerErr error
resp, innerErr = m.next.ConvertObject(ctx, req)
return instrumentationutils.RequestStatusFromError(innerErr), innerErr
})
return result, err
return resp, err
}