Plugins: Remove pluginsInstrumentationStatusSource feature toggle (#83067)

* Plugins: Remove pluginsInstrumentationStatusSource feature toggle

* update tests

* Inline pluginRequestDurationWithLabels, pluginRequestCounterWithLabels, pluginRequestDurationSecondsWithLabels
This commit is contained in:
Giuseppe Guerra 2024-02-21 12:57:40 +01:00 committed by GitHub
parent b6b5935992
commit 68fe045ec7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 34 additions and 103 deletions

View File

@ -157,7 +157,6 @@ Experimental features might be changed or removed without prior notice.
| `kubernetesSnapshots` | Routes snapshot requests from /api to the /apis endpoint | | `kubernetesSnapshots` | Routes snapshot requests from /api to the /apis endpoint |
| `teamHttpHeaders` | Enables datasources to apply team headers to the client requests | | `teamHttpHeaders` | Enables datasources to apply team headers to the client requests |
| `cachingOptimizeSerializationMemoryUsage` | If enabled, the caching backend gradually serializes query responses for the cache, comparing against the configured `[caching]max_value_mb` value as it goes. This can can help prevent Grafana from running out of memory while attempting to cache very large query responses. | | `cachingOptimizeSerializationMemoryUsage` | If enabled, the caching backend gradually serializes query responses for the cache, comparing against the configured `[caching]max_value_mb` value as it goes. This can can help prevent Grafana from running out of memory while attempting to cache very large query responses. |
| `pluginsInstrumentationStatusSource` | Include a status source label for plugin request metrics and logs |
| `prometheusPromQAIL` | Prometheus and AI/ML to assist users in creating a query | | `prometheusPromQAIL` | Prometheus and AI/ML to assist users in creating a query |
| `alertmanagerRemoteSecondary` | Enable Grafana to sync configuration and state with a remote Alertmanager. | | `alertmanagerRemoteSecondary` | Enable Grafana to sync configuration and state with a remote Alertmanager. |
| `alertmanagerRemotePrimary` | Enable Grafana to have a remote Alertmanager instance as the primary Alertmanager. | | `alertmanagerRemotePrimary` | Enable Grafana to have a remote Alertmanager instance as the primary Alertmanager. |

View File

@ -139,7 +139,6 @@ export interface FeatureToggles {
awsDatasourcesNewFormStyling?: boolean; awsDatasourcesNewFormStyling?: boolean;
cachingOptimizeSerializationMemoryUsage?: boolean; cachingOptimizeSerializationMemoryUsage?: boolean;
panelTitleSearchInV1?: boolean; panelTitleSearchInV1?: boolean;
pluginsInstrumentationStatusSource?: boolean;
managedPluginsInstall?: boolean; managedPluginsInstall?: boolean;
prometheusPromQAIL?: boolean; prometheusPromQAIL?: boolean;
addFieldFromCalculationStatFunctions?: boolean; addFieldFromCalculationStatFunctions?: boolean;

View File

@ -905,13 +905,6 @@ var (
Stage: FeatureStageExperimental, Stage: FeatureStageExperimental,
Owner: grafanaBackendPlatformSquad, Owner: grafanaBackendPlatformSquad,
}, },
{
Name: "pluginsInstrumentationStatusSource",
Description: "Include a status source label for plugin request metrics and logs",
FrontendOnly: false,
Stage: FeatureStageExperimental,
Owner: grafanaPluginsPlatformSquad,
},
{ {
Name: "managedPluginsInstall", Name: "managedPluginsInstall",
Description: "Install managed plugins directly from plugins catalog", Description: "Install managed plugins directly from plugins catalog",

View File

@ -120,7 +120,6 @@ teamHttpHeaders,experimental,@grafana/identity-access-team,false,false,false
awsDatasourcesNewFormStyling,preview,@grafana/aws-datasources,false,false,true awsDatasourcesNewFormStyling,preview,@grafana/aws-datasources,false,false,true
cachingOptimizeSerializationMemoryUsage,experimental,@grafana/grafana-operator-experience-squad,false,false,false cachingOptimizeSerializationMemoryUsage,experimental,@grafana/grafana-operator-experience-squad,false,false,false
panelTitleSearchInV1,experimental,@grafana/backend-platform,true,false,false panelTitleSearchInV1,experimental,@grafana/backend-platform,true,false,false
pluginsInstrumentationStatusSource,experimental,@grafana/plugins-platform-backend,false,false,false
managedPluginsInstall,preview,@grafana/plugins-platform-backend,false,false,false managedPluginsInstall,preview,@grafana/plugins-platform-backend,false,false,false
prometheusPromQAIL,experimental,@grafana/observability-metrics,false,false,true prometheusPromQAIL,experimental,@grafana/observability-metrics,false,false,true
addFieldFromCalculationStatFunctions,preview,@grafana/dataviz-squad,false,false,true addFieldFromCalculationStatFunctions,preview,@grafana/dataviz-squad,false,false,true

1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
120 awsDatasourcesNewFormStyling preview @grafana/aws-datasources false false true
121 cachingOptimizeSerializationMemoryUsage experimental @grafana/grafana-operator-experience-squad false false false
122 panelTitleSearchInV1 experimental @grafana/backend-platform true false false
pluginsInstrumentationStatusSource experimental @grafana/plugins-platform-backend false false false
123 managedPluginsInstall preview @grafana/plugins-platform-backend false false false
124 prometheusPromQAIL experimental @grafana/observability-metrics false false true
125 addFieldFromCalculationStatFunctions preview @grafana/dataviz-squad false false true

View File

@ -491,10 +491,6 @@ const (
// Enable searching for dashboards using panel title in search v1 // Enable searching for dashboards using panel title in search v1
FlagPanelTitleSearchInV1 = "panelTitleSearchInV1" FlagPanelTitleSearchInV1 = "panelTitleSearchInV1"
// FlagPluginsInstrumentationStatusSource
// Include a status source label for plugin request metrics and logs
FlagPluginsInstrumentationStatusSource = "pluginsInstrumentationStatusSource"
// FlagManagedPluginsInstall // FlagManagedPluginsInstall
// Install managed plugins directly from plugins catalog // Install managed plugins directly from plugins catalog
FlagManagedPluginsInstall = "managedPluginsInstall" FlagManagedPluginsInstall = "managedPluginsInstall"

View File

@ -82,7 +82,8 @@
"metadata": { "metadata": {
"name": "pluginsInstrumentationStatusSource", "name": "pluginsInstrumentationStatusSource",
"resourceVersion": "1708108588074", "resourceVersion": "1708108588074",
"creationTimestamp": "2024-02-16T18:36:28Z" "creationTimestamp": "2024-02-16T18:36:28Z",
"deletionTimestamp": "2024-02-19T14:18:02Z"
}, },
"spec": { "spec": {
"description": "Include a status source label for plugin request metrics and logs", "description": "Include a status source label for plugin request metrics and logs",

View File

@ -50,9 +50,7 @@ func (m *LoggerMiddleware) logRequest(ctx context.Context, fn func(ctx context.C
if err != nil { if err != nil {
logParams = append(logParams, "error", err) logParams = append(logParams, "error", err)
} }
if m.features.IsEnabled(ctx, featuremgmt.FlagPluginsInstrumentationStatusSource) { logParams = append(logParams, "statusSource", pluginrequestmeta.StatusSourceFromContext(ctx))
logParams = append(logParams, "statusSource", pluginrequestmeta.StatusSourceFromContext(ctx))
}
ctxLogger := m.logger.FromContext(ctx) ctxLogger := m.logger.FromContext(ctx)
logFunc := ctxLogger.Info logFunc := ctxLogger.Info
@ -81,9 +79,11 @@ func (m *LoggerMiddleware) QueryData(ctx context.Context, req *backend.QueryData
ctxLogger := m.logger.FromContext(ctx) ctxLogger := m.logger.FromContext(ctx)
for refID, dr := range resp.Responses { for refID, dr := range resp.Responses {
if dr.Error != nil { if dr.Error != nil {
logParams := []any{"refID", refID, "status", int(dr.Status), "error", dr.Error} logParams := []any{
if m.features.IsEnabled(ctx, featuremgmt.FlagPluginsInstrumentationStatusSource) { "refID", refID,
logParams = append(logParams, "statusSource", pluginrequestmeta.StatusSourceFromPluginErrorSource(dr.ErrorSource)) "status", int(dr.Status),
"error", dr.Error,
"statusSource", pluginrequestmeta.StatusSourceFromPluginErrorSource(dr.ErrorSource),
} }
ctxLogger.Error("Partial data response error", logParams...) ctxLogger.Error("Partial data response error", logParams...)
} }

View File

@ -32,10 +32,7 @@ type MetricsMiddleware struct {
} }
func newMetricsMiddleware(promRegisterer prometheus.Registerer, pluginRegistry registry.Service, features featuremgmt.FeatureToggles) *MetricsMiddleware { func newMetricsMiddleware(promRegisterer prometheus.Registerer, pluginRegistry registry.Service, features featuremgmt.FeatureToggles) *MetricsMiddleware {
var additionalLabels []string additionalLabels := []string{"status_source"}
if features.IsEnabledGlobally(featuremgmt.FlagPluginsInstrumentationStatusSource) {
additionalLabels = []string{"status_source"}
}
pluginRequestCounter := prometheus.NewCounterVec(prometheus.CounterOpts{ pluginRequestCounter := prometheus.NewCounterVec(prometheus.CounterOpts{
Namespace: "grafana", Namespace: "grafana",
Name: "plugin_request_total", Name: "plugin_request_total",
@ -119,19 +116,11 @@ func (m *MetricsMiddleware) instrumentPluginRequest(ctx context.Context, pluginC
status, err := fn(ctx) status, err := fn(ctx)
elapsed := time.Since(start) elapsed := time.Since(start)
pluginRequestDurationLabels := []string{pluginCtx.PluginID, endpoint, target} statusSource := pluginrequestmeta.StatusSourceFromContext(ctx)
pluginRequestCounterLabels := []string{pluginCtx.PluginID, endpoint, status.String(), target}
pluginRequestDurationSecondsLabels := []string{"grafana-backend", pluginCtx.PluginID, endpoint, status.String(), target}
if m.features.IsEnabled(ctx, featuremgmt.FlagPluginsInstrumentationStatusSource) {
statusSource := pluginrequestmeta.StatusSourceFromContext(ctx)
pluginRequestDurationLabels = append(pluginRequestDurationLabels, string(statusSource))
pluginRequestCounterLabels = append(pluginRequestCounterLabels, string(statusSource))
pluginRequestDurationSecondsLabels = append(pluginRequestDurationSecondsLabels, string(statusSource))
}
pluginRequestDurationWithLabels := m.pluginRequestDuration.WithLabelValues(pluginRequestDurationLabels...) pluginRequestDurationWithLabels := m.pluginRequestDuration.WithLabelValues(pluginCtx.PluginID, endpoint, target, string(statusSource))
pluginRequestCounterWithLabels := m.pluginRequestCounter.WithLabelValues(pluginRequestCounterLabels...) pluginRequestCounterWithLabels := m.pluginRequestCounter.WithLabelValues(pluginCtx.PluginID, endpoint, status.String(), target, string(statusSource))
pluginRequestDurationSecondsWithLabels := m.pluginRequestDurationSeconds.WithLabelValues(pluginRequestDurationSecondsLabels...) pluginRequestDurationSecondsWithLabels := m.pluginRequestDurationSeconds.WithLabelValues("grafana-backend", pluginCtx.PluginID, endpoint, status.String(), target, string(statusSource))
if traceID := tracing.TraceIDFromContext(ctx, true); traceID != "" { if traceID := tracing.TraceIDFromContext(ctx, true); traceID != "" {
pluginRequestDurationWithLabels.(prometheus.ExemplarObserver).ObserveWithExemplar( pluginRequestDurationWithLabels.(prometheus.ExemplarObserver).ObserveWithExemplar(

View File

@ -90,7 +90,7 @@ func TestInstrumentationMiddleware(t *testing.T) {
require.Equal(t, 1, testutil.CollectAndCount(promRegistry, metricRequestDurationMs)) require.Equal(t, 1, testutil.CollectAndCount(promRegistry, metricRequestDurationMs))
require.Equal(t, 1, testutil.CollectAndCount(promRegistry, metricRequestDurationS)) require.Equal(t, 1, testutil.CollectAndCount(promRegistry, metricRequestDurationS))
counter := mw.pluginMetrics.pluginRequestCounter.WithLabelValues(pluginID, tc.expEndpoint, requestStatusOK.String(), string(backendplugin.TargetUnknown)) counter := mw.pluginMetrics.pluginRequestCounter.WithLabelValues(pluginID, tc.expEndpoint, requestStatusOK.String(), string(backendplugin.TargetUnknown), string(pluginrequestmeta.DefaultStatusSource))
require.Equal(t, 1.0, testutil.ToFloat64(counter)) require.Equal(t, 1.0, testutil.ToFloat64(counter))
for _, m := range []string{metricRequestDurationMs, metricRequestDurationS} { for _, m := range []string{metricRequestDurationMs, metricRequestDurationS} {
require.NoError(t, checkHistogram(promRegistry, m, map[string]string{ require.NoError(t, checkHistogram(promRegistry, m, map[string]string{
@ -115,12 +115,6 @@ func TestInstrumentationMiddleware(t *testing.T) {
func TestInstrumentationMiddlewareStatusSource(t *testing.T) { func TestInstrumentationMiddlewareStatusSource(t *testing.T) {
const labelStatusSource = "status_source" const labelStatusSource = "status_source"
queryDataOKCounterLabels := prometheus.Labels{
"plugin_id": pluginID,
"endpoint": endpointQueryData,
"status": requestStatusOK.String(),
"target": string(backendplugin.TargetUnknown),
}
queryDataErrorCounterLabels := prometheus.Labels{ queryDataErrorCounterLabels := prometheus.Labels{
"plugin_id": pluginID, "plugin_id": pluginID,
"endpoint": endpointQueryData, "endpoint": endpointQueryData,
@ -159,8 +153,7 @@ func TestInstrumentationMiddlewareStatusSource(t *testing.T) {
require.NoError(t, pluginsRegistry.Add(context.Background(), &plugins.Plugin{ require.NoError(t, pluginsRegistry.Add(context.Background(), &plugins.Plugin{
JSONData: plugins.JSONData{ID: pluginID, Backend: true}, JSONData: plugins.JSONData{ID: pluginID, Backend: true},
})) }))
features := featuremgmt.WithFeatures(featuremgmt.FlagPluginsInstrumentationStatusSource) metricsMw := newMetricsMiddleware(promRegistry, pluginsRegistry, featuremgmt.WithFeatures())
metricsMw := newMetricsMiddleware(promRegistry, pluginsRegistry, features)
cdt := clienttest.NewClientDecoratorTest(t, clienttest.WithMiddlewares( cdt := clienttest.NewClientDecoratorTest(t, clienttest.WithMiddlewares(
NewPluginRequestMetaMiddleware(), NewPluginRequestMetaMiddleware(),
plugins.ClientMiddlewareFunc(func(next plugins.Client) plugins.Client { plugins.ClientMiddlewareFunc(func(next plugins.Client) plugins.Client {
@ -171,53 +164,21 @@ func TestInstrumentationMiddlewareStatusSource(t *testing.T) {
)) ))
t.Run("Metrics", func(t *testing.T) { t.Run("Metrics", func(t *testing.T) {
t.Run("Should ignore ErrorSource if feature flag is disabled", func(t *testing.T) { metricsMw.pluginMetrics.pluginRequestCounter.Reset()
// Use different middleware without feature flag
metricsMw := newMetricsMiddleware(prometheus.NewRegistry(), pluginsRegistry, featuremgmt.WithFeatures())
cdt := clienttest.NewClientDecoratorTest(t, clienttest.WithMiddlewares(
plugins.ClientMiddlewareFunc(func(next plugins.Client) plugins.Client {
metricsMw.next = next
return metricsMw
}),
))
cdt.TestClient.QueryDataFunc = func(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { cdt.TestClient.QueryDataFunc = func(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
return &backend.QueryDataResponse{Responses: map[string]backend.DataResponse{"A": downstreamErrorResponse}}, nil return &backend.QueryDataResponse{Responses: map[string]backend.DataResponse{"A": downstreamErrorResponse}}, nil
} }
_, err := cdt.Decorator.QueryData(context.Background(), &backend.QueryDataRequest{PluginContext: pCtx}) _, err := cdt.Decorator.QueryData(context.Background(), &backend.QueryDataRequest{PluginContext: pCtx})
require.NoError(t, err) require.NoError(t, err)
counter, err := metricsMw.pluginMetrics.pluginRequestCounter.GetMetricWith(newLabels(queryDataErrorCounterLabels, nil)) counter, err := metricsMw.pluginMetrics.pluginRequestCounter.GetMetricWith(newLabels(
require.NoError(t, err) queryDataErrorCounterLabels,
require.Equal(t, 1.0, testutil.ToFloat64(counter)) prometheus.Labels{
labelStatusSource: string(backend.ErrorSourceDownstream),
// error_source should not be defined at all }),
_, err = metricsMw.pluginMetrics.pluginRequestCounter.GetMetricWith(newLabels( )
queryDataOKCounterLabels, require.NoError(t, err)
prometheus.Labels{ require.Equal(t, 1.0, testutil.ToFloat64(counter))
labelStatusSource: string(backend.ErrorSourceDownstream),
}),
)
require.Error(t, err)
require.ErrorContains(t, err, "inconsistent label cardinality")
})
t.Run("Should add error_source label if feature flag is enabled", func(t *testing.T) {
metricsMw.pluginMetrics.pluginRequestCounter.Reset()
cdt.TestClient.QueryDataFunc = func(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
return &backend.QueryDataResponse{Responses: map[string]backend.DataResponse{"A": downstreamErrorResponse}}, nil
}
_, err := cdt.Decorator.QueryData(context.Background(), &backend.QueryDataRequest{PluginContext: pCtx})
require.NoError(t, err)
counter, err := metricsMw.pluginMetrics.pluginRequestCounter.GetMetricWith(newLabels(
queryDataErrorCounterLabels,
prometheus.Labels{
labelStatusSource: string(backend.ErrorSourceDownstream),
}),
)
require.NoError(t, err)
require.Equal(t, 1.0, testutil.ToFloat64(counter))
})
}) })
t.Run("Priority", func(t *testing.T) { t.Run("Priority", func(t *testing.T) {

View File

@ -153,12 +153,8 @@ func NewClientDecorator(
} }
func CreateMiddlewares(cfg *setting.Cfg, oAuthTokenService oauthtoken.OAuthTokenService, tracer tracing.Tracer, cachingService caching.CachingService, features *featuremgmt.FeatureManager, promRegisterer prometheus.Registerer, registry registry.Service) []plugins.ClientMiddleware { func CreateMiddlewares(cfg *setting.Cfg, oAuthTokenService oauthtoken.OAuthTokenService, tracer tracing.Tracer, cachingService caching.CachingService, features *featuremgmt.FeatureManager, promRegisterer prometheus.Registerer, registry registry.Service) []plugins.ClientMiddleware {
var middlewares []plugins.ClientMiddleware middlewares := []plugins.ClientMiddleware{
clientmiddleware.NewPluginRequestMetaMiddleware(),
if features.IsEnabledGlobally(featuremgmt.FlagPluginsInstrumentationStatusSource) {
middlewares = []plugins.ClientMiddleware{
clientmiddleware.NewPluginRequestMetaMiddleware(),
}
} }
skipCookiesNames := []string{cfg.LoginCookieName} skipCookiesNames := []string{cfg.LoginCookieName}
@ -189,11 +185,9 @@ func CreateMiddlewares(cfg *setting.Cfg, oAuthTokenService oauthtoken.OAuthToken
middlewares = append(middlewares, clientmiddleware.NewHTTPClientMiddleware()) middlewares = append(middlewares, clientmiddleware.NewHTTPClientMiddleware())
if features.IsEnabledGlobally(featuremgmt.FlagPluginsInstrumentationStatusSource) { // StatusSourceMiddleware should be at the very bottom, or any middlewares below it won't see the
// StatusSourceMiddleware should be at the very bottom, or any middlewares below it won't see the // correct status source in their context.Context
// correct status source in their context.Context middlewares = append(middlewares, clientmiddleware.NewStatusSourceMiddleware())
middlewares = append(middlewares, clientmiddleware.NewStatusSourceMiddleware())
}
return middlewares return middlewares
} }