From 4936c530722ff33648caa2995f17885609f0fb18 Mon Sep 17 00:00:00 2001 From: Sven Grossmann Date: Thu, 16 Jan 2025 14:08:32 +0100 Subject: [PATCH 01/30] chore: upgrade `@grafana/lezer-logql` and `@grafana/monaco-logql` (#99076) --- package.json | 4 ++-- yarn.lock | 22 ++++++++++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index aab7da135dc..e6bbe7d9342 100644 --- a/package.json +++ b/package.json @@ -265,8 +265,8 @@ "@grafana/faro-web-tracing": "^1.8.2", "@grafana/flamegraph": "workspace:*", "@grafana/google-sdk": "0.1.2", - "@grafana/lezer-logql": "0.2.6", - "@grafana/monaco-logql": "^0.0.7", + "@grafana/lezer-logql": "0.2.7", + "@grafana/monaco-logql": "^0.0.8", "@grafana/o11y-ds-frontend": "workspace:*", "@grafana/prometheus": "workspace:*", "@grafana/runtime": "workspace:*", diff --git a/yarn.lock b/yarn.lock index 582c3493fc7..d5581c46a4f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3363,6 +3363,15 @@ __metadata: languageName: node linkType: hard +"@grafana/lezer-logql@npm:0.2.7": + version: 0.2.7 + resolution: "@grafana/lezer-logql@npm:0.2.7" + peerDependencies: + "@lezer/lr": ^1.0.0 + checksum: 10/606a9dc77b3b3751e1f325d6b1a8994b1bafef7fe0f6f3980ee7d184244b373f828960f46a748746e765615352ed8928d10f22ff06cede588fcc9d32e70a68d8 + languageName: node + linkType: hard + "@grafana/lezer-traceql@npm:0.0.20": version: 0.0.20 resolution: "@grafana/lezer-traceql@npm:0.0.20" @@ -3381,6 +3390,15 @@ __metadata: languageName: node linkType: hard +"@grafana/monaco-logql@npm:^0.0.8": + version: 0.0.8 + resolution: "@grafana/monaco-logql@npm:0.0.8" + peerDependencies: + monaco-editor: ^0.32.1 + checksum: 10/30443df2bab511e5b385cb8cd5b8ae54b09f794cd3e2b1ad9cdcd58c46d3384b90d3d738c36e63702c17d914d58ad765c93d89d1398e050fa7c9ab68d940386d + languageName: node + linkType: hard + "@grafana/o11y-ds-frontend@workspace:*, @grafana/o11y-ds-frontend@workspace:packages/grafana-o11y-ds-frontend": version: 0.0.0-use.local resolution: "@grafana/o11y-ds-frontend@workspace:packages/grafana-o11y-ds-frontend" @@ -17389,8 +17407,8 @@ __metadata: "@grafana/faro-web-tracing": "npm:^1.8.2" "@grafana/flamegraph": "workspace:*" "@grafana/google-sdk": "npm:0.1.2" - "@grafana/lezer-logql": "npm:0.2.6" - "@grafana/monaco-logql": "npm:^0.0.7" + "@grafana/lezer-logql": "npm:0.2.7" + "@grafana/monaco-logql": "npm:^0.0.8" "@grafana/o11y-ds-frontend": "workspace:*" "@grafana/plugin-e2e": "npm:^1.11.0" "@grafana/prometheus": "workspace:*" From 98e9f3a534429cf98a92f05948618bfa26b6ec81 Mon Sep 17 00:00:00 2001 From: Georges Chaudy Date: Thu, 16 Jan 2025 14:11:55 +0100 Subject: [PATCH 02/30] [unistore] wire authlib compile (#99027) * Wire authz client compile method * add verb to metric * remove tipo --- pkg/storage/unified/resource/access.go | 137 +++++++++++++++++-------- pkg/storage/unified/resource/server.go | 2 + pkg/storage/unified/sql/server.go | 2 +- 3 files changed, 98 insertions(+), 43 deletions(-) diff --git a/pkg/storage/unified/resource/access.go b/pkg/storage/unified/resource/access.go index da6aad7fc2b..28c3c5ede6a 100644 --- a/pkg/storage/unified/resource/access.go +++ b/pkg/storage/unified/resource/access.go @@ -2,12 +2,16 @@ package resource import ( "context" + "fmt" "log/slog" + "sync" "time" "github.com/grafana/authlib/authz" "github.com/grafana/authlib/claims" + "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/services/authn/grpcutils" + "github.com/prometheus/client_golang/prometheus" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace/noop" @@ -33,104 +37,153 @@ var _ authz.AccessClient = &staticAuthzClient{} type groupResource map[string]map[string]interface{} +const ( + metricsNamespace = "grafana" + metricsSubSystem = "grpc_authz_limited_client" +) + +var metOnce sync.Once + +type accessMetrics struct { + checkDuration *prometheus.HistogramVec + compileDuration *prometheus.HistogramVec + errorsTotal *prometheus.CounterVec +} + +func newMetrics(reg prometheus.Registerer) *accessMetrics { + m := &accessMetrics{ + checkDuration: prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: metricsSubSystem, + Name: "check_duration_seconds", + Help: "duration of the access check calls going through the authz service", + }, []string{"group", "resource", "verb", "allowed"}), + compileDuration: prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: metricsSubSystem, + Name: "compile_duration_seconds", + Help: "duration of the access compile calls going through the authz service", + }, []string{"group", "resource", "verb"}), + errorsTotal: prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: metricsSubSystem, + Name: "errors_total", + Help: "Number of errors", + }, []string{"group", "resource", "verb"}), + } + + if reg != nil { + metOnce.Do(func() { + reg.MustRegister(m.checkDuration) + reg.MustRegister(m.compileDuration) + reg.MustRegister(m.errorsTotal) + }) + } + + return m +} + // authzLimitedClient is a client that enforces RBAC for the limited number of groups and resources. // This is a temporary solution until the authz service is fully implemented. // The authz service will be responsible for enforcing RBAC. // For now, it makes one call to the authz service for each list items. This is known to be inefficient. type authzLimitedClient struct { - client authz.AccessChecker + client authz.AccessClient // allowlist is a map of group to resources that are compatible with RBAC. allowlist groupResource logger *slog.Logger tracer trace.Tracer + metrics *accessMetrics } type AuthzOptions struct { - Tracer trace.Tracer + Tracer trace.Tracer + Registry prometheus.Registerer } // NewAuthzLimitedClient creates a new authzLimitedClient. -func NewAuthzLimitedClient(client authz.AccessChecker, opts AuthzOptions) authz.AccessClient { +func NewAuthzLimitedClient(client authz.AccessClient, opts AuthzOptions) authz.AccessClient { logger := slog.Default().With("logger", "limited-authz-client") if opts.Tracer == nil { opts.Tracer = noop.NewTracerProvider().Tracer("limited-authz-client") } + if opts.Registry == nil { + opts.Registry = prometheus.DefaultRegisterer + } return &authzLimitedClient{ client: client, allowlist: groupResource{ "dashboard.grafana.app": map[string]interface{}{"dashboards": nil}, "folder.grafana.app": map[string]interface{}{"folders": nil}, }, - logger: logger, - tracer: opts.Tracer, + logger: logger, + tracer: opts.Tracer, + metrics: newMetrics(opts.Registry), } } // Check implements authz.AccessClient. func (c authzLimitedClient) Check(ctx context.Context, id claims.AuthInfo, req authz.CheckRequest) (authz.CheckResponse, error) { + t := time.Now() ctx, span := c.tracer.Start(ctx, "authzLimitedClient.Check", trace.WithAttributes( attribute.String("group", req.Group), attribute.String("resource", req.Resource), - attribute.Bool("fallback", grpcutils.FallbackUsed(ctx)), + attribute.String("namespace", req.Namespace), + attribute.String("name", req.Name), + attribute.String("verb", req.Verb), + attribute.String("folder", req.Folder), + attribute.Bool("fallback_used", grpcutils.FallbackUsed(ctx)), )) defer span.End() if grpcutils.FallbackUsed(ctx) { - c.logger.Debug("Check", "group", req.Group, "resource", req.Resource, "fallback", true, "rbac", false, "allowed", true) + span.SetAttributes(attribute.Bool("allowed", true)) return authz.CheckResponse{Allowed: true}, nil } if !c.IsCompatibleWithRBAC(req.Group, req.Resource) { - c.logger.Debug("Check", "group", req.Group, "resource", req.Resource, "fallback", false, "rbac", false, "allowed", true) + span.SetAttributes(attribute.Bool("allowed", true)) return authz.CheckResponse{Allowed: true}, nil } - t := time.Now() resp, err := c.client.Check(ctx, id, req) if err != nil { - c.logger.Error("Check", "group", req.Group, "resource", req.Resource, "fallback", false, "rbac", true, "error", err, "duration", time.Since(t)) + c.logger.Error("Check", "group", req.Group, "resource", req.Resource, "error", err, "duration", time.Since(t), "traceid", tracing.TraceIDFromContext(ctx, false)) + c.metrics.errorsTotal.WithLabelValues(req.Group, req.Resource, req.Verb).Inc() + span.SetAttributes(attribute.String("error", err.Error())) return resp, err } - c.logger.Debug("Check", "group", req.Group, "resource", req.Resource, "fallback", false, "rbac", true, "allowed", resp.Allowed, "duration", time.Since(t)) + span.SetAttributes(attribute.Bool("allowed", resp.Allowed)) + c.metrics.checkDuration.WithLabelValues(req.Group, req.Resource, req.Verb, fmt.Sprintf("%t", resp.Allowed)).Observe(time.Since(t).Seconds()) return resp, nil } // Compile implements authz.AccessClient. func (c authzLimitedClient) Compile(ctx context.Context, id claims.AuthInfo, req authz.ListRequest) (authz.ItemChecker, error) { + t := time.Now() + fallbackUsed := grpcutils.FallbackUsed(ctx) ctx, span := c.tracer.Start(ctx, "authzLimitedClient.Compile", trace.WithAttributes( attribute.String("group", req.Group), attribute.String("resource", req.Resource), + attribute.String("namespace", req.Namespace), + attribute.String("verb", req.Verb), + attribute.Bool("fallback_used", fallbackUsed), )) defer span.End() - return func(namespace string, name, folder string) bool { - ctx, span := c.tracer.Start(ctx, "authzLimitedClient.Compile.Check", trace.WithAttributes( - attribute.String("group", req.Group), - attribute.String("resource", req.Resource), - attribute.Bool("fallback", grpcutils.FallbackUsed(ctx)), - )) - defer span.End() - if grpcutils.FallbackUsed(ctx) { - c.logger.Debug("Compile.Check", "group", req.Group, "resource", req.Resource, "fallback", true, "rbac", false, "allowed", true) + if fallbackUsed || !c.IsCompatibleWithRBAC(req.Group, req.Resource) { + return func(namespace string, name, folder string) bool { return true - } - // TODO: Implement For now we perform the check for each item. - if !c.IsCompatibleWithRBAC(req.Group, req.Resource) { - c.logger.Debug("Compile.Check", "group", req.Group, "resource", req.Resource, "namespace", namespace, "name", name, "folder", folder, "fallback", false, "rbac", false, "allowed", true) - return true - } - t := time.Now() - r, err := c.client.Check(ctx, id, authz.CheckRequest{ - Verb: "get", - Group: req.Group, - Resource: req.Resource, - Namespace: namespace, - Name: name, - Folder: folder, - }) - if err != nil { - c.logger.Error("Compile.Check", "group", req.Group, "resource", req.Resource, "namespace", namespace, "name", name, "folder", folder, "fallback", false, "rbac", true, "error", err, "duration", time.Since(t)) - return false - } - c.logger.Debug("Compile.Check", "group", req.Group, "resource", req.Resource, "namespace", namespace, "name", name, "folder", folder, "fallback", false, "rbac", true, "allowed", r.Allowed, "duration", time.Since(t)) - return r.Allowed - }, nil + }, nil + } + checker, err := c.client.Compile(ctx, id, req) + if err != nil { + c.logger.Error("Compile", "group", req.Group, "resource", req.Resource, "error", err, "traceid", tracing.TraceIDFromContext(ctx, false)) + c.metrics.errorsTotal.WithLabelValues(req.Group, req.Resource, req.Verb).Inc() + span.SetAttributes(attribute.String("error", err.Error())) + return nil, err + } + c.metrics.compileDuration.WithLabelValues(req.Group, req.Resource, req.Verb).Observe(time.Since(t).Seconds()) + return checker, nil } func (c authzLimitedClient) IsCompatibleWithRBAC(group, resource string) bool { diff --git a/pkg/storage/unified/resource/server.go b/pkg/storage/unified/resource/server.go index eca39d0e802..01b9b75322c 100644 --- a/pkg/storage/unified/resource/server.go +++ b/pkg/storage/unified/resource/server.go @@ -714,6 +714,7 @@ func (s *server) List(ctx context.Context, req *ListRequest) (*ListResponse, err Group: key.Group, Resource: key.Resource, Namespace: key.Namespace, + Verb: utils.VerbGet, }) if err != nil { return &ListResponse{Error: AsErrorResult(err)}, nil @@ -789,6 +790,7 @@ func (s *server) Restore(ctx context.Context, req *RestoreRequest) (*RestoreResp Group: req.Key.Group, Resource: req.Key.Resource, Namespace: req.Key.Namespace, + Verb: utils.VerbGet, }) if err != nil { return &RestoreResponse{Error: AsErrorResult(err)}, nil diff --git a/pkg/storage/unified/sql/server.go b/pkg/storage/unified/sql/server.go index 0269e395961..a765d8292f6 100644 --- a/pkg/storage/unified/sql/server.go +++ b/pkg/storage/unified/sql/server.go @@ -33,7 +33,7 @@ func NewResourceServer(ctx context.Context, db infraDB.DB, cfg *setting.Cfg, Reg: reg, } if ac != nil { - opts.AccessClient = resource.NewAuthzLimitedClient(ac, resource.AuthzOptions{Tracer: tracer}) + opts.AccessClient = resource.NewAuthzLimitedClient(ac, resource.AuthzOptions{Tracer: tracer, Registry: reg}) } // Support local file blob if strings.HasPrefix(opts.Blob.URL, "./data/") { From 70ddf9cb76b453d52c8ab6dfff629d58fce61161 Mon Sep 17 00:00:00 2001 From: Gabriel MABILLE Date: Thu, 16 Jan 2025 14:33:57 +0100 Subject: [PATCH 03/30] Authenticator: Return gRPC errors (#99000) --- .../unified/resource/grpc/authenticator.go | 47 +++++++++---------- .../resource/grpc/authenticator_test.go | 6 +-- pkg/storage/unified/sql/service.go | 3 +- 3 files changed, 27 insertions(+), 29 deletions(-) diff --git a/pkg/storage/unified/resource/grpc/authenticator.go b/pkg/storage/unified/resource/grpc/authenticator.go index 6c5f2b19dd1..dbb8257feb4 100644 --- a/pkg/storage/unified/resource/grpc/authenticator.go +++ b/pkg/storage/unified/resource/grpc/authenticator.go @@ -2,16 +2,17 @@ package grpc import ( "context" - "fmt" "strconv" "google.golang.org/grpc" + "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" - "github.com/grafana/authlib/authn" authClaims "github.com/grafana/authlib/claims" "github.com/grafana/grafana/pkg/apimachinery/identity" + "github.com/grafana/grafana/pkg/infra/tracing" ) const ( @@ -27,10 +28,13 @@ const ( // var _ interceptors.Authenticator = (*Authenticator)(nil) type Authenticator struct { - IDTokenVerifier authn.Verifier[authn.IDTokenClaims] + Tracer tracing.Tracer } func (f *Authenticator) Authenticate(ctx context.Context) (context.Context, error) { + ctx, span := f.Tracer.Start(ctx, "legacy.grpc.Authenticator.Authenticate") + defer span.End() + r, err := identity.GetRequester(ctx) if err == nil && r != nil { return ctx, nil // noop, requester exists @@ -38,16 +42,19 @@ func (f *Authenticator) Authenticate(ctx context.Context) (context.Context, erro md, ok := metadata.FromIncomingContext(ctx) if !ok { - return nil, fmt.Errorf("no metadata found") + err := status.Error(codes.Unauthenticated, "no metadata found in grpc context") + span.RecordError(err) + return nil, err } - user, err := f.decodeMetadata(ctx, md) + user, err := f.decodeMetadata(md) if err != nil { + span.RecordError(err) return nil, err } return identity.WithRequester(ctx, user), nil } -func (f *Authenticator) decodeMetadata(ctx context.Context, meta metadata.MD) (identity.Requester, error) { +func (f *Authenticator) decodeMetadata(meta metadata.MD) (identity.Requester, error) { // Avoid NPE/panic with getting keys getter := func(key string) string { v := meta.Get(key) @@ -57,20 +64,10 @@ func (f *Authenticator) decodeMetadata(ctx context.Context, meta metadata.MD) (i return "" } - // First try the token - token := getter(mdToken) - if token != "" && f.IDTokenVerifier != nil { - claims, err := f.IDTokenVerifier.Verify(ctx, token) - if err != nil { - return nil, err - } - fmt.Printf("TODO, convert CLAIMS to an identity %+v\n", claims) - } - user := &identity.StaticRequester{} user.Login = getter(mdLogin) if user.Login == "" { - return nil, fmt.Errorf("no login found in grpc metadata") + return nil, status.Error(codes.Unauthenticated, "no login found in grpc metadata") } // The namespaced versions have a "-" in the key @@ -80,34 +77,34 @@ func (f *Authenticator) decodeMetadata(ctx context.Context, meta metadata.MD) (i user.Type = authClaims.TypeUser user.UserID, err = strconv.ParseInt(getter("grafana-userid"), 10, 64) if err != nil { - return nil, fmt.Errorf("invalid user id: %w", err) + return nil, status.Error(codes.Unauthenticated, "invalid user id") } user.OrgID, err = strconv.ParseInt(getter("grafana-orgid"), 10, 64) if err != nil { - return nil, fmt.Errorf("invalid org id: %w", err) + return nil, status.Error(codes.Unauthenticated, "invalid org id") } return user, nil } typ, id, err := authClaims.ParseTypeID(getter(mdUserID)) if err != nil { - return nil, fmt.Errorf("invalid user id: %w", err) + return nil, status.Error(codes.Unauthenticated, "invalid user id") } user.Type = typ user.UserID, err = strconv.ParseInt(id, 10, 64) if err != nil { - return nil, fmt.Errorf("invalid user id: %w", err) + return nil, status.Error(codes.Unauthenticated, "invalid user id") } - _, id, err = authClaims.ParseTypeID(getter(mdUserUID)) + _, uid, err := authClaims.ParseTypeID(getter(mdUserUID)) if err != nil { - return nil, fmt.Errorf("invalid user id: %w", err) + return nil, status.Error(codes.Unauthenticated, "invalid user uid") } - user.UserUID = id + user.UserUID = uid user.OrgID, err = strconv.ParseInt(getter(mdOrgID), 10, 64) if err != nil { - return nil, fmt.Errorf("invalid org id: %w", err) + return nil, status.Error(codes.Unauthenticated, "invalid org id") } user.OrgRole = identity.RoleType(getter(mdOrgRole)) return user, nil diff --git a/pkg/storage/unified/resource/grpc/authenticator_test.go b/pkg/storage/unified/resource/grpc/authenticator_test.go index 674d846c486..c89a19c6dd2 100644 --- a/pkg/storage/unified/resource/grpc/authenticator_test.go +++ b/pkg/storage/unified/resource/grpc/authenticator_test.go @@ -1,13 +1,13 @@ package grpc import ( - "context" "testing" "github.com/stretchr/testify/require" "github.com/grafana/authlib/claims" "github.com/grafana/grafana/pkg/apimachinery/identity" + "github.com/grafana/grafana/pkg/infra/tracing" ) func TestBasicEncodeDecode(t *testing.T) { @@ -20,10 +20,10 @@ func TestBasicEncodeDecode(t *testing.T) { OrgRole: identity.RoleAdmin, } - auth := &Authenticator{} + auth := &Authenticator{Tracer: tracing.NewNoopTracerService()} md := encodeIdentityInMetadata(before) - after, err := auth.decodeMetadata(context.Background(), md) + after, err := auth.decodeMetadata(md) require.NoError(t, err) require.Equal(t, before.GetID(), after.GetID()) require.Equal(t, before.GetUID(), after.GetUID()) diff --git a/pkg/storage/unified/sql/service.go b/pkg/storage/unified/sql/service.go index 4397a48b6d4..6c05f884b27 100644 --- a/pkg/storage/unified/sql/service.go +++ b/pkg/storage/unified/sql/service.go @@ -80,7 +80,8 @@ func ProvideUnifiedStorageGrpcService( // FIXME: This is a temporary solution while we are migrating to the new authn interceptor // grpcutils.NewGrpcAuthenticator should be used instead. - authn, err := grpcutils.NewGrpcAuthenticatorWithFallback(cfg, reg, tracing, &grpc.Authenticator{}) + fallback := &grpc.Authenticator{Tracer: tracing} + authn, err := grpcutils.NewGrpcAuthenticatorWithFallback(cfg, reg, tracing, fallback) if err != nil { return nil, err } From 862c0ce9b50b1d10b62d5e7a93a7145bca6cf23d Mon Sep 17 00:00:00 2001 From: Tom Ratcliffe Date: Thu, 16 Jan 2025 13:59:32 +0000 Subject: [PATCH 04/30] Alerting: Fix check for contact point email in IRM essentials page (#98977) --- .../configuration-tracker/alerting/hooks.ts | 18 ------------- .../configuration-tracker/alerting/utils.ts | 25 ++++++++++++------- .../gops/configuration-tracker/irmHooks.ts | 14 +++++++---- 3 files changed, 25 insertions(+), 32 deletions(-) diff --git a/public/app/features/gops/configuration-tracker/alerting/hooks.ts b/public/app/features/gops/configuration-tracker/alerting/hooks.ts index f0cde843803..5893cc31b9e 100644 --- a/public/app/features/gops/configuration-tracker/alerting/hooks.ts +++ b/public/app/features/gops/configuration-tracker/alerting/hooks.ts @@ -1,7 +1,6 @@ import { useEffect } from 'react'; import { alertRuleApi } from 'app/features/alerting/unified/api/alertRuleApi'; -import { alertmanagerApi } from 'app/features/alerting/unified/api/alertmanagerApi'; import { ReceiverTypes } from 'app/features/alerting/unified/components/receivers/grafanaAppReceivers/onCall/onCall'; import { useDataSourceFeatures } from 'app/features/alerting/unified/hooks/useCombinedRule'; import { GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting/unified/utils/datasource'; @@ -34,20 +33,3 @@ export function isOnCallContactPointReady(contactPoints: Receiver[]) { contactPoint.grafana_managed_receiver_configs?.some((receiver) => receiver.type === ReceiverTypes.OnCall) ); } - -/** - * @deprecated Will be removed when notification policies is moved to k8s API. Do not use! - */ -export function useGetDefaultContactPoint() { - const alertmanagerConfiguration = alertmanagerApi.endpoints.getAlertmanagerConfiguration.useQuery( - GRAFANA_RULES_SOURCE_NAME, - { - refetchOnFocus: true, - refetchOnReconnect: true, - refetchOnMountOrArgChange: true, - } - ); - - const defaultContactpoint = alertmanagerConfiguration.data?.alertmanager_config?.route?.receiver ?? ''; - return { defaultContactpoint, isLoading: alertmanagerConfiguration.isLoading }; -} diff --git a/public/app/features/gops/configuration-tracker/alerting/utils.ts b/public/app/features/gops/configuration-tracker/alerting/utils.ts index 481f42504af..3982b9dcffa 100644 --- a/public/app/features/gops/configuration-tracker/alerting/utils.ts +++ b/public/app/features/gops/configuration-tracker/alerting/utils.ts @@ -2,14 +2,21 @@ import { Receiver } from 'app/plugins/datasource/alertmanager/types'; const DEFAULT_EMAIL = ''; export function isContactPointReady(defaultContactPoint: string, contactPoints: Receiver[]) { - // We consider the contact point ready if the default contact has the address filled - - const defaultEmailUpdated = contactPoints.some( - (contactPoint: Receiver) => - contactPoint.name === defaultContactPoint && - contactPoint.grafana_managed_receiver_configs?.some( - (receiver) => receiver.name === defaultContactPoint && receiver.settings?.address !== DEFAULT_EMAIL - ) + // We consider the contact point ready if the default contact is no longer referencing the default email address + const matchingDefaultContactPoint = contactPoints.find( + (contactPoint: Receiver) => contactPoint.name === defaultContactPoint ); - return defaultEmailUpdated; + + if (!matchingDefaultContactPoint) { + return false; + } + + return matchingDefaultContactPoint.grafana_managed_receiver_configs?.some((receiver) => { + const isEmailReceiver = receiver.type === 'email'; + if (isEmailReceiver) { + return receiver.settings?.addresses !== DEFAULT_EMAIL; + } else { + return true; + } + }); } diff --git a/public/app/features/gops/configuration-tracker/irmHooks.ts b/public/app/features/gops/configuration-tracker/irmHooks.ts index 39121db0e6e..3510de2e5e5 100644 --- a/public/app/features/gops/configuration-tracker/irmHooks.ts +++ b/public/app/features/gops/configuration-tracker/irmHooks.ts @@ -2,9 +2,11 @@ import { useMemo } from 'react'; import { locationService } from '@grafana/runtime'; import { useGrafanaContactPoints } from 'app/features/alerting/unified/components/contact-points/useContactPoints'; +import { useNotificationPolicyRoute } from 'app/features/alerting/unified/components/notification-policies/useNotificationPolicyRoute'; +import { GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting/unified/utils/datasource'; import { RelativeUrl, createRelativeUrl } from 'app/features/alerting/unified/utils/url'; -import { isOnCallContactPointReady, useGetDefaultContactPoint, useIsCreateAlertRuleDone } from './alerting/hooks'; +import { isOnCallContactPointReady, useIsCreateAlertRuleDone } from './alerting/hooks'; import { isContactPointReady } from './alerting/utils'; import { ConfigurationStepsEnum, DataSourceConfigurationData, IrmCardConfiguration } from './components/ConfigureIRM'; import { useGetIncidentPluginConfig } from './incidents/hooks'; @@ -50,8 +52,10 @@ export interface EssentialsConfigurationData { function useGetConfigurationForApps() { // configuration checks for alerting const { contactPoints, isLoading: isLoadingContactPoints } = useGrafanaContactPoints(); - // TODO: Switch to k8s API/refactored notification policies hook when available - const { defaultContactpoint, isLoading: isLoadingDefaultContactPoint } = useGetDefaultContactPoint(); + const { data: rootRoute, isLoading: isLoadingDefaultContactPoint } = useNotificationPolicyRoute({ + alertmanager: GRAFANA_RULES_SOURCE_NAME, + }); + const defaultContactpoint = rootRoute?.[0].receiver || ''; const { isDone: isCreateAlertRuleDone, isLoading: isLoadingAlertCreatedDone } = useIsCreateAlertRuleDone(); // configuration checks for incidents const { @@ -124,8 +128,8 @@ export function useGetEssentialsConfiguration(): EssentialsConfigurationData { description: 'Configure Grafana Alerting', steps: [ { - title: 'Update default email contact point', - description: 'Add a valid email to the default email contact point.', + title: 'Update default contact point', + description: 'Update the default contact point to a method other than the example email address.', button: { type: 'openLink', urlLink: { From 4c0fa629dac45e2678f6af062c6e67c4fd50acab Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Thu, 16 Jan 2025 15:01:51 +0100 Subject: [PATCH 05/30] Prometheus: Support utf8 metric/label/label value suggestions in code mode (#98253) * utf8 metrics for prometheus devenv * introduce utf8 support * completions and suggestions * don't wrap the utf8 label in quotes * linting * support series endpoint --- .../monaco-completion-provider/completions.ts | 44 +++- .../data_provider.ts | 3 + .../monaco-completion-provider/index.ts | 1 + .../situation.test.ts | 125 +++++++++++ .../monaco-completion-provider/situation.ts | 200 ++++++++++++++---- .../src/language_provider.test.ts | 149 ++++++++++++- .../src/language_provider.ts | 27 ++- .../src/language_utils.test.ts | 52 +++++ .../grafana-prometheus/src/language_utils.ts | 5 +- .../src/utf8_support.test.ts | 35 +++ .../grafana-prometheus/src/utf8_support.ts | 81 +++++++ 11 files changed, 657 insertions(+), 65 deletions(-) create mode 100644 packages/grafana-prometheus/src/utf8_support.test.ts create mode 100644 packages/grafana-prometheus/src/utf8_support.ts diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.ts index 1060c8df90a..ff1f0490560 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.ts @@ -1,11 +1,13 @@ // Core grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/completions.ts import UFuzzy from '@leeoniya/ufuzzy'; +import { languages } from 'monaco-editor'; import { config } from '@grafana/runtime'; import { prometheusRegularEscape } from '../../../datasource'; import { escapeLabelValueInExactSelector } from '../../../language_utils'; import { FUNCTIONS } from '../../../promql'; +import { isValidLegacyName } from '../../../utf8_support'; import { DataProvider } from './data_provider'; import type { Label, Situation } from './situation'; @@ -14,10 +16,16 @@ import { NeverCaseError } from './util'; export type CompletionType = 'HISTORY' | 'FUNCTION' | 'METRIC_NAME' | 'DURATION' | 'LABEL_NAME' | 'LABEL_VALUE'; +// We cannot use languages.CompletionItemInsertTextRule.InsertAsSnippet because grafana-prometheus package isn't compatible +// It should first change the moduleResolution to bundler for TS to correctly resolve the types +// https://github.com/grafana/grafana/pull/96450 +const InsertAsSnippet = 4; + type Completion = { type: CompletionType; label: string; insertText: string; + insertTextRules?: languages.CompletionItemInsertTextRule; detail?: string; documentation?: string; triggerOnInsert?: boolean; @@ -29,6 +37,11 @@ const metricNamesSearch = { singleError: new UFuzzy({ intraMode: 1 }), }; +// Snippet Marker is telling monaco where to show the cursor and maybe a help text +// With help text example: ${1:labelName} +// labelName will be shown as selected. So user would know what to type next +const snippetMarker = '${1:}'; + interface MetricFilterOptions { metricNames: string[]; inputText: string; @@ -74,9 +87,16 @@ function getAllMetricNamesCompletions(dataProvider: DataProvider): Completion[] return dataProvider.metricNamesToMetrics(metricNames).map((metric) => ({ type: 'METRIC_NAME', label: metric.name, - insertText: metric.name, detail: `${metric.name} : ${metric.type}`, documentation: metric.help, + ...(metric.isUtf8 + ? { + insertText: `{"${metric.name}"${snippetMarker}}`, + insertTextRules: InsertAsSnippet, + } + : { + insertText: metric.name, + }), })); } @@ -159,12 +179,22 @@ async function getLabelNamesForCompletions( dataProvider: DataProvider ): Promise { const labelNames = await getLabelNames(metric, otherLabels, dataProvider); - return labelNames.map((text) => ({ - type: 'LABEL_NAME', - label: text, - insertText: `${text}${suffix}`, - triggerOnInsert, - })); + return labelNames.map((text) => { + const isUtf8 = !isValidLegacyName(text); + return { + type: 'LABEL_NAME', + label: text, + ...(isUtf8 + ? { + insertText: `"${text}"${suffix}`, + insertTextRules: InsertAsSnippet, + } + : { + insertText: `${text}${suffix}`, + }), + triggerOnInsert, + }; + }); } async function getLabelNamesForSelectorCompletions( diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/data_provider.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/data_provider.ts index 48549442d64..b1baad9a770 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/data_provider.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/data_provider.ts @@ -3,6 +3,7 @@ import type { Monaco } from '@grafana/ui'; // used in TSDoc `@link` below import PromQlLanguageProvider from '../../../language_provider'; import { PromQuery } from '../../../types'; +import { isValidLegacyName } from '../../../utf8_support'; export const CODE_MODE_SUGGESTIONS_INCOMPLETE_EVENT = 'codeModeSuggestionsIncomplete'; @@ -26,6 +27,7 @@ interface Metric { name: string; help: string; type: string; + isUtf8?: boolean; } export interface DataProviderParams { @@ -78,6 +80,7 @@ export class DataProvider { name: m, help: metaItem?.help ?? '', type: metaItem?.type ?? '', + isUtf8: !isValidLegacyName(m), }; }); diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/index.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/index.ts index abc97de27ce..5108401b2fd 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/index.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/index.ts @@ -95,6 +95,7 @@ export function getCompletionProvider( kind: getMonacoCompletionItemKind(item.type, monaco), label: item.label, insertText: item.insertText, + insertTextRules: item.insertTextRules, detail: item.detail, documentation: item.documentation, sortText: index.toString().padStart(maxIndexDigits, '0'), // to force the order we have diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.test.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.test.ts index 188eb333415..65e82cc1ca3 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.test.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.test.ts @@ -56,6 +56,7 @@ describe('situation', () => { type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', metricName: 'something', otherLabels: [], + betweenQuotes: false, }); assertSituation('sum(something) by (^)', { @@ -79,34 +80,157 @@ describe('situation', () => { { name: 'three', value: 'val3', op: '=~' }, { name: 'four', value: 'val4', op: '!~' }, ], + betweenQuotes: false, }); assertSituation('{^}', { type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', otherLabels: [], + betweenQuotes: false, }); assertSituation('{one="val1",^}', { type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', otherLabels: [{ name: 'one', value: 'val1', op: '=' }], + betweenQuotes: false, }); // single-quoted label-values with escape assertSituation("{one='val\\'1',^}", { type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', otherLabels: [{ name: 'one', value: "val'1", op: '=' }], + betweenQuotes: false, }); // double-quoted label-values with escape assertSituation('{one="val\\"1",^}', { type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', otherLabels: [{ name: 'one', value: 'val"1', op: '=' }], + betweenQuotes: false, }); // backticked label-values with escape (the escape should not be interpreted) assertSituation('{one=`val\\"1`,^}', { type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', otherLabels: [{ name: 'one', value: 'val\\"1', op: '=' }], + betweenQuotes: false, + }); + }); + + describe('utf-8 metric name support', () => { + it('with utf8 metric name no label and no comma', () => { + assertSituation(`{"metric.name"^}`, null); + }); + + it('with utf8 metric name no label', () => { + assertSituation(`{"metric.name", ^}`, { + type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', + metricName: 'metric.name', + otherLabels: [], + betweenQuotes: false, + }); + }); + + it('with utf8 metric name requesting utf8 labels in quotes', () => { + assertSituation(`{"metric.name", "^"}`, { + type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', + metricName: 'metric.name', + otherLabels: [], + betweenQuotes: true, + }); + }); + + it('with utf8 metric name with a legacy label', () => { + assertSituation(`{"metric.name", label1="val", ^}`, { + type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', + metricName: 'metric.name', + otherLabels: [{ name: 'label1', value: 'val', op: '=' }], + betweenQuotes: false, + }); + }); + + it('with utf8 metric name with a legacy label and no value', () => { + assertSituation(`{"metric.name", label1="^"}`, { + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', + metricName: 'metric.name', + labelName: 'label1', + betweenQuotes: true, + otherLabels: [], + }); + }); + + it('with utf8 metric name with a utf8 label and no value', () => { + assertSituation(`{"metric.name", "utf8.label"="^"}`, { + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', + metricName: 'metric.name', + labelName: '"utf8.label"', + betweenQuotes: true, + otherLabels: [], + }); + }); + + it('with utf8 metric name with a legacy label and utf8 label', () => { + assertSituation(`{"metric.name", label1="val", "utf8.label"="^"}`, { + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', + metricName: 'metric.name', + labelName: `"utf8.label"`, + betweenQuotes: true, + otherLabels: [{ name: 'label1', value: 'val', op: '=' }], + }); + }); + + it('with utf8 metric name with a utf8 label and legacy label', () => { + assertSituation(`{"metric.name", "utf8.label"="val", label1="^"}`, { + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', + metricName: 'metric.name', + labelName: `label1`, + betweenQuotes: true, + otherLabels: [{ name: '"utf8.label"', value: 'val', op: '=' }], + }); + }); + + it('with utf8 metric name with grouping', () => { + assertSituation(`sum by (^)(rate({"metric.name", label1="val"}[1m]))`, { + type: 'IN_GROUPING', + metricName: 'metric.name', + otherLabels: [], + }); + }); + }); + + it('utf-8 label support', () => { + assertSituation(`metric{"label": "^"}`, null); + + assertSituation(`metric{"label with space": "^"}`, null); + + assertSituation(`metric{"label_🤖": "^"}`, null); + + assertSituation(`metric{"Spaß": "^"}`, null); + + assertSituation(`{"metric", "Spaß": "^"}`, null); + + assertSituation('something{"job"=^}', { + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', + metricName: 'something', + labelName: '"job"', + betweenQuotes: false, + otherLabels: [], + }); + + assertSituation('something{"job📈"=^}', { + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', + metricName: 'something', + labelName: '"job📈"', + betweenQuotes: false, + otherLabels: [], + }); + + assertSituation('something{"job with space"=^,host="h1"}', { + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', + metricName: 'something', + labelName: '"job with space"', + betweenQuotes: false, + otherLabels: [{ name: 'host', value: 'h1', op: '=' }], }); }); @@ -194,6 +318,7 @@ describe('situation', () => { { name: 'three', value: 'val3', op: '=~' }, { name: 'four', value: 'val4', op: '!~' }, ], + betweenQuotes: false, }); }); }); diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.ts index c7420522b4c..7b1bbac866a 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.ts @@ -18,6 +18,8 @@ import { NumberDurationLiteralInDurationContext, parser, PromQL, + QuotedLabelMatcher, + QuotedLabelName, StringLiteral, UnquotedLabelMatcher, VectorSelector, @@ -35,8 +37,10 @@ type NodeTypeId = | typeof GroupingLabels | typeof Identifier | typeof UnquotedLabelMatcher + | typeof QuotedLabelMatcher | typeof LabelMatchers | typeof LabelName + | typeof QuotedLabelName | typeof PromQL | typeof StringLiteral | typeof VectorSelector @@ -80,8 +84,10 @@ function walk(node: SyntaxNode, path: Path): SyntaxNode | null { return current; } -function getNodeText(node: SyntaxNode, text: string): string { - return text.slice(node.from, node.to); +function getNodeText(node: SyntaxNode, text: string, utf8?: boolean): string { + const nodeFrom = utf8 ? node.from + 1 : node.from; + const nodeTo = utf8 ? node.to - 1 : node.to; + return text.slice(nodeFrom, nodeTo); } function parsePromQLStringLiteral(text: string): string { @@ -140,6 +146,8 @@ export type Situation = type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME'; metricName?: string; otherLabels: Label[]; + // utf8 labels must be in quotes + betweenQuotes: boolean; } | { type: 'IN_GROUPING'; @@ -170,6 +178,10 @@ const RESOLVERS: Resolver[] = [ path: [LabelMatchers, VectorSelector], fun: resolveLabelKeysWithEquals, }, + { + path: [StringLiteral, QuotedLabelName, LabelMatchers, VectorSelector], + fun: resolveUtf8LabelKeysWithEquals, + }, { path: [PromQL], fun: resolveTopLevel, @@ -182,6 +194,10 @@ const RESOLVERS: Resolver[] = [ path: [StringLiteral, UnquotedLabelMatcher], fun: resolveLabelMatcher, }, + { + path: [StringLiteral, QuotedLabelMatcher], + fun: resolveQuotedLabelMatcher, + }, { path: [ERROR_NODE_NAME, BinaryExpr, PromQL], fun: resolveTopLevel, @@ -190,6 +206,10 @@ const RESOLVERS: Resolver[] = [ path: [ERROR_NODE_NAME, UnquotedLabelMatcher], fun: resolveLabelMatcher, }, + { + path: [ERROR_NODE_NAME, QuotedLabelMatcher], + fun: resolveQuotedLabelMatcher, + }, { path: [ERROR_NODE_NAME, NumberDurationLiteralInDurationContext, MatrixSelector], fun: resolveDurations, @@ -217,11 +237,13 @@ function getLabelOp(opNode: SyntaxNode): LabelOperator | null { } function getLabel(labelMatcherNode: SyntaxNode, text: string): Label | null { - if (labelMatcherNode.type.id !== UnquotedLabelMatcher) { + const allowedMatchers = new Set([UnquotedLabelMatcher, QuotedLabelMatcher]); + if (!allowedMatchers.has(labelMatcherNode.type.id)) { return null; } - const nameNode = walk(labelMatcherNode, [['firstChild', LabelName]]); + const nameNode = + walk(labelMatcherNode, [['firstChild', LabelName]]) ?? walk(labelMatcherNode, [['firstChild', QuotedLabelName]]); if (nameNode === null) { return null; @@ -254,8 +276,17 @@ function getLabels(labelMatchersNode: SyntaxNode, text: string): Label[] { return []; } - const labelNodes = labelMatchersNode.getChildren(UnquotedLabelMatcher); - return labelNodes.map((ln) => getLabel(ln, text)).filter(notEmpty); + const matchers = [UnquotedLabelMatcher, QuotedLabelMatcher]; + + return matchers.reduce((acc, matcher) => { + labelMatchersNode.getChildren(matcher).forEach((ln) => { + const label = getLabel(ln, text); + if (notEmpty(label)) { + acc.push(label); + } + }); + return acc; + }, []); } function getNodeChildren(node: SyntaxNode): SyntaxNode[] { @@ -299,12 +330,20 @@ function resolveLabelsForGrouping(node: SyntaxNode, text: string, pos: number): return null; } - const metricIdNode = getNodeInSubtree(bodyNode, Identifier); - if (metricIdNode === null) { + const metricIdNode = getNodeInSubtree(bodyNode, Identifier) ?? getNodeInSubtree(bodyNode, StringLiteral); + + if (!metricIdNode) { return null; } - const metricName = getNodeText(metricIdNode, text); + // Let's check whether it's a utf8 metric. + // A utf8 metric must be a StringLiteral and its parent must be a QuotedLabelName + if (metricIdNode.type.id === StringLiteral && metricIdNode.parent?.type.id !== QuotedLabelName) { + return null; + } + + const metricName = getNodeText(metricIdNode, text, metricIdNode.type.id === StringLiteral); + return { type: 'IN_GROUPING', metricName, @@ -341,29 +380,54 @@ function resolveLabelMatcher(node: SyntaxNode, text: string, pos: number): Situa // we need to remove "our" label from all-labels, if it is in there const otherLabels = allLabels.filter((label) => label.name !== labelName); - const metricNameNode = walk(labelMatchersNode, [ - ['parent', VectorSelector], - ['firstChild', Identifier], - ]); - - if (metricNameNode === null) { - // we are probably in a situation without a metric name - return { - type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', - labelName, - betweenQuotes: inStringNode, - otherLabels, - }; - } - - const metricName = getNodeText(metricNameNode, text); + const metricName = getMetricName(labelMatchersNode, text); + // we are probably in a situation without a metric name return { type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', - metricName, labelName, betweenQuotes: inStringNode, otherLabels, + ...(metricName ? { metricName } : {}), + }; +} + +function resolveQuotedLabelMatcher(node: SyntaxNode, text: string, pos: number): Situation | null { + // we can arrive here in two situation. `node` is either: + // - a StringNode (like in `{"job"="^"}`) + // - or an error node (like in `{"job"=^}`) + const inStringNode = !node.type.isError; + + const parent = walk(node, [['parent', QuotedLabelMatcher]]); + if (parent === null) { + return null; + } + + const labelNameNode = walk(parent, [['firstChild', QuotedLabelName]]); + if (labelNameNode === null) { + return null; + } + + const labelName = getNodeText(labelNameNode, text); + + const labelMatchersNode = walk(parent, [['parent', LabelMatchers]]); + if (labelMatchersNode === null) { + return null; + } + + // now we need to find the other names + const allLabels = getLabels(labelMatchersNode, text); + + // we need to remove "our" label from all-labels, if it is in there + const otherLabels = allLabels.filter((label) => label.name !== labelName); + const metricName = getMetricName(parent.parent!, text); + + return { + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', + labelName, + betweenQuotes: inStringNode, + otherLabels, + ...(metricName ? { metricName } : {}), }; } @@ -388,7 +452,7 @@ function resolveDurations(node: SyntaxNode, text: string, pos: number): Situatio function resolveLabelKeysWithEquals(node: SyntaxNode, text: string, pos: number): Situation | null { // next false positive: // `something{a="1"^}` - const child = walk(node, [['firstChild', UnquotedLabelMatcher]]); + let child = walk(node, [['firstChild', UnquotedLabelMatcher]]); if (child !== null) { // means the label-matching part contains at least one label already. // @@ -403,28 +467,72 @@ function resolveLabelKeysWithEquals(node: SyntaxNode, text: string, pos: number) } } - const metricNameNode = walk(node, [ + // next false positive: + // `{"utf8.metric"^}` + child = walk(node, [['firstChild', QuotedLabelName]]); + if (child !== null) { + // means the label-matching part contains a utf8 metric. + // + // in this case, we will need to have a `,` character at the end, + // to be able to suggest adding the next label. + // the area between the end-of-the-child-node and the cursor-pos + // must contain a `,` in this case. + const textToCheck = text.slice(child.to, pos); + + if (!textToCheck.includes(',')) { + return null; + } + } + + const otherLabels = getLabels(node, text); + const metricName = getMetricName(node, text); + + return { + type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', + otherLabels, + betweenQuotes: false, + ...(metricName ? { metricName } : {}), + }; +} + +function resolveUtf8LabelKeysWithEquals(node: SyntaxNode, text: string, pos: number): Situation | null { + const otherLabels = getLabels(node, text); + const metricName = node.parent?.parent ? getMetricName(node.parent.parent, text) : null; + + return { + type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', + otherLabels, + betweenQuotes: true, + ...(metricName ? { metricName } : {}), + }; +} + +function getMetricName(node: SyntaxNode, text: string): string | null { + // Legacy Metric metric_name{label="value"} + const legacyMetricNameNode = walk(node, [ ['parent', VectorSelector], ['firstChild', Identifier], ]); - const otherLabels = getLabels(node, text); - - if (metricNameNode === null) { - // we are probably in a situation without a metric name. - return { - type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', - otherLabels, - }; + if (legacyMetricNameNode) { + return getNodeText(legacyMetricNameNode, text); } - const metricName = getNodeText(metricNameNode, text); + // check for a utf-8 metric + // utf-8 metric {"metric.name", label="value"} + const utf8MetricNameNode = walk(node, [ + ['parent', VectorSelector], + ['firstChild', LabelMatchers], + ['firstChild', QuotedLabelName], + ['firstChild', StringLiteral], + ]); - return { - type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', - metricName, - otherLabels, - }; + if (utf8MetricNameNode) { + return getNodeText(utf8MetricNameNode, text, true); + } + + // no metric name + return null; } // we find the first error-node in the tree that is at the cursor-position. @@ -461,10 +569,10 @@ export function getSituation(text: string, pos: number): Situation | null { } /** - PromQL - Expr - VectorSelector - LabelMatchers + PromQL + Expr + VectorSelector + LabelMatchers */ const tree = parser.parse(text); diff --git a/packages/grafana-prometheus/src/language_provider.test.ts b/packages/grafana-prometheus/src/language_provider.test.ts index c9ed7dc2b14..48ed7276693 100644 --- a/packages/grafana-prometheus/src/language_provider.test.ts +++ b/packages/grafana-prometheus/src/language_provider.test.ts @@ -4,7 +4,7 @@ import { AbstractLabelOperator, dateTime, TimeRange } from '@grafana/data'; import { DEFAULT_SERIES_LIMIT } from './components/PrometheusMetricsBrowser'; import { Label } from './components/monaco-query-field/monaco-completion-provider/situation'; import { PrometheusDatasource } from './datasource'; -import LanguageProvider from './language_provider'; +import LanguageProvider, { removeQuotesIfExist } from './language_provider'; import { getClientCacheDurationInMinutes, getPrometheusTime, getRangeSnapInterval } from './language_utils'; import { PrometheusCacheLevel, PromQuery } from './types'; @@ -120,7 +120,13 @@ describe('Language completion provider', () => { const labelName = 'job'; const labelValue = 'grafana'; - getSeriesLabels(`{${labelName}="${labelValue}"}`, [{ name: labelName, value: labelValue, op: '=' }] as Label[]); + getSeriesLabels(`{${labelName}="${labelValue}"}`, [ + { + name: labelName, + value: labelValue, + op: '=', + }, + ] as Label[]); expect(requestSpy).toHaveBeenCalled(); expect(requestSpy).toHaveBeenCalledWith( `/api/v1/labels`, @@ -145,7 +151,13 @@ describe('Language completion provider', () => { const labelName = 'job'; const labelValue = 'grafana'; - getSeriesLabels(`{${labelName}="${labelValue}"}`, [{ name: labelName, value: labelValue, op: '=' }] as Label[]); + getSeriesLabels(`{${labelName}="${labelValue}"}`, [ + { + name: labelName, + value: labelValue, + op: '=', + }, + ] as Label[]); expect(requestSpy).toHaveBeenCalled(); expect(requestSpy).toHaveBeenCalledWith( '/api/v1/series', @@ -174,7 +186,13 @@ describe('Language completion provider', () => { const labelName = 'job'; const labelValue = 'grafana'; - getSeriesLabels(`{${labelName}="${labelValue}"}`, [{ name: labelName, value: labelValue, op: '=' }] as Label[]); + getSeriesLabels(`{${labelName}="${labelValue}"}`, [ + { + name: labelName, + value: labelValue, + op: '=', + }, + ] as Label[]); expect(requestSpy).toHaveBeenCalled(); expect(requestSpy).toHaveBeenCalledWith( `/api/v1/labels`, @@ -569,14 +587,14 @@ describe('Language completion provider', () => { it('should interpolate variable in series', () => { const languageProvider = new LanguageProvider({ ...defaultDatasource, - interpolateString: (string: string) => string.replace(/\$/, 'interpolated-'), + interpolateString: (string: string) => string.replace(/\$/g, 'interpolated_'), } as PrometheusDatasource); const fetchLabelValues = languageProvider.fetchLabelValues; const requestSpy = jest.spyOn(languageProvider, 'request'); fetchLabelValues('$job'); expect(requestSpy).toHaveBeenCalled(); expect(requestSpy).toHaveBeenCalledWith( - '/api/v1/label/interpolated-job/values', + '/api/v1/label/interpolated_job/values', [], { end: toPrometheusTimeString, @@ -585,6 +603,69 @@ describe('Language completion provider', () => { undefined ); }); + + it('should fetch with encoded utf8 label', () => { + const languageProvider = new LanguageProvider({ + ...defaultDatasource, + interpolateString: (string: string) => string.replace(/\$/g, 'http.status:sum'), + } as PrometheusDatasource); + const fetchLabelValues = languageProvider.fetchLabelValues; + const requestSpy = jest.spyOn(languageProvider, 'request'); + fetchLabelValues('"http.status:sum"'); + expect(requestSpy).toHaveBeenCalled(); + expect(requestSpy).toHaveBeenCalledWith( + '/api/v1/label/U__http_2e_status:sum/values', + [], + { + end: toPrometheusTimeString, + start: fromPrometheusTimeString, + }, + undefined + ); + }); + }); + + describe('fetchSeriesValuesWithMatch', () => { + it('should fetch with encoded utf8 label', () => { + const languageProvider = new LanguageProvider({ + ...defaultDatasource, + interpolateString: (string: string) => string.replace(/\$/g, 'http.status:sum'), + } as PrometheusDatasource); + const fetchSeriesValuesWithMatch = languageProvider.fetchSeriesValuesWithMatch; + const requestSpy = jest.spyOn(languageProvider, 'request'); + fetchSeriesValuesWithMatch('"http.status:sum"', '{__name__="a_utf8_http_requests_total"}'); + expect(requestSpy).toHaveBeenCalled(); + expect(requestSpy).toHaveBeenCalledWith( + '/api/v1/label/U__http_2e_status:sum/values', + [], + { + end: toPrometheusTimeString, + start: fromPrometheusTimeString, + 'match[]': '{__name__="a_utf8_http_requests_total"}', + }, + undefined + ); + }); + + it('should fetch without encoding for standard prometheus labels', () => { + const languageProvider = new LanguageProvider({ + ...defaultDatasource, + } as PrometheusDatasource); + const fetchSeriesValuesWithMatch = languageProvider.fetchSeriesValuesWithMatch; + const requestSpy = jest.spyOn(languageProvider, 'request'); + fetchSeriesValuesWithMatch('"http_status_sum"', '{__name__="a_utf8_http_requests_total"}'); + expect(requestSpy).toHaveBeenCalled(); + expect(requestSpy).toHaveBeenCalledWith( + '/api/v1/label/http_status_sum/values', + [], + { + end: toPrometheusTimeString, + start: fromPrometheusTimeString, + 'match[]': '{__name__="a_utf8_http_requests_total"}', + }, + undefined + ); + }); }); describe('disabled metrics lookup', () => { @@ -650,3 +731,59 @@ describe('Language completion provider', () => { }); }); }); + +describe('removeQuotesIfExist', () => { + it('removes quotes from a string with double quotes', () => { + const input = '"hello"'; + const result = removeQuotesIfExist(input); + expect(result).toBe('hello'); + }); + + it('returns the original string if it does not start and end with quotes', () => { + const input = 'hello'; + const result = removeQuotesIfExist(input); + expect(result).toBe('hello'); + }); + + it('returns the original string if it has mismatched quotes', () => { + const input = '"hello'; + const result = removeQuotesIfExist(input); + expect(result).toBe('"hello'); + }); + + it('removes quotes for strings with special characters inside quotes', () => { + const input = '"hello, world!"'; + const result = removeQuotesIfExist(input); + expect(result).toBe('hello, world!'); + }); + + it('removes quotes for strings with spaces inside quotes', () => { + const input = '" "'; + const result = removeQuotesIfExist(input); + expect(result).toBe(' '); + }); + + it('returns the original string for an empty string', () => { + const input = ''; + const result = removeQuotesIfExist(input); + expect(result).toBe(''); + }); + + it('returns the original string if the string only has a single quote character', () => { + const input = '"'; + const result = removeQuotesIfExist(input); + expect(result).toBe('"'); + }); + + it('handles strings with nested quotes correctly', () => { + const input = '"nested \"quotes\""'; + const result = removeQuotesIfExist(input); + expect(result).toBe('nested \"quotes\"'); + }); + + it('removes quotes from a numeric string wrapped in quotes', () => { + const input = '"12345"'; + const result = removeQuotesIfExist(input); + expect(result).toBe('12345'); + }); +}); diff --git a/packages/grafana-prometheus/src/language_provider.ts b/packages/grafana-prometheus/src/language_provider.ts index 105c354dcae..749c579296e 100644 --- a/packages/grafana-prometheus/src/language_provider.ts +++ b/packages/grafana-prometheus/src/language_provider.ts @@ -29,6 +29,7 @@ import { import PromqlSyntax from './promql'; import { buildVisualQueryFromString } from './querybuilder/parsing'; import { PrometheusCacheLevel, PromMetricsMetadata, PromQuery } from './types'; +import { escapeForUtf8Support, isValidLegacyName } from './utf8_support'; const DEFAULT_KEYS = ['job', 'instance']; const EMPTY_SELECTOR = '{}'; @@ -208,7 +209,8 @@ export default class PromQlLanguageProvider extends LanguageProvider { fetchLabelValues = async (key: string): Promise => { const params = this.datasource.getAdjustedInterval(this.timeRange); const interpolatedName = this.datasource.interpolateString(key); - const url = `/api/v1/label/${interpolatedName}/values`; + const interpolatedAndEscapedName = escapeForUtf8Support(removeQuotesIfExist(interpolatedName)); + const url = `/api/v1/label/${interpolatedAndEscapedName}/values`; const value = await this.request(url, [], params, this.getDefaultCacheHeaders()); return value ?? []; }; @@ -232,10 +234,11 @@ export default class PromQlLanguageProvider extends LanguageProvider { queries?.forEach((q) => { const visualQuery = buildVisualQueryFromString(q.expr); if (visualQuery.query.metric !== '') { - searchParams.append('match[]', visualQuery.query.metric); + const isUtf8Metric = !isValidLegacyName(visualQuery.query.metric); + searchParams.append('match[]', isUtf8Metric ? `{"${visualQuery.query.metric}"}` : visualQuery.query.metric); if (visualQuery.query.binaryQueries) { visualQuery.query.binaryQueries.forEach((bq) => { - searchParams.append('match[]', bq.query.metric); + searchParams.append('match[]', isUtf8Metric ? `{"${bq.query.metric}"}` : bq.query.metric); }); } } @@ -263,7 +266,7 @@ export default class PromQlLanguageProvider extends LanguageProvider { getSeriesValues = async (labelName: string, selector: string): Promise => { if (!this.datasource.hasLabelsMatchAPISupport()) { const data = await this.getSeries(selector); - return data[labelName] ?? []; + return data[removeQuotesIfExist(labelName)] ?? []; } return await this.fetchSeriesValuesWithMatch(labelName, selector); }; @@ -297,7 +300,14 @@ export default class PromQlLanguageProvider extends LanguageProvider { requestOptions = undefined; } - const value = await this.request(`/api/v1/label/${interpolatedName}/values`, [], urlParams, requestOptions); + const interpolatedAndEscapedName = escapeForUtf8Support(removeQuotesIfExist(interpolatedName ?? '')); + + const value = await this.request( + `/api/v1/label/${interpolatedAndEscapedName}/values`, + [], + urlParams, + requestOptions + ); return value ?? []; }; @@ -493,3 +503,10 @@ function isCancelledError(error: unknown): error is { } { return typeof error === 'object' && error !== null && 'cancelled' in error && error.cancelled === true; } + +// For utf8 labels we use quotes around the label +// While requesting the label values we must remove the quotes +export function removeQuotesIfExist(input: string): string { + const match = input.match(/^"(.*)"$/); // extract the content inside the quotes + return match?.[1] ?? input; +} diff --git a/packages/grafana-prometheus/src/language_utils.test.ts b/packages/grafana-prometheus/src/language_utils.test.ts index a0ac8fcb808..6c536879fc6 100644 --- a/packages/grafana-prometheus/src/language_utils.test.ts +++ b/packages/grafana-prometheus/src/language_utils.test.ts @@ -11,6 +11,7 @@ import { getPrometheusTime, getRangeSnapInterval, parseSelector, + processLabels, toPromLikeQuery, truncateResult, } from './language_utils'; @@ -565,3 +566,54 @@ describe('truncateResult', () => { expect(array[999]).toBe(999); }); }); + +describe('processLabels', () => { + it('export abstract query to expr', () => { + const labels: Array<{ [key: string]: string }> = [ + { label1: 'value1' }, + { label2: 'value2' }, + { label3: 'value3' }, + { label1: 'value1' }, + { label1: 'value1b' }, + ]; + + expect(processLabels(labels)).toEqual({ + keys: ['label1', 'label2', 'label3'], + values: { label1: ['value1', 'value1b'], label2: ['value2'], label3: ['value3'] }, + }); + }); + + it('dont wrap utf8 label values with quotes', () => { + const labels: Array<{ [key: string]: string }> = [ + { label1: 'value1' }, + { label2: 'value2' }, + { label3: 'value3 with space' }, + { label4: 'value4.with.dot' }, + ]; + + expect(processLabels(labels)).toEqual({ + keys: ['label1', 'label2', 'label3', 'label4'], + values: { + label1: ['value1'], + label2: ['value2'], + label3: [`value3 with space`], + label4: [`value4.with.dot`], + }, + }); + }); + + it('dont wrap utf8 labels with quotes', () => { + const labels: Array<{ [key: string]: string }> = [ + { 'label1 with space': 'value1' }, + { 'label2.with.dot': 'value2' }, + ]; + + expect(processLabels(labels)).toEqual({ + keys: ['label1 with space', 'label2.with.dot'], + values: { + 'label1 with space': ['value1'], + 'label2.with.dot': ['value2'], + }, + }); + }); +}); diff --git a/packages/grafana-prometheus/src/language_utils.ts b/packages/grafana-prometheus/src/language_utils.ts index 61d48edef1a..69e1a2ccad8 100644 --- a/packages/grafana-prometheus/src/language_utils.ts +++ b/packages/grafana-prometheus/src/language_utils.ts @@ -478,7 +478,10 @@ export function extractLabelMatchers(tokens: Array): AbstractLab export function getRangeSnapInterval( cacheLevel: PrometheusCacheLevel, range: TimeRange -): { start: string; end: string } { +): { + start: string; + end: string; +} { // Don't round the range if we're not caching if (cacheLevel === PrometheusCacheLevel.None) { return { diff --git a/packages/grafana-prometheus/src/utf8_support.test.ts b/packages/grafana-prometheus/src/utf8_support.test.ts new file mode 100644 index 00000000000..0c62733bddf --- /dev/null +++ b/packages/grafana-prometheus/src/utf8_support.test.ts @@ -0,0 +1,35 @@ +import { escapeForUtf8Support, utf8Support } from './utf8_support'; + +describe('utf8 support', () => { + it('should return utf8 labels wrapped in quotes', () => { + const labels = ['valid:label', 'metric_label', 'utf8 label with space 🤘', '']; + const expected = ['valid:label', 'metric_label', `"utf8 label with space 🤘"`, '']; + const supportedLabels = labels.map(utf8Support); + expect(supportedLabels).toEqual(expected); + }); +}); + +describe('applyValueEncodingEscaping', () => { + it('should return utf8 labels wrapped in quotes', () => { + const labels = [ + 'no:escaping_required', + 'mysystem.prod.west.cpu.load', + 'mysystem.prod.west.cpu.load_total', + 'http.status:sum', + 'my lovely_http.status:sum', + '花火', + 'label with 😱', + ]; + const expected = [ + 'no:escaping_required', + 'U__mysystem_2e_prod_2e_west_2e_cpu_2e_load', + 'U__mysystem_2e_prod_2e_west_2e_cpu_2e_load__total', + 'U__http_2e_status:sum', + 'U__my_20_lovely__http_2e_status:sum', + 'U___82b1__706b_', + 'U__label_20_with_20__1f631_', + ]; + const excapedLabels = labels.map(escapeForUtf8Support); + expect(excapedLabels).toEqual(expected); + }); +}); diff --git a/packages/grafana-prometheus/src/utf8_support.ts b/packages/grafana-prometheus/src/utf8_support.ts new file mode 100644 index 00000000000..386d41ba987 --- /dev/null +++ b/packages/grafana-prometheus/src/utf8_support.ts @@ -0,0 +1,81 @@ +export const utf8Support = (value: string) => { + if (value === '') { + return value; + } + const isLegacyLabel = isValidLegacyName(value); + if (isLegacyLabel) { + return value; + } + return `"${value}"`; +}; + +export const escapeForUtf8Support = (value: string) => { + const isLegacyLabel = isValidLegacyName(value); + if (isLegacyLabel) { + return value; + } + + let escaped = 'U__'; + + for (let i = 0; i < value.length; i++) { + const char = value[i]; + const codePoint = value.codePointAt(i); + + if (char === '_') { + escaped += '__'; + } else if (codePoint !== undefined && isValidLegacyRune(char, i)) { + escaped += char; + } else if (codePoint === undefined || !isValidCodePoint(codePoint)) { + escaped += '_FFFD_'; + } else { + escaped += '_'; + escaped += codePoint.toString(16); // Convert code point to hexadecimal + escaped += '_'; + } + + // Handle surrogate pairs for characters outside the Basic Multilingual Plane + if (codePoint !== undefined && codePoint > 0xffff) { + i++; // Skip the second half of the surrogate pair + } + } + + return escaped; +}; + +export const isValidLegacyName = (name: string): boolean => { + if (name.length === 0) { + return false; + } + + for (let i = 0; i < name.length; i++) { + const char = name[i]; + if (!isValidLegacyRune(char, i)) { + return false; + } + } + + return true; +}; + +// const labelNamePriorToUtf8Support = /^[a-zA-Z_:][a-zA-Z0-9_:]*$/; +// instead of regex we use rune check (converted from prometheus code) +// https://github.com/prometheus/common/blob/main/model/metric.go#L426-L428 +const isValidLegacyRune = (char: string, index: number): boolean => { + const codePoint = char.codePointAt(0); + if (codePoint === undefined) { + return false; + } + + return ( + (codePoint >= 97 && codePoint <= 122) || // 'a' to 'z' + (codePoint >= 65 && codePoint <= 90) || // 'A' to 'Z' + codePoint === 95 || // '_' + codePoint === 58 || // ':' + (codePoint >= 48 && codePoint <= 57 && index > 0) // '0' to '9', but not at the start + ); +}; + +const isValidCodePoint = (codePoint: number): boolean => { + // Validate the code point for UTF-8 compliance if needed. + return codePoint >= 0 && codePoint <= 0x10ffff; +}; From 31deddafb6f8aff13ccf2d4f909fac4c37ad32f1 Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Thu, 16 Jan 2025 15:24:56 +0100 Subject: [PATCH 06/30] Prometheus: Support utf8 labels and metrics on visual query builder (#98274) * utf8 metrics for prometheus devenv * introduce utf8 support * completions and suggestions * don't wrap the utf8 label in quotes * linting * support utf8 labels and metrics on visual query builder * lint * update raw view for utf8 metric syntax * betterer * support series endpoint * support series endpoint * betterer --- .betterer.results | 4 +- .../src/add_label_to_query.test.ts | 20 ++++ .../querybuilder/PromQueryModeller.test.ts | 79 +++++++++++++++ .../src/querybuilder/parsing.test.ts | 99 +++++++++++++++++++ .../src/querybuilder/parsing.ts | 38 ++++++- .../shared/LokiAndPromQueryModellerBase.ts | 19 +++- .../PrometheusListView/RawListItem.tsx | 20 +++- 7 files changed, 267 insertions(+), 12 deletions(-) diff --git a/.betterer.results b/.betterer.results index 8c565ab008f..fc658ccf0c8 100644 --- a/.betterer.results +++ b/.betterer.results @@ -4799,7 +4799,9 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] ], "public/app/features/explore/PrometheusListView/RawListItem.tsx:5381": [ - [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"] + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "1"], + [0, 0, 0, "No untranslated strings. Wrap text with ", "2"] ], "public/app/features/explore/PrometheusListView/RawListItemAttributes.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], diff --git a/packages/grafana-prometheus/src/add_label_to_query.test.ts b/packages/grafana-prometheus/src/add_label_to_query.test.ts index 0936da9f726..a57f9294938 100644 --- a/packages/grafana-prometheus/src/add_label_to_query.test.ts +++ b/packages/grafana-prometheus/src/add_label_to_query.test.ts @@ -112,4 +112,24 @@ describe('addLabelToQuery()', () => { it('should not add ad-hoc filter bool operator', () => { expect(addLabelToQuery('ALERTS < bool 1', 'bar', 'baz')).toBe('ALERTS{bar="baz"} < bool 1'); }); + + it('should add a utf8 label', () => { + expect(addLabelToQuery('{"metric.name"}', 'cenk.erdem', 'muhabbet')).toBe( + '{"metric.name", "cenk.erdem"="muhabbet"}' + ); + + expect(addLabelToQuery('metric{label="val"}', 'cenk.erdem', 'muhabbet')).toBe( + 'metric{label="val", "cenk.erdem"="muhabbet"}' + ); + }); + + it('should not add a utf8 label when it is already applied', () => { + expect(addLabelToQuery('{"metric.name", "cenk.erdem"="muhabbet"}', 'cenk.erdem', 'muhabbet')).toBe( + '{"metric.name", "cenk.erdem"="muhabbet"}' + ); + + expect(addLabelToQuery('metric{label="val", "cenk.erdem"="muhabbet"}', 'cenk.erdem', 'muhabbet')).toBe( + 'metric{label="val", "cenk.erdem"="muhabbet"}' + ); + }); }); diff --git a/packages/grafana-prometheus/src/querybuilder/PromQueryModeller.test.ts b/packages/grafana-prometheus/src/querybuilder/PromQueryModeller.test.ts index 9dd51170263..0461458d612 100644 --- a/packages/grafana-prometheus/src/querybuilder/PromQueryModeller.test.ts +++ b/packages/grafana-prometheus/src/querybuilder/PromQueryModeller.test.ts @@ -334,3 +334,82 @@ describe('PromQueryModeller', () => { ).toBe('cluster_namespace_slug_dialer_name <= bool 2'); }); }); + +describe('PromQueryModeller with utf8 support', () => { + const modeller = new PromQueryModeller(); + + it('should render nothing if there is nothing', () => { + expect( + modeller.renderQuery({ + metric: undefined, + labels: [], + operations: [], + }) + ).toBe(''); + + expect( + modeller.renderQuery({ + metric: '', + labels: [], + operations: [], + }) + ).toBe(''); + }); + + it('should render legacy metric name as usual', () => { + expect( + modeller.renderQuery({ + metric: 'not_a_utf8_metric', + labels: [], + operations: [], + }) + ).toBe('not_a_utf8_metric'); + }); + + it('can render utf8 metric name in curly braces', () => { + expect( + modeller.renderQuery({ + metric: 'a.utf8.metric', + labels: [], + operations: [], + }) + ).toBe('{"a.utf8.metric"}'); + }); + + it('can render utf8 metric name in curly braces with legacy labels', () => { + expect( + modeller.renderQuery({ + metric: 'a.utf8.metric', + labels: [ + { + label: 'label', + value: 'value', + op: '=', + }, + ], + operations: [], + }) + ).toBe('{"a.utf8.metric", label="value"}'); + }); + + it('can render utf8 metric name in curly braces with legacy and utf8 labels', () => { + expect( + modeller.renderQuery({ + metric: 'a.utf8.metric', + labels: [ + { + label: 'label', + value: 'value', + op: '=', + }, + { + label: 'utf8.label', + value: 'value', + op: '=', + }, + ], + operations: [], + }) + ).toBe('{"a.utf8.metric", label="value", "utf8.label"="value"}'); + }); +}); diff --git a/packages/grafana-prometheus/src/querybuilder/parsing.test.ts b/packages/grafana-prometheus/src/querybuilder/parsing.test.ts index ce2aaede3ac..0ed20246890 100644 --- a/packages/grafana-prometheus/src/querybuilder/parsing.test.ts +++ b/packages/grafana-prometheus/src/querybuilder/parsing.test.ts @@ -3,6 +3,80 @@ import { buildVisualQueryFromString } from './parsing'; import { PromOperationId, PromVisualQuery } from './types'; describe('buildVisualQueryFromString', () => { + describe('utf8 support', () => { + it('supports uts-8 label names', () => { + expect(buildVisualQueryFromString('{"glück:🍀.dot"="luck"} == 11')).toEqual({ + query: { + labels: [ + { + label: 'glück:🍀.dot', + op: '=', + value: 'luck', + }, + ], + metric: '', + operations: [ + { + id: PromOperationId.EqualTo, + params: [11, false], + }, + ], + }, + errors: [], + }); + }); + + it('supports uts-8 metric names', () => { + expect(buildVisualQueryFromString('{"I am a metric"}')).toEqual({ + query: { + labels: [], + metric: 'I am a metric', + operations: [], + }, + errors: [], + }); + }); + + it('supports uts-8 metric names with labels', () => { + expect(buildVisualQueryFromString('{"metric.name", label_field="label value"}')).toEqual({ + query: { + labels: [ + { + label: 'label_field', + op: '=', + value: 'label value', + }, + ], + metric: 'metric.name', + operations: [], + }, + errors: [], + }); + }); + + it('supports uts-8 metric names with utf8 labels', () => { + expect(buildVisualQueryFromString('{"metric.name", "glück:🍀.dot"="luck"} == 11')).toEqual({ + query: { + labels: [ + { + label: 'glück:🍀.dot', + op: '=', + value: 'luck', + }, + ], + metric: 'metric.name', + operations: [ + { + id: PromOperationId.EqualTo, + params: [11, false], + }, + ], + }, + errors: [], + }); + }); + }); + it('creates no errors for empty query', () => { expect(buildVisualQueryFromString('')).toEqual( noErrors({ @@ -246,6 +320,31 @@ describe('buildVisualQueryFromString', () => { ); }); + it('parses query with aggregation by utf8 labels', () => { + const visQuery = { + metric: 'metric_name', + labels: [ + { + label: 'instance', + op: '=', + value: 'internal:3000', + }, + ], + operations: [ + { + id: '__sum_by', + params: ['cluster', '"app.version"'], + }, + ], + }; + expect( + buildVisualQueryFromString('sum(metric_name{instance="internal:3000"}) by ("app.version", cluster)') + ).toEqual(noErrors(visQuery)); + expect( + buildVisualQueryFromString('sum by ("app.version", cluster)(metric_name{instance="internal:3000"})') + ).toEqual(noErrors(visQuery)); + }); + it('parses aggregation with params', () => { expect(buildVisualQueryFromString('topk(5, http_requests_total)')).toEqual( noErrors({ diff --git a/packages/grafana-prometheus/src/querybuilder/parsing.ts b/packages/grafana-prometheus/src/querybuilder/parsing.ts index 3e81d154d0e..a282990da83 100644 --- a/packages/grafana-prometheus/src/querybuilder/parsing.ts +++ b/packages/grafana-prometheus/src/querybuilder/parsing.ts @@ -12,6 +12,7 @@ import { GroupingLabels, Identifier, LabelName, + QuotedLabelName, MatchingModifierClause, MatchOp, NumberDurationLiteral, @@ -19,6 +20,7 @@ import { ParenExpr, parser, StringLiteral, + QuotedLabelMatcher, UnquotedLabelMatcher, VectorSelector, Without, @@ -145,9 +147,33 @@ export function handleExpression(expr: string, node: SyntaxNode, context: Contex break; } + case QuotedLabelName: { + // Usually we got the metric name above in the Identifier case. + // If we didn't get the name that's potentially we have it in curly braces as quoted string. + // It must be quoted because that's how utf8 metric names should be defined + // See proposal https://github.com/prometheus/proposals/blob/main/proposals/2023-08-21-utf8.md + if (visQuery.metric === '') { + const strLiteral = node.getChild(StringLiteral); + const quotedMetric = getString(expr, strLiteral); + visQuery.metric = quotedMetric.slice(1, -1); + } + break; + } + + case QuotedLabelMatcher: { + const quotedLabel = getLabel(expr, node, QuotedLabelName); + quotedLabel.label = quotedLabel.label.slice(1, -1); + visQuery.labels.push(quotedLabel); + const err = node.getChild(ErrorId); + if (err) { + context.errors.push(makeError(expr, err)); + } + break; + } + case UnquotedLabelMatcher: { // Same as MetricIdentifier should be just one per query. - visQuery.labels.push(getLabel(expr, node)); + visQuery.labels.push(getLabel(expr, node, LabelName)); const err = node.getChild(ErrorId); if (err) { context.errors.push(makeError(expr, err)); @@ -202,8 +228,12 @@ function isIntervalVariableError(node: SyntaxNode) { return node.prevSibling?.firstChild?.type.id === VectorSelector; } -function getLabel(expr: string, node: SyntaxNode): QueryBuilderLabelFilter { - const label = getString(expr, node.getChild(LabelName)); +function getLabel( + expr: string, + node: SyntaxNode, + labelType: typeof LabelName | typeof QuotedLabelName +): QueryBuilderLabelFilter { + const label = getString(expr, node.getChild(labelType)); const op = getString(expr, node.getChild(MatchOp)); const value = getString(expr, node.getChild(StringLiteral)).replace(/^["'`]|["'`]$/g, ''); return { @@ -281,7 +311,7 @@ function handleAggregation(expr: string, node: SyntaxNode, context: Context) { funcName = `__${funcName}_without`; } - labels.push(...getAllByType(expr, modifier, LabelName)); + labels.push(...getAllByType(expr, modifier, LabelName), ...getAllByType(expr, modifier, QuotedLabelName)); } const body = node.getChild(FunctionCallBody); diff --git a/packages/grafana-prometheus/src/querybuilder/shared/LokiAndPromQueryModellerBase.ts b/packages/grafana-prometheus/src/querybuilder/shared/LokiAndPromQueryModellerBase.ts index 1d06ed7edac..2300e221dfc 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/LokiAndPromQueryModellerBase.ts +++ b/packages/grafana-prometheus/src/querybuilder/shared/LokiAndPromQueryModellerBase.ts @@ -3,6 +3,7 @@ import { Registry } from '@grafana/data'; import { config } from '@grafana/runtime'; import { prometheusRegularEscape } from '../../datasource'; +import { isValidLegacyName, utf8Support } from '../../utf8_support'; import { PromVisualQueryOperationCategory } from '../types'; import { QueryBuilderLabelFilter, QueryBuilderOperation, QueryBuilderOperationDef, VisualQueryModeller } from './types'; @@ -97,14 +98,28 @@ export abstract class LokiAndPromQueryModellerBase implements VisualQueryModelle if (config.featureToggles.prometheusSpecialCharsInLabelValues && !usingRegexOperator) { labelValue = prometheusRegularEscape(labelValue); } - expr += `${filter.label}${filter.op}"${labelValue}"`; + expr += `${utf8Support(filter.label)}${filter.op}"${labelValue}"`; } return expr + `}`; } renderQuery(query: PromLokiVisualQuery, nested?: boolean) { - let queryString = `${query.metric ?? ''}${this.renderLabels(query.labels)}`; + let queryString = ''; + const labels = this.renderLabels(query.labels); + if (query.metric) { + if (isValidLegacyName(query.metric)) { + // This is a legacy metric, put outside the curl legacy_query{label="value"} + queryString = `${query.metric}${labels}`; + } else { + // This is a utf8 metric, put inside the curly and quotes {"utf8.metric", label="value"} + queryString = `{"${query.metric}"${labels.length > 0 ? `, ${labels.substring(1)}` : `}`}`; + } + } else { + // No metric just use labels {label="value"} + queryString = labels; + } + queryString = this.renderOperations(queryString, query.operations); if (!nested && this.hasBinaryOp(query) && Boolean(query.binaryQueries?.length)) { diff --git a/public/app/features/explore/PrometheusListView/RawListItem.tsx b/public/app/features/explore/PrometheusListView/RawListItem.tsx index 465cf895565..19945763aba 100644 --- a/public/app/features/explore/PrometheusListView/RawListItem.tsx +++ b/public/app/features/explore/PrometheusListView/RawListItem.tsx @@ -2,6 +2,7 @@ import { css } from '@emotion/css'; import { useCopyToClipboard } from 'react-use'; import { Field, GrafanaTheme2 } from '@grafana/data/'; +import { isValidLegacyName, utf8Support } from '@grafana/prometheus/src/utf8_support'; import { reportInteraction } from '@grafana/runtime/src'; import { IconButton, useStyles2 } from '@grafana/ui/'; @@ -94,6 +95,8 @@ function getQueryValues(allLabels: Pick { const { __name__, ...allLabels } = listItemData; + // We must know whether it is a utf8 metric name or not + const isLegacyMetric = isValidLegacyName(__name__); const [_, copyToClipboard] = useCopyToClipboard(); const displayLength = valueLabels?.length ?? totalNumberOfValues; const styles = useStyles2(getStyles, displayLength, isExpandedView); @@ -110,10 +113,12 @@ const RawListItem = ({ listItemData, listKey, totalNumberOfValues, valueLabels, }; // Convert the object back into a string - const stringRep = `${__name__}{${attributeValues.map((value) => { - // For histograms the string representation currently in this object is not directly queryable in all situations, leading to broken copied queries. Omitting the attribute from the copied result gives a query which returns all le values, which I assume to be a more common use case. - return `${value.key}="${transformCopyValue(value.value)}"`; - })}}`; + const stringRep = `${isLegacyMetric ? __name__ : ''}{${isLegacyMetric ? '' : `"${__name__}", `}${attributeValues.map( + (value) => { + // For histograms the string representation currently in this object is not directly queryable in all situations, leading to broken copied queries. Omitting the attribute from the copied result gives a query which returns all le values, which I assume to be a more common use case. + return `${utf8Support(value.key)}="${transformCopyValue(value.value)}"`; + } + )}}`; const hideFieldsWithoutValues = Boolean(valueLabels && valueLabels?.length); @@ -135,8 +140,13 @@ const RawListItem = ({ listItemData, listKey, totalNumberOfValues, valueLabels,
- {__name__} + {isLegacyMetric && {__name__}} {`{`} + {!isLegacyMetric && __name__ !== '' && ( + + "{__name__}"{', '} + + )} {attributeValues.map((value, index) => ( Date: Thu, 16 Jan 2025 17:41:52 +0300 Subject: [PATCH 07/30] K8s/Client: Add watch support (#99060) * add watch client * add watch client * add support for selectors * parse labels * always send watch * reuse decoder * Update public/app/features/apiserver/client.ts Co-authored-by: Alex Khomenko * Update public/app/features/apiserver/client.ts Co-authored-by: Alex Khomenko * Update public/app/features/apiserver/client.ts Co-authored-by: Alex Khomenko --------- Co-authored-by: Alex Khomenko --- public/app/core/services/backend_srv.ts | 9 +++--- public/app/features/apiserver/client.ts | 42 +++++++++++++++++++++++++ public/app/features/apiserver/types.ts | 27 ++++++++++++++++ 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/public/app/core/services/backend_srv.ts b/public/app/core/services/backend_srv.ts index ce7dab8c838..cc667ac6c56 100644 --- a/public/app/core/services/backend_srv.ts +++ b/public/app/core/services/backend_srv.ts @@ -198,13 +198,14 @@ export class BackendSrv implements BackendService { } } process() - .catch((e) => { - console.log(requestId, 'catch', e); - }) // from abort .then(() => { console.log(requestId, 'complete'); observer.complete(); - }); // runs in background + }) // runs in background + .catch((e) => { + console.log(requestId, 'catch', e); + observer.error(e); + }); // from abort }, error: (e) => { observer.error(e); diff --git a/public/app/features/apiserver/client.ts b/public/app/features/apiserver/client.ts index 8ac5b531095..ba647d4cf6c 100644 --- a/public/app/features/apiserver/client.ts +++ b/public/app/features/apiserver/client.ts @@ -1,3 +1,5 @@ +import { Observable, from, retry, catchError, filter, map, mergeMap } from 'rxjs'; + import { config, getBackendSrv } from '@grafana/runtime'; import { contextSrv } from 'app/core/core'; @@ -11,8 +13,10 @@ import { ResourceList, ResourceClient, ObjectMeta, + WatchOptions, K8sAPIGroupList, AnnoKeySavedFromUI, + ResourceEvent, } from './types'; export interface GroupVersionResource { @@ -34,6 +38,44 @@ export class ScopedResourceClient implements return getBackendSrv().get>(`${this.url}/${name}`); } + public watch(opts?: WatchOptions): Observable> { + const decoder = new TextDecoder(); + const params = { + ...opts, + watch: true, + labelSelector: this.parseListOptionsSelector(opts?.labelSelector), + fieldSelector: this.parseListOptionsSelector(opts?.fieldSelector), + }; + return getBackendSrv() + .chunked({ + url: params.name ? `${this.url}/${params.name}` : this.url, + params, + }) + .pipe( + filter((response) => response.ok && response.data instanceof Uint8Array), + map((response) => { + const text = decoder.decode(response.data); + return text.split('\n'); + }), + mergeMap((text) => from(text)), + filter((line) => line.length > 0), + map((line) => { + try { + return JSON.parse(line); + } catch (e) { + console.warn('Invalid JSON in watch stream:', e); + return null; + } + }), + filter((event): event is ResourceEvent => event !== null), + retry({ count: 3, delay: 1000 }), + catchError((error) => { + console.error('Watch stream error:', error); + throw error; + }) + ); + } + public async subresource(name: string, path: string): Promise { return getBackendSrv().get(`${this.url}/${name}/${path}`); } diff --git a/public/app/features/apiserver/types.ts b/public/app/features/apiserver/types.ts index 054aa62d810..c6d142f4019 100644 --- a/public/app/features/apiserver/types.ts +++ b/public/app/features/apiserver/types.ts @@ -8,6 +8,8 @@ * */ +import { Observable } from 'rxjs'; + /** The object type and version */ export interface TypeMeta { apiVersion: string; @@ -152,6 +154,25 @@ export interface ListOptions { // Limit the response count limit?: number; + + // Watch for changes + watch?: boolean; +} + +export interface WatchOptions { + // A specific resource + name?: string; + + // Start watching from a given resource version + resourceVersion?: string; + + // Query by labels + // https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + labelSelector?: ListOptionsLabelSelector; + + // Query by fields + // https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/ + fieldSelector?: ListOptionsFieldSelector; } export interface MetaStatus { @@ -171,9 +192,15 @@ export interface MetaStatus { details?: object; } +export interface ResourceEvent { + type: 'ADDED' | 'DELETED' | 'MODIFIED'; + object: Resource; +} + export interface ResourceClient { create(obj: ResourceForCreate): Promise>; get(name: string): Promise>; + watch(opts?: WatchOptions): Observable>; subresource(name: string, path: string): Promise; list(opts?: ListOptions): Promise>; update(obj: ResourceForCreate): Promise>; From 3df1fa86ae1dfa02e7acd5848f861b8d4379d12e Mon Sep 17 00:00:00 2001 From: Sergej-Vlasov <37613182+Sergej-Vlasov@users.noreply.github.com> Date: Thu, 16 Jan 2025 14:43:46 +0000 Subject: [PATCH 08/30] setDashboardPanelContext: Allow to add filters from the table with the same key (#99004) * always add filters for elastic seach ds when filtering table value * simplify update filter logic and restore behaviour from old arch * remove unnecessary modifications * adjust namig --- .../scene/setDashboardPanelContext.test.ts | 13 +++++--- .../scene/setDashboardPanelContext.ts | 32 +++++++++---------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/public/app/features/dashboard-scene/scene/setDashboardPanelContext.test.ts b/public/app/features/dashboard-scene/scene/setDashboardPanelContext.test.ts index 36eb42d3a05..d246ddcccd4 100644 --- a/public/app/features/dashboard-scene/scene/setDashboardPanelContext.test.ts +++ b/public/app/features/dashboard-scene/scene/setDashboardPanelContext.test.ts @@ -130,11 +130,16 @@ describe('setDashboardPanelContext', () => { it('Should add new filter set', () => { const { scene, context } = buildTestScene({}); - context.onAddAdHocFilter!({ key: 'hello', value: 'world', operator: '=' }); + context.onAddAdHocFilter!({ key: 'hello', value: 'world', operator: '!=' }); + context.onAddAdHocFilter!({ key: 'hello', value: 'world2', operator: '!=' }); const variable = getAdHocFilterVariableFor(scene, { uid: 'my-ds-uid' }); - expect(variable.state.filters).toEqual([{ key: 'hello', value: 'world', operator: '=' }]); + expect(variable.state.filters).toEqual([ + { key: 'hello', value: 'world', operator: '!=' }, + { key: 'hello', value: 'world2', operator: '!=' }, + , + ]); }); it('Should update and add filter to existing set', () => { @@ -149,9 +154,9 @@ describe('setDashboardPanelContext', () => { expect(variable.state.filters.length).toBe(2); // Can update existing filter value without adding a new filter - context.onAddAdHocFilter!({ key: 'hello', value: 'world2', operator: '=' }); + context.onAddAdHocFilter!({ key: 'hello', value: 'world', operator: '!=' }); // Verify existing filter value updated - expect(variable.state.filters[1].value).toBe('world2'); + expect(variable.state.filters[1].operator).toBe('!='); }); }); }); diff --git a/public/app/features/dashboard-scene/scene/setDashboardPanelContext.ts b/public/app/features/dashboard-scene/scene/setDashboardPanelContext.ts index 00150b02a0a..4b141354801 100644 --- a/public/app/features/dashboard-scene/scene/setDashboardPanelContext.ts +++ b/public/app/features/dashboard-scene/scene/setDashboardPanelContext.ts @@ -175,23 +175,23 @@ export function getAdHocFilterVariableFor(scene: DashboardScene, ds: DataSourceR } function updateAdHocFilterVariable(filterVar: AdHocFiltersVariable, newFilter: AdHocFilterItem) { - // Check if we need to update an existing filter - for (const filter of filterVar.state.filters) { - if (filter.key === newFilter.key) { - filterVar.setState({ - filters: filterVar.state.filters.map((f) => { - if (f.key === newFilter.key) { - return newFilter; - } - return f; - }), - }); - return; - } + // This function handles 'Filter for value' and 'Filter out value' from table cell + // We are allowing to add filters with the same key because elastic search ds supports that + + // Update is only required when we change operator and keep key and value the same + // key1 = value1 -> key1 != value1 + const filterToReplaceIndex = filterVar.state.filters.findIndex( + (filter) => + filter.key === newFilter.key && filter.value === newFilter.value && filter.operator !== newFilter.operator + ); + + if (filterToReplaceIndex >= 0) { + const updatedFilters = filterVar.state.filters.slice(); + updatedFilters.splice(filterToReplaceIndex, 1, newFilter); + filterVar.updateFilters(updatedFilters); + return; } // Add new filter - filterVar.setState({ - filters: [...filterVar.state.filters, newFilter], - }); + filterVar.updateFilters([...filterVar.state.filters, newFilter]); } From a32eed1d1354c183a0cb60f33db002d943ecf003 Mon Sep 17 00:00:00 2001 From: Sergej-Vlasov <37613182+Sergej-Vlasov@users.noreply.github.com> Date: Thu, 16 Jan 2025 14:45:23 +0000 Subject: [PATCH 09/30] TransformationFilter: Include transformation outputs in transformation filtering options (#98323) * wip: include transformation output as filtering option * add refId to joinByField transformation * clean up * add refId to transformations that create new data frames * adjust duplicate query removal for filtering options * refactor transformation input/output subscription effect * adjust input data frame filtering logic to include transformations as input for debug view * transformation filter can only filter on output of previous transformation --- .../transformers/ensureColumns.test.ts | 6 +- .../transformations/transformers/histogram.ts | 1 + .../transformers/joinByField.ts | 1 + .../src/transformations/transformers/merge.ts | 5 +- .../transformations/transformers/reduce.ts | 4 +- .../transformers/seriesToRows.ts | 5 +- .../transformations/transformers/transpose.ts | 1 + .../TransformationEditor.tsx | 48 ++---------- .../TransformationFilter.tsx | 25 +++---- .../TransformationOperationRow.tsx | 73 +++++++++++++++++-- .../transformers/joinByLabels/joinByLabels.ts | 8 +- .../rowsToFields/rowsToFields.test.ts | 2 + .../transformers/rowsToFields/rowsToFields.ts | 1 + .../geomap/editor/FrameSelectionEditor.tsx | 4 +- 14 files changed, 113 insertions(+), 71 deletions(-) diff --git a/packages/grafana-data/src/transformations/transformers/ensureColumns.test.ts b/packages/grafana-data/src/transformations/transformers/ensureColumns.test.ts index 0f63477d51b..c46fbf9320f 100644 --- a/packages/grafana-data/src/transformations/transformers/ensureColumns.test.ts +++ b/packages/grafana-data/src/transformations/transformers/ensureColumns.test.ts @@ -42,7 +42,10 @@ describe('ensureColumns transformer', () => { options: {}, }; - const data = [seriesA, seriesBC]; + const data = [ + { refId: 'A', ...seriesA }, + { refId: 'B', ...seriesBC }, + ]; await expect(transformDataFrame([cfg], data)).toEmitValuesWith((received) => { const filtered = received[0]; @@ -109,6 +112,7 @@ describe('ensureColumns transformer', () => { }, ], "length": 2, + "refId": "joinByField-A-B", } `); }); diff --git a/packages/grafana-data/src/transformations/transformers/histogram.ts b/packages/grafana-data/src/transformations/transformers/histogram.ts index 0d5746309b7..6d534d22a4b 100644 --- a/packages/grafana-data/src/transformations/transformers/histogram.ts +++ b/packages/grafana-data/src/transformations/transformers/histogram.ts @@ -592,5 +592,6 @@ export function histogramFieldsToFrame(info: HistogramFields, theme?: GrafanaThe type: DataFrameType.Histogram, }, fields: [info.xMin, info.xMax, ...info.counts], + refId: `${DataTransformerID.histogram}`, }; } diff --git a/packages/grafana-data/src/transformations/transformers/joinByField.ts b/packages/grafana-data/src/transformations/transformers/joinByField.ts index 127cb3a3bd2..371044c0783 100644 --- a/packages/grafana-data/src/transformations/transformers/joinByField.ts +++ b/packages/grafana-data/src/transformations/transformers/joinByField.ts @@ -42,6 +42,7 @@ export const joinByFieldTransformer: SynchronousDataTransformerInfo frame.refId).join('-')}`; return [joined]; } } diff --git a/packages/grafana-data/src/transformations/transformers/merge.ts b/packages/grafana-data/src/transformations/transformers/merge.ts index 6bdd9d94af9..275bfa65840 100644 --- a/packages/grafana-data/src/transformations/transformers/merge.ts +++ b/packages/grafana-data/src/transformations/transformers/merge.ts @@ -43,7 +43,10 @@ export const mergeTransformer: DataTransformerInfo = { const fieldNames = new Set(); const fieldIndexByName: Record> = {}; const fieldNamesForKey: string[] = []; - const dataFrame = new MutableDataFrame(); + const dataFrame = new MutableDataFrame({ + refId: `${DataTransformerID.merge}-${data.map((frame) => frame.refId).join('-')}`, + fields: [], + }); for (let frameIndex = 0; frameIndex < data.length; frameIndex++) { const frame = data[frameIndex]; diff --git a/packages/grafana-data/src/transformations/transformers/reduce.ts b/packages/grafana-data/src/transformations/transformers/reduce.ts index 8a28a35fa11..dba2bc286e0 100644 --- a/packages/grafana-data/src/transformations/transformers/reduce.ts +++ b/packages/grafana-data/src/transformations/transformers/reduce.ts @@ -56,7 +56,9 @@ export const reduceTransformer: DataTransformerInfo = // Add a row for each series const res = reduceSeriesToRows(data, matcher, options.reducers, options.labelsToFields); - return res ? [res] : []; + return res + ? [{ ...res, refId: `${DataTransformerID.reduce}-${data.map((frame) => frame.refId).join('-')}` }] + : []; }) ), }; diff --git a/packages/grafana-data/src/transformations/transformers/seriesToRows.ts b/packages/grafana-data/src/transformations/transformers/seriesToRows.ts index bec6c6939c9..6c7dd055f05 100644 --- a/packages/grafana-data/src/transformations/transformers/seriesToRows.ts +++ b/packages/grafana-data/src/transformations/transformers/seriesToRows.ts @@ -37,7 +37,10 @@ export const seriesToRowsTransformer: DataTransformerInfo = {}; const targetFields = new Set(); - const dataFrame = new MutableDataFrame(); + const dataFrame = new MutableDataFrame({ + refId: `${DataTransformerID.seriesToRows}-${data.map((frame) => frame.refId).join('-')}`, + fields: [], + }); const metricField: Field = { name: TIME_SERIES_METRIC_FIELD_NAME, values: [], diff --git a/packages/grafana-data/src/transformations/transformers/transpose.ts b/packages/grafana-data/src/transformations/transformers/transpose.ts index b4e04c9d316..ae97e8f4ceb 100644 --- a/packages/grafana-data/src/transformations/transformers/transpose.ts +++ b/packages/grafana-data/src/transformations/transformers/transpose.ts @@ -80,6 +80,7 @@ function transposeDataFrame(options: TransposeTransformerOptions, data: DataFram ...frame, fields: newFields, length: Math.max(...newFields.map((field) => field.values.length)), + refId: `${DataTransformerID.transpose}-${frame.refId}`, }; }); } diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationEditor.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationEditor.tsx index 7ac97009d96..af52b70a8f6 100644 --- a/public/app/features/dashboard/components/TransformationsEditor/TransformationEditor.tsx +++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationEditor.tsx @@ -1,26 +1,17 @@ import { css } from '@emotion/css'; -import { createElement, useEffect, useMemo, useState } from 'react'; -import { mergeMap } from 'rxjs/operators'; +import { createElement, useMemo } from 'react'; -import { - DataFrame, - DataTransformerConfig, - GrafanaTheme2, - transformDataFrame, - TransformerRegistryItem, - getFrameMatchers, - DataTransformContext, -} from '@grafana/data'; +import { DataFrame, DataTransformerConfig, GrafanaTheme2, TransformerRegistryItem } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; -import { getTemplateSrv } from '@grafana/runtime'; import { Icon, JSONFormatter, useStyles2, Drawer } from '@grafana/ui'; import { TransformationsEditorTransformation } from './types'; interface TransformationEditorProps { + input: DataFrame[]; + output: DataFrame[]; debugMode?: boolean; index: number; - data: DataFrame[]; uiConfig: TransformerRegistryItem; configs: TransformationsEditorTransformation[]; onChange: (index: number, config: DataTransformerConfig) => void; @@ -28,45 +19,18 @@ interface TransformationEditorProps { } export const TransformationEditor = ({ + input, + output, debugMode, index, - data, uiConfig, configs, onChange, toggleShowDebug, }: TransformationEditorProps) => { const styles = useStyles2(getStyles); - const [input, setInput] = useState([]); - const [output, setOutput] = useState([]); const config = useMemo(() => configs[index], [configs, index]); - useEffect(() => { - const config = configs[index].transformation; - const matcher = config.filter?.options ? getFrameMatchers(config.filter) : undefined; - const inputTransforms = configs.slice(0, index).map((t) => t.transformation); - const outputTransforms = configs.slice(index, index + 1).map((t) => t.transformation); - - const ctx: DataTransformContext = { - interpolate: (v: string) => getTemplateSrv().replace(v), - }; - - const inputSubscription = transformDataFrame(inputTransforms, data, ctx).subscribe((v) => { - if (matcher) { - v = data.filter((v) => matcher(v)); - } - setInput(v); - }); - const outputSubscription = transformDataFrame(inputTransforms, data, ctx) - .pipe(mergeMap((before) => transformDataFrame(outputTransforms, before, ctx))) - .subscribe(setOutput); - - return function unsubscribe() { - inputSubscription.unsubscribe(); - outputSubscription.unsubscribe(); - }; - }, [index, data, configs]); - const editor = useMemo( () => createElement(uiConfig.editor, { diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationFilter.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationFilter.tsx index 893c1fc5770..2c42b7779cb 100644 --- a/public/app/features/dashboard/components/TransformationsEditor/TransformationFilter.tsx +++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationFilter.tsx @@ -1,40 +1,35 @@ import { css } from '@emotion/css'; import { useMemo } from 'react'; -import { - DataTransformerConfig, - GrafanaTheme2, - StandardEditorContext, - StandardEditorsRegistryItem, -} from '@grafana/data'; +import { DataFrame, DataTransformerConfig, GrafanaTheme2 } from '@grafana/data'; import { DataTopic } from '@grafana/schema'; import { Field, Select, useStyles2 } from '@grafana/ui'; import { FrameMultiSelectionEditor } from 'app/plugins/panel/geomap/editor/FrameSelectionEditor'; -import { TransformationData } from './TransformationsEditor'; - interface TransformationFilterProps { + /** data frames from the output of previous transformation */ + data: DataFrame[]; index: number; config: DataTransformerConfig; - data: TransformationData; + annotations?: DataFrame[]; onChange: (index: number, config: DataTransformerConfig) => void; } -export const TransformationFilter = ({ index, data, config, onChange }: TransformationFilterProps) => { +export const TransformationFilter = ({ index, annotations, config, onChange, data }: TransformationFilterProps) => { const styles = useStyles2(getStyles); const opts = useMemo(() => { return { // eslint-disable-next-line - context: { data: data.series } as StandardEditorContext, - showTopic: true || data.annotations?.length || config.topic?.length, + context: { data }, + showTopic: true || annotations?.length || config.topic?.length, showFilter: config.topic !== DataTopic.Annotations, source: [ - { value: DataTopic.Series, label: `Query results` }, + { value: DataTopic.Series, label: `Query and Transformation results` }, { value: DataTopic.Annotations, label: `Annotation data` }, ], }; - }, [data, config.topic]); + }, [data, annotations?.length, config.topic]); return (
@@ -59,8 +54,6 @@ export const TransformationFilter = ({ index, data, config, onChange }: Transfor onChange(index, { ...config, filter })} /> )} diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx index 94b4964fc6a..9b11a3d84d5 100644 --- a/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx +++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx @@ -1,10 +1,18 @@ -import { useCallback } from 'react'; -import * as React from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { useToggle } from 'react-use'; +import { mergeMap } from 'rxjs'; -import { DataTransformerConfig, TransformerRegistryItem, FrameMatcherID, DataTopic } from '@grafana/data'; +import { + DataTransformerConfig, + TransformerRegistryItem, + FrameMatcherID, + DataTransformContext, + getFrameMatchers, + transformDataFrame, + DataFrame, +} from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; -import { reportInteraction } from '@grafana/runtime'; +import { getTemplateSrv, reportInteraction } from '@grafana/runtime'; import { ConfirmModal } from '@grafana/ui'; import { QueryOperationAction, @@ -46,6 +54,10 @@ export const TransformationOperationRow = ({ const topic = configs[index].transformation.topic; const showFilterEditor = configs[index].transformation.filter != null || topic != null; const showFilterToggle = showFilterEditor || data.series.length > 0 || (data.annotations?.length ?? 0) > 0; + const [input, setInput] = useState([]); + const [output, setOutput] = useState([]); + // output of previous transformation + const [prevOutput, setPrevOutput] = useState([]); const onDisableToggle = useCallback( (index: number) => { @@ -92,6 +104,48 @@ export const TransformationOperationRow = ({ [configs, index] ); + useEffect(() => { + const config = configs[index].transformation; + const matcher = config.filter?.options ? getFrameMatchers(config.filter) : undefined; + // we need previous transformation index to get its outputs + // to be used in this transforms inputs + const prevTransformIndex = index - 1; + + let prevInputTransforms: Array> = []; + let prevOutputTransforms: Array> = []; + + if (prevTransformIndex >= 0) { + prevInputTransforms = configs.slice(0, prevTransformIndex).map((t) => t.transformation); + prevOutputTransforms = configs.slice(prevTransformIndex, index).map((t) => t.transformation); + } + + const inputTransforms = configs.slice(0, index).map((t) => t.transformation); + const outputTransforms = configs.slice(index, index + 1).map((t) => t.transformation); + + const ctx: DataTransformContext = { + interpolate: (v: string) => getTemplateSrv().replace(v), + }; + + const inputSubscription = transformDataFrame(inputTransforms, data.series, ctx).subscribe((data) => { + if (matcher) { + data = data.filter((frame) => matcher(frame)); + } + setInput(data); + }); + const outputSubscription = transformDataFrame(inputTransforms, data.series, ctx) + .pipe(mergeMap((before) => transformDataFrame(outputTransforms, before, ctx))) + .subscribe(setOutput); + const prevOutputSubscription = transformDataFrame(prevInputTransforms, data.series, ctx) + .pipe(mergeMap((before) => transformDataFrame(prevOutputTransforms, before, ctx))) + .subscribe(setPrevOutput); + + return function unsubscribe() { + inputSubscription.unsubscribe(); + outputSubscription.unsubscribe(); + prevOutputSubscription.unsubscribe(); + }; + }, [index, data, configs]); + const renderActions = () => { return ( <> @@ -162,13 +216,20 @@ export const TransformationOperationRow = ({ }} > {showFilterEditor && ( - + )} frame.refId).join('-')}`, + }; for (let i = 0; i < join.length; i++) { frame.fields.push({ name: join[i], diff --git a/public/app/features/transformers/rowsToFields/rowsToFields.test.ts b/public/app/features/transformers/rowsToFields/rowsToFields.test.ts index f6e458db2b8..4d3ee3d96d9 100644 --- a/public/app/features/transformers/rowsToFields/rowsToFields.test.ts +++ b/public/app/features/transformers/rowsToFields/rowsToFields.test.ts @@ -12,6 +12,7 @@ describe('Rows to fields', () => { { name: 'Miiin', type: FieldType.number, values: [3, 100] }, { name: 'max', type: FieldType.string, values: [15, 200] }, ], + refId: 'A', }); const result = rowsToFields( @@ -57,6 +58,7 @@ describe('Rows to fields', () => { }, ], "length": 1, + "refId": "rowsToFields-A", } `); }); diff --git a/public/app/features/transformers/rowsToFields/rowsToFields.ts b/public/app/features/transformers/rowsToFields/rowsToFields.ts index 6232f3f5546..7bdece8e98b 100644 --- a/public/app/features/transformers/rowsToFields/rowsToFields.ts +++ b/public/app/features/transformers/rowsToFields/rowsToFields.ts @@ -64,6 +64,7 @@ export function rowsToFields(options: RowToFieldsTransformOptions, data: DataFra return { fields: outFields, length: 1, + refId: `${DataTransformerID.rowsToFields}-${data.refId}`, }; } diff --git a/public/app/plugins/panel/geomap/editor/FrameSelectionEditor.tsx b/public/app/plugins/panel/geomap/editor/FrameSelectionEditor.tsx index 00b245ba035..69f423b8f0d 100644 --- a/public/app/plugins/panel/geomap/editor/FrameSelectionEditor.tsx +++ b/public/app/plugins/panel/geomap/editor/FrameSelectionEditor.tsx @@ -29,7 +29,9 @@ export const FrameSelectionEditor = ({ value, context, onChange }: Props) => { ); }; -export const FrameMultiSelectionEditor = ({ value, context, onChange }: Props) => { +type FrameMultiSelectionEditorProps = Omit, 'item'>; + +export const FrameMultiSelectionEditor = ({ value, context, onChange }: FrameMultiSelectionEditorProps) => { const onFilterChange = useCallback( (v: string[]) => { onChange( From b532df36c459e45badcc47e08186b05d70a685a5 Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Thu, 16 Jan 2025 15:49:06 +0100 Subject: [PATCH 10/30] Explore Metrics: Support prometheus utf8 metrics names and labels (#98285) * utf8 metrics for prometheus devenv * introduce utf8 support * completions and suggestions * don't wrap the utf8 label in quotes * linting * support utf8 labels and metrics on visual query builder * lint * update raw view for utf8 metric syntax * betterer * support utf8 metric names in explore metrics * utf8 support in grouop by * utf8 support in label break down * support series endpoint * support series endpoint * support series endpoint * Explore metrics: Utf8 support in Explore metrics with OTel experience enabled (#98707) * betterer --------- Co-authored-by: Brendan O'Handley --- devenv/docker/blocks/prometheus_utf8/main.go | 15 +++ packages/grafana-prometheus/src/datasource.ts | 17 +++- packages/grafana-prometheus/src/types.ts | 1 + .../src/utf8_support.test.ts | 94 ++++++++++++++++++- .../grafana-prometheus/src/utf8_support.ts | 32 +++++++ .../trails/ActionTabs/MetricOverviewScene.tsx | 12 ++- .../trails/Breakdown/LabelBreakdownScene.tsx | 13 ++- .../app/features/trails/MetricSelect/api.ts | 3 +- .../trails/MetricSelect/previewPanel.test.ts | 2 +- .../trails/MetricSelect/previewPanel.ts | 2 +- .../autoQuery/getAutoQueriesForMetric.ts | 4 +- .../autoQuery/queryGenerators/common.ts | 2 + .../autoQuery/queryGenerators/histogram.ts | 2 + .../trails/helpers/MetricDatasourceHelper.ts | 13 +++ public/app/features/trails/otel/api.ts | 14 ++- public/app/features/trails/otel/util.ts | 18 +++- 16 files changed, 229 insertions(+), 15 deletions(-) diff --git a/devenv/docker/blocks/prometheus_utf8/main.go b/devenv/docker/blocks/prometheus_utf8/main.go index 1aaf3f49b1f..8a61eb97bba 100644 --- a/devenv/docker/blocks/prometheus_utf8/main.go +++ b/devenv/docker/blocks/prometheus_utf8/main.go @@ -60,6 +60,14 @@ func main() { label: "label.with.spaß", getNextValue: staticList([]string{"this_is_fun"}), }, + { + label: "instance", + getNextValue: staticList([]string{"instance"}), + }, + { + label: "job", + getNextValue: staticList([]string{"job"}), + }, { label: "site", getNextValue: staticList([]string{"LA-EPI"}), @@ -85,6 +93,12 @@ func main() { Help: "a metric with utf8 labels", }, dimensions) + target_info := promauto.NewGauge(prometheus.GaugeOpts{ + Name: "target_info", + Help: "an info metric model for otel", + ConstLabels: map[string]string{"job": "job", "instance": "instance", "resource 1": "1", "resource 2": "2", "resource ę": "e", "deployment_environment": "prod"}, + }) + http.Handle("/metrics", promhttp.Handler()) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) @@ -101,6 +115,7 @@ func main() { utf8Metric.WithLabelValues(labels...).Inc() opsProcessed.WithLabelValues(labels...).Inc() + target_info.Set(1) time.Sleep(time.Second * 5) } diff --git a/packages/grafana-prometheus/src/datasource.ts b/packages/grafana-prometheus/src/datasource.ts index 8ece500ac12..a6c0daffd37 100644 --- a/packages/grafana-prometheus/src/datasource.ts +++ b/packages/grafana-prometheus/src/datasource.ts @@ -71,6 +71,7 @@ import { RawRecordingRules, RuleQueryMapping, } from './types'; +import { utf8Support, wrapUtf8Filters } from './utf8_support'; import { PrometheusVariableSupport } from './variables'; const ANNOTATION_QUERY_STEP_DEFAULT = '60s'; @@ -925,7 +926,21 @@ export class PrometheusDatasource // We need a first replace to evaluate variables before applying adhoc filters // This is required for an expression like `metric > $VAR` where $VAR is a float to which we must not add adhoc filters - const expr = this.templateSrv.replace(target.expr, variables, this.interpolateQueryExpr); + const expr = this.templateSrv.replace( + target.expr, + variables, + (value: string | string[] = [], variable: QueryVariableModel | CustomVariableModel) => { + if (typeof value === 'string' && target.fromExploreMetrics) { + if (variable.name === 'filters') { + return wrapUtf8Filters(value); + } + if (variable.name === 'groupby') { + return utf8Support(value); + } + } + return this.interpolateQueryExpr(value, variable); + } + ); // Apply ad-hoc filters // When ad-hoc filters are applied, we replace again the variables in case the ad-hoc filters also reference a variable diff --git a/packages/grafana-prometheus/src/types.ts b/packages/grafana-prometheus/src/types.ts index 57903231250..25887e7d8eb 100644 --- a/packages/grafana-prometheus/src/types.ts +++ b/packages/grafana-prometheus/src/types.ts @@ -20,6 +20,7 @@ export interface PromQuery extends GenPromQuery, DataQuery { disableTextWrap?: boolean; fullMetaSearch?: boolean; includeNullMetadata?: boolean; + fromExploreMetrics?: boolean; } export enum PrometheusCacheLevel { diff --git a/packages/grafana-prometheus/src/utf8_support.test.ts b/packages/grafana-prometheus/src/utf8_support.test.ts index 0c62733bddf..5b02d3920e3 100644 --- a/packages/grafana-prometheus/src/utf8_support.test.ts +++ b/packages/grafana-prometheus/src/utf8_support.test.ts @@ -1,4 +1,4 @@ -import { escapeForUtf8Support, utf8Support } from './utf8_support'; +import { escapeForUtf8Support, utf8Support, wrapUtf8Filters } from './utf8_support'; describe('utf8 support', () => { it('should return utf8 labels wrapped in quotes', () => { @@ -33,3 +33,95 @@ describe('applyValueEncodingEscaping', () => { expect(excapedLabels).toEqual(expected); }); }); + +describe('wrapUtf8Filters', () => { + it('should correctly wrap UTF-8 labels and values for multiple key-value pairs', () => { + const result = wrapUtf8Filters('label.with.spaß="this_is_fun",instance="localhost:9112"'); + const expected = '"label.with.spaß"="this_is_fun",instance="localhost:9112"'; + expect(result).toEqual(expected); + }); + + it('should correctly wrap UTF-8 labels and values for a single key-value pair', () => { + const result = wrapUtf8Filters('label.with.spaß="this_is_fun"'); + const expected = '"label.with.spaß"="this_is_fun"'; + expect(result).toEqual(expected); + }); + + it('should correctly handle commas within values', () => { + const result = wrapUtf8Filters('label.with.spaß="this,is,fun",instance="localhost:9112"'); + const expected = '"label.with.spaß"="this,is,fun",instance="localhost:9112"'; + expect(result).toEqual(expected); + }); + + it('should correctly handle escaped quotes within values', () => { + const result = wrapUtf8Filters(`label.with.spaß="this_is_\\"fun\\"",instance="localhost:9112"`); + const expected = `"label.with.spaß"="this_is_\\"fun\\"",instance="localhost:9112"`; + expect(result).toEqual(expected); + }); + + it('should correctly handle spaces within keys', () => { + const result = wrapUtf8Filters('label with space="value with space",instance="localhost:9112"'); + const expected = '"label with space"="value with space",instance="localhost:9112"'; + expect(result).toEqual(expected); + }); + + it('should correctly process mixed inputs with various formats', () => { + const result = wrapUtf8Filters('key1="value1",key2="value,with,comma",key3="val3"'); + const expected = 'key1="value1",key2="value,with,comma",key3="val3"'; + expect(result).toEqual(expected); + }); + + it('should correctly handle empty values', () => { + const result = wrapUtf8Filters('key1="",key2="value2"'); + const expected = 'key1="",key2="value2"'; + expect(result).toEqual(expected); + }); + + it('should handle an empty input string', () => { + const result = wrapUtf8Filters(''); + const expected = ''; + expect(result).toEqual(expected); + }); + + it('should handle a single key with an empty value', () => { + const result = wrapUtf8Filters('key1=""'); + const expected = 'key1=""'; + expect(result).toEqual(expected); + }); + + it('should handle multiple consecutive commas in a value', () => { + const result = wrapUtf8Filters('key1="value1,,value2",key2="value3"'); + const expected = 'key1="value1,,value2",key2="value3"'; + expect(result).toEqual(expected); + }); + + it('should handle a key-value pair with special characters in the key', () => { + const result = wrapUtf8Filters('special@key#="value1",key2="value2"'); + const expected = '"special@key#"="value1",key2="value2"'; + expect(result).toEqual(expected); + }); + + it('should handle a key-value pair with special characters in the value', () => { + const result = wrapUtf8Filters('key1="value@#&*",key2="value2"'); + const expected = 'key1="value@#&*",key2="value2"'; + expect(result).toEqual(expected); + }); + + it('should correctly process keys without special characters', () => { + const result = wrapUtf8Filters('key1="value1",key2="value2"'); + const expected = 'key1="value1",key2="value2"'; + expect(result).toEqual(expected); + }); + + it('should handle nested escaped quotes correctly', () => { + const result = wrapUtf8Filters('key1="nested \\"escaped\\" quotes",key2="value2"'); + const expected = 'key1="nested \\"escaped\\" quotes",key2="value2"'; + expect(result).toEqual(expected); + }); + + it('should handle escaped quotes correctly', () => { + const result = wrapUtf8Filters('key1="nested \\"escaped\\" quotes",key2="value with \\"escaped\\" quotes"'); + const expected = 'key1="nested \\"escaped\\" quotes",key2="value with \\"escaped\\" quotes"'; + expect(result).toEqual(expected); + }); +}); diff --git a/packages/grafana-prometheus/src/utf8_support.ts b/packages/grafana-prometheus/src/utf8_support.ts index 386d41ba987..9f757c0bc73 100644 --- a/packages/grafana-prometheus/src/utf8_support.ts +++ b/packages/grafana-prometheus/src/utf8_support.ts @@ -79,3 +79,35 @@ const isValidCodePoint = (codePoint: number): boolean => { // Validate the code point for UTF-8 compliance if needed. return codePoint >= 0 && codePoint <= 0x10ffff; }; + +export const wrapUtf8Filters = (filterStr: string): string => { + const resultArray: string[] = []; + let currentKey = ''; + let currentValue = ''; + let inQuotes = false; + let temp = ''; + + for (const char of filterStr) { + if (char === '"' && temp[temp.length - 1] !== '\\') { + // Toggle inQuotes when an unescaped quote is found + inQuotes = !inQuotes; + temp += char; + } else if (char === ',' && !inQuotes) { + // When outside quotes and encountering ',', finalize the current pair + [currentKey, currentValue] = temp.split('='); + resultArray.push(`${utf8Support(currentKey.trim())}="${currentValue.slice(1, -1)}"`); + temp = ''; // Reset for the next pair + } else { + // Collect characters + temp += char; + } + } + + // Handle the last key-value pair + if (temp) { + [currentKey, currentValue] = temp.split('='); + resultArray.push(`${utf8Support(currentKey.trim())}="${currentValue.slice(1, -1)}"`); + } + + return resultArray.join(','); +}; diff --git a/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx b/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx index c82226fc763..4f3807c6034 100644 --- a/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx +++ b/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx @@ -1,6 +1,7 @@ import { useEffect } from 'react'; import { PromMetricsMetadataItem } from '@grafana/prometheus'; +import { isValidLegacyName } from '@grafana/prometheus/src/utf8_support'; import { QueryVariable, SceneComponentProps, @@ -90,9 +91,14 @@ export class MetricOverviewScene extends SceneObjectBase ({ label: el, value: el })); + const attributeArray: VariableValueOption[] = resourceAttributes.split(',').map((el) => { + let label = el; + if (!isValidLegacyName(el)) { + // remove '' from label + label = el.slice(1, -1); + } + return { label, value: el }; + }); allLabelOptions = attributeArray.concat(allLabelOptions); } } diff --git a/public/app/features/trails/Breakdown/LabelBreakdownScene.tsx b/public/app/features/trails/Breakdown/LabelBreakdownScene.tsx index 1ab14b84aac..c650e3876ae 100644 --- a/public/app/features/trails/Breakdown/LabelBreakdownScene.tsx +++ b/public/app/features/trails/Breakdown/LabelBreakdownScene.tsx @@ -4,6 +4,7 @@ import { isNumber, max, min, throttle } from 'lodash'; import { useEffect, useState } from 'react'; import { DataFrame, FieldType, GrafanaTheme2, PanelData, SelectableValue } from '@grafana/data'; +import { isValidLegacyName, utf8Support } from '@grafana/prometheus/src/utf8_support'; import { config } from '@grafana/runtime'; import { ConstantVariable, @@ -313,7 +314,14 @@ export class LabelBreakdownScene extends SceneObjectBase ({ label: el, value: el })); + const attributeArray: SelectableValue[] = resourceAttributes.split(',').map((el) => { + let label = el; + if (!isValidLegacyName(el)) { + // remove '' from label + label = el.slice(1, -1); + } + return { label, value: el }; + }); // shift ALL value to the front const all: SelectableValue = [{ label: 'All', value: ALL_VARIABLE_VALUE }]; const firstGroup = all.concat(attributeArray); @@ -449,7 +457,7 @@ export function buildAllLayout( break; } - const expr = queryDef.queries[0].expr.replaceAll(VAR_GROUP_BY_EXP, String(option.value)); + const expr = queryDef.queries[0].expr.replaceAll(VAR_GROUP_BY_EXP, utf8Support(String(option.value))); const unit = queryDef.unit; const vizPanel = PanelBuilders.timeseries() @@ -465,6 +473,7 @@ export function buildAllLayout( refId: `A-${option.label}`, expr, legendFormat: `{{${option.label}}}`, + fromExploreMetrics: true, }, ], }) diff --git a/public/app/features/trails/MetricSelect/api.ts b/public/app/features/trails/MetricSelect/api.ts index 2d499efc3c0..cd61a3782d5 100644 --- a/public/app/features/trails/MetricSelect/api.ts +++ b/public/app/features/trails/MetricSelect/api.ts @@ -1,6 +1,7 @@ import { AdHocVariableFilter, RawTimeRange, Scope } from '@grafana/data'; import { getPrometheusTime } from '@grafana/prometheus/src/language_utils'; import { PromQueryModeller } from '@grafana/prometheus/src/querybuilder/PromQueryModeller'; +import { utf8Support } from '@grafana/prometheus/src/utf8_support'; import { config, getBackendSrv } from '@grafana/runtime'; import { limitOtelMatchTerms } from '../otel/util'; @@ -38,7 +39,7 @@ export async function getMetricNamesWithoutScopes( ? adhocFilters.map((filter) => removeBrackets(queryModeller.renderLabels([{ label: filter.key, op: filter.operator, value: filter.value }])) ) - : adhocFilters.map((filter) => `${filter.key}${filter.operator}"${filter.value}"`); + : adhocFilters.map((filter) => `${utf8Support(filter.key)}${filter.operator}"${filter.value}"`); let missingOtelTargets = false; if (jobs.length > 0 && instances.length > 0) { diff --git a/public/app/features/trails/MetricSelect/previewPanel.test.ts b/public/app/features/trails/MetricSelect/previewPanel.test.ts index 59daafa3297..6175af65793 100644 --- a/public/app/features/trails/MetricSelect/previewPanel.test.ts +++ b/public/app/features/trails/MetricSelect/previewPanel.test.ts @@ -20,7 +20,7 @@ describe('getPreviewPanelFor', () => { }); test('When there are 1 or more filters, append to the ${filters} variable', () => { - const expected = 'avg(${metric}{${filters},__ignore_usage__=""} ${otel_join_query})'; + const expected = 'avg(${metric}{__ignore_usage__="",${filters}} ${otel_join_query})'; for (let i = 1; i < 10; ++i) { const expr = callAndGetExpr(1); diff --git a/public/app/features/trails/MetricSelect/previewPanel.ts b/public/app/features/trails/MetricSelect/previewPanel.ts index 92007959ac0..7206d3bb8e5 100644 --- a/public/app/features/trails/MetricSelect/previewPanel.ts +++ b/public/app/features/trails/MetricSelect/previewPanel.ts @@ -54,7 +54,7 @@ export function getPreviewPanelFor( function convertPreviewQueriesToIgnoreUsage(query: PromQuery, currentFilterCount: number) { // If there are filters, we append to the list. Otherwise, we replace the empty list. - const replacement = currentFilterCount > 0 ? '${filters},__ignore_usage__=""' : '__ignore_usage__=""'; + const replacement = currentFilterCount > 0 ? '__ignore_usage__="",${filters}' : '__ignore_usage__=""'; const expr = query.expr?.replace('${filters}', replacement); diff --git a/public/app/features/trails/autoQuery/getAutoQueriesForMetric.ts b/public/app/features/trails/autoQuery/getAutoQueriesForMetric.ts index 732fd6ed4b3..01b74f22ace 100644 --- a/public/app/features/trails/autoQuery/getAutoQueriesForMetric.ts +++ b/public/app/features/trails/autoQuery/getAutoQueriesForMetric.ts @@ -1,3 +1,5 @@ +import { isValidLegacyName } from '@grafana/prometheus/src/utf8_support'; + import { createDefaultMetricQueryDefs } from './queryGenerators/default'; import { createHistogramMetricQueryDefs } from './queryGenerators/histogram'; import { createSummaryMetricQueryDefs } from './queryGenerators/summary'; @@ -5,7 +7,7 @@ import { AutoQueryContext, AutoQueryInfo } from './types'; import { getUnit } from './units'; export function getAutoQueriesForMetric(metric: string, nativeHistogram?: boolean): AutoQueryInfo { - const isUtf8Metric = false; + const isUtf8Metric = !isValidLegacyName(metric); const metricParts = metric.split('_'); const suffix = metricParts.at(-1); diff --git a/public/app/features/trails/autoQuery/queryGenerators/common.ts b/public/app/features/trails/autoQuery/queryGenerators/common.ts index b0e82b4baa3..d77a8ce1de1 100644 --- a/public/app/features/trails/autoQuery/queryGenerators/common.ts +++ b/public/app/features/trails/autoQuery/queryGenerators/common.ts @@ -24,6 +24,7 @@ export function generateCommonAutoQueryInfo({ refId: 'A', expr: mainQueryExpr, legendFormat: description, + fromExploreMetrics: true, }; const main = { @@ -48,6 +49,7 @@ export function generateCommonAutoQueryInfo({ refId: 'A', expr: breakdownQueryExpr, legendFormat: `{{${VAR_GROUP_BY_EXP}}}`, + fromExploreMetrics: true, }, ], vizBuilder: () => simpleGraphBuilder(breakdown), diff --git a/public/app/features/trails/autoQuery/queryGenerators/histogram.ts b/public/app/features/trails/autoQuery/queryGenerators/histogram.ts index c4fc17ad331..015ecdc8441 100644 --- a/public/app/features/trails/autoQuery/queryGenerators/histogram.ts +++ b/public/app/features/trails/autoQuery/queryGenerators/histogram.ts @@ -44,6 +44,7 @@ export function createHistogramMetricQueryDefs(context: AutoQueryContext) { isUtf8Metric: context.isUtf8Metric, groupings: ['le'], }), + fromExploreMetrics: true, format: 'heatmap', }, ], @@ -73,5 +74,6 @@ function percentileQuery(context: AutoQueryContext, percentile: number, grouping refId: `Percentile${percentile}`, expr: `histogram_quantile(${percent}, ${query})`, legendFormat, + fromExploreMetrics: true, }; } diff --git a/public/app/features/trails/helpers/MetricDatasourceHelper.ts b/public/app/features/trails/helpers/MetricDatasourceHelper.ts index 4ecfb09db53..b77a28d2c3c 100644 --- a/public/app/features/trails/helpers/MetricDatasourceHelper.ts +++ b/public/app/features/trails/helpers/MetricDatasourceHelper.ts @@ -149,6 +149,7 @@ export class MetricDatasourceHelper { const ds = await this.getDatasource(); if (ds instanceof PrometheusDatasource) { + options.key = unwrapQuotes(options.key); const keys = await ds.getTagValues(options); return keys; } @@ -172,3 +173,15 @@ export function getMetricDescription(metadata?: PromMetricsMetadataItem) { return lines.join('\n\n'); } + +function unwrapQuotes(value: string): string { + if (value === '' || !isWrappedInQuotes(value)) { + return value; + } + return value.slice(1, -1); +} + +function isWrappedInQuotes(value: string): boolean { + const wrappedInQuotes = /^".*"$/; + return wrappedInQuotes.test(value); +} diff --git a/public/app/features/trails/otel/api.ts b/public/app/features/trails/otel/api.ts index 3399b0f7fe9..083d1bef15e 100644 --- a/public/app/features/trails/otel/api.ts +++ b/public/app/features/trails/otel/api.ts @@ -1,5 +1,6 @@ import { RawTimeRange, Scope } from '@grafana/data'; import { getPrometheusTime } from '@grafana/prometheus/src/language_utils'; +import { isValidLegacyName } from '@grafana/prometheus/src/utf8_support'; import { config, getBackendSrv } from '@grafana/runtime'; import { callSuggestionsApi } from '../utils'; @@ -40,7 +41,10 @@ export async function totalOtelResources( ): Promise { const start = getPrometheusTime(timeRange.from, false); const end = getPrometheusTime(timeRange.to, true); - + // check that the metric is utf8 before doing a resource query + if (metric && !isValidLegacyName(metric)) { + metric = `{"${metric}"}`; + } const query = metric ? metricOtelJobInstanceQuery(metric) : otelTargetInfoQuery(filters); const url = `/api/datasources/uid/${dataSourceUid}/resources/api/v1/query`; @@ -204,7 +208,13 @@ export async function getFilteredResourceAttributes( // The match param for the metric to get all possible labels for this metric const metricMatchTerms = limitOtelMatchTerms([], metricResources.jobs, metricResources.instances); - let metricMatchParam = `${metric}{${metricMatchTerms.jobsRegex},${metricMatchTerms.instancesRegex}}`; + let metricMatchParam = ''; + // check metric is utf8 to give corrrect syntax + if (!isValidLegacyName(metric)) { + metricMatchParam = `{'${metric}',${metricMatchTerms.jobsRegex},${metricMatchTerms.instancesRegex}}`; + } else { + metricMatchParam = `${metric}{${metricMatchTerms.jobsRegex},${metricMatchTerms.instancesRegex}}`; + } const start = getPrometheusTime(timeRange.from, false); const end = getPrometheusTime(timeRange.to, true); diff --git a/public/app/features/trails/otel/util.ts b/public/app/features/trails/otel/util.ts index d5c2c0b9886..b0f95dabd51 100644 --- a/public/app/features/trails/otel/util.ts +++ b/public/app/features/trails/otel/util.ts @@ -1,4 +1,5 @@ import { AdHocVariableFilter, MetricFindValue, RawTimeRange, VariableHide } from '@grafana/data'; +import { isValidLegacyName } from '@grafana/prometheus/src/utf8_support'; import { config } from '@grafana/runtime'; import { AdHocFiltersVariable, ConstantVariable, sceneGraph, SceneObject } from '@grafana/scenes'; @@ -110,7 +111,13 @@ export function getOtelResourcesObject(scene: SceneObject, firstQueryVal?: strin // add the other OTEL resource filters for (let i = 0; i < otelFilters?.length; i++) { - const labelName = otelFilters[i].key; + let labelName = otelFilters[i].key; + + // when adding an otel resource filter with utfb + if (!isValidLegacyName(labelName)) { + labelName = `'${labelName}'`; + } + const op = otelFilters[i].operator; const labelValue = otelFilters[i].value; @@ -281,8 +288,15 @@ export async function updateOtelJoinWithGroupLeft(trail: DataTrail, metric: stri ); // here we start to add the attributes to the group left if (attributes.length > 0) { + // loop through attributes to check for utf8 + const utf8Attributes = attributes.map((a) => { + if (!isValidLegacyName(a)) { + return `'${a}'`; + } + return a; + }); // update the group left variable that contains all the filtered resource attributes - otelGroupLeft.setState({ value: attributes.join(',') }); + otelGroupLeft.setState({ value: utf8Attributes.join(',') }); // get the new otel join query that includes the group left attributes const resourceObject = getOtelResourcesObject(trail); const otelJoinQuery = getOtelJoinQuery(resourceObject, trail); From 019ee9c2d47c0cac67bd484dae084cbce81bcd6d Mon Sep 17 00:00:00 2001 From: Ihor Yeromin Date: Thu, 16 Jan 2025 15:58:56 +0100 Subject: [PATCH 11/30] Table: Fix inspect drawer disappears unexpectedly (#99025) fix(table): inspect drawer disappears unexpectedly --- .betterer.results | 3 +- .../src/components/Table/CellActions.tsx | 69 +++++---- .../src/components/Table/DefaultCell.tsx | 22 +-- .../src/components/Table/RowsList.tsx | 12 +- .../grafana-ui/src/components/Table/Table.tsx | 136 ++++++++++-------- .../src/components/Table/TableCell.tsx | 5 +- .../grafana-ui/src/components/Table/types.ts | 5 + 7 files changed, 134 insertions(+), 118 deletions(-) diff --git a/.betterer.results b/.betterer.results index fc658ccf0c8..40e87849b9b 100644 --- a/.betterer.results +++ b/.betterer.results @@ -830,7 +830,8 @@ exports[`better eslint`] = { ], "packages/grafana-ui/src/components/Table/types.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], - [0, 0, 0, "Unexpected any. Specify a different type.", "1"] + [0, 0, 0, "Unexpected any. Specify a different type.", "1"], + [0, 0, 0, "Unexpected any. Specify a different type.", "2"] ], "packages/grafana-ui/src/components/Table/utils.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], diff --git a/packages/grafana-ui/src/components/Table/CellActions.tsx b/packages/grafana-ui/src/components/Table/CellActions.tsx index 222c441d5e2..8c70d56a481 100644 --- a/packages/grafana-ui/src/components/Table/CellActions.tsx +++ b/packages/grafana-ui/src/components/Table/CellActions.tsx @@ -1,4 +1,4 @@ -import { useCallback, useState } from 'react'; +import { useCallback } from 'react'; import * as React from 'react'; import { IconSize } from '../../types/icon'; @@ -6,7 +6,7 @@ import { IconButton } from '../IconButton/IconButton'; import { Stack } from '../Layout/Stack/Stack'; import { TooltipPlacement } from '../Tooltip'; -import { TableCellInspector, TableCellInspectorMode } from './TableCellInspector'; +import { TableCellInspectorMode } from './TableCellInspector'; import { FILTER_FOR_OPERATOR, FILTER_OUT_OPERATOR, TableCellProps } from './types'; import { getTextAlign } from './utils'; @@ -20,9 +20,14 @@ interface CommonButtonProps { tooltipPlacement: TooltipPlacement; } -export function CellActions({ field, cell, previewMode, showFilters, onCellFilterAdded }: CellActionProps) { - const [isInspecting, setIsInspecting] = useState(false); - +export function CellActions({ + field, + cell, + previewMode, + showFilters, + onCellFilterAdded, + setInspectCell, +}: CellActionProps) { const isRightAligned = getTextAlign(field) === 'flex-end'; const inspectEnabled = Boolean(field.config.custom?.inspect); const commonButtonProps: CommonButtonProps = { @@ -48,37 +53,27 @@ export function CellActions({ field, cell, previewMode, showFilters, onCellFilte ); return ( - <> -
- - {inspectEnabled && ( - { - setIsInspecting(true); - }} - {...commonButtonProps} - /> - )} - {showFilters && ( - - )} - {showFilters && ( - - )} - -
- - {isInspecting && ( - { - setIsInspecting(false); - }} - /> - )} - +
+ + {inspectEnabled && ( + { + if (setInspectCell) { + setInspectCell({ value: cell.value, mode: previewMode }); + } + }} + {...commonButtonProps} + /> + )} + {showFilters && ( + + )} + {showFilters && ( + + )} + +
); } diff --git a/packages/grafana-ui/src/components/Table/DefaultCell.tsx b/packages/grafana-ui/src/components/Table/DefaultCell.tsx index d37f37d5abc..652aae07f0c 100644 --- a/packages/grafana-ui/src/components/Table/DefaultCell.tsx +++ b/packages/grafana-ui/src/components/Table/DefaultCell.tsx @@ -1,5 +1,5 @@ import { cx } from '@emotion/css'; -import { ReactElement, useState } from 'react'; +import { ReactElement } from 'react'; import * as React from 'react'; import { DisplayValue, formattedValueToString } from '@grafana/data'; @@ -28,18 +28,10 @@ export const DefaultCell = (props: TableCellProps) => { const hasLinks = Boolean(getCellLinks(field, row)?.length); const hasActions = Boolean(actions?.length); const clearButtonStyle = useStyles2(clearLinkButtonStyles); - const [hover, setHover] = useState(false); let value: string | ReactElement; const OG_TWEET_LENGTH = 140; // 🙏 - const onMouseLeave = () => { - setHover(false); - }; - const onMouseEnter = () => { - setHover(true); - }; - if (cellOptions.type === TableCellDisplayMode.Custom) { const CustomCellComponent: React.ComponentType = cellOptions.cellComponent; value = ; @@ -88,13 +80,7 @@ export const DefaultCell = (props: TableCellProps) => { const { key, ...rest } = cellProps; return ( -
+
{hasLinks || hasActions ? ( getCellLinks(field, row) || []} actions={actions}> {(api) => { @@ -118,9 +104,7 @@ export const DefaultCell = (props: TableCellProps) => {
{value}
)} - {hover && showActions && ( - - )} + {showActions && }
); }; diff --git a/packages/grafana-ui/src/components/Table/RowsList.tsx b/packages/grafana-ui/src/components/Table/RowsList.tsx index 646b4781fbe..b15745d3b82 100644 --- a/packages/grafana-ui/src/components/Table/RowsList.tsx +++ b/packages/grafana-ui/src/components/Table/RowsList.tsx @@ -24,7 +24,13 @@ import { usePanelContext } from '../PanelChrome'; import { ExpandedRow, getExpandedRowHeight } from './ExpandedRow'; import { TableCell } from './TableCell'; import { TableStyles } from './styles'; -import { CellColors, GetActionsFunction, TableFieldOptions, TableFilterActionCallback } from './types'; +import { + CellColors, + GetActionsFunction, + TableFieldOptions, + TableFilterActionCallback, + TableInspectCellCallback, +} from './types'; import { calculateAroundPointThreshold, getCellColors, @@ -57,6 +63,7 @@ interface RowsListProps { textWrapField?: Field; getActions?: GetActionsFunction; replaceVariables?: InterpolateFunction; + setInspectCell?: TableInspectCellCallback; } export const RowsList = (props: RowsListProps) => { @@ -85,6 +92,7 @@ export const RowsList = (props: RowsListProps) => { textWrapField, getActions, replaceVariables, + setInspectCell, } = props; const [rowHighlightIndex, setRowHighlightIndex] = useState(initialRowIndex); @@ -346,6 +354,7 @@ export const RowsList = (props: RowsListProps) => { height={Number(style.height)} getActions={getActions} replaceVariables={replaceVariables} + setInspectCell={setInspectCell} /> ))}
@@ -374,6 +383,7 @@ export const RowsList = (props: RowsListProps) => { timeRange, getActions, replaceVariables, + setInspectCell, ] ); diff --git a/packages/grafana-ui/src/components/Table/Table.tsx b/packages/grafana-ui/src/components/Table/Table.tsx index 54d61990463..2d8a040dc65 100644 --- a/packages/grafana-ui/src/components/Table/Table.tsx +++ b/packages/grafana-ui/src/components/Table/Table.tsx @@ -22,10 +22,11 @@ import { Pagination } from '../Pagination/Pagination'; import { FooterRow } from './FooterRow'; import { HeaderRow } from './HeaderRow'; import { RowsList } from './RowsList'; +import { TableCellInspector } from './TableCellInspector'; import { useFixScrollbarContainer, useResetVariableListSizeCache } from './hooks'; import { getInitialState, useTableStateReducer } from './reducer'; import { useTableStyles } from './styles'; -import { FooterItem, GrafanaTableState, Props } from './types'; +import { FooterItem, GrafanaTableState, InspectCell, Props } from './types'; import { getColumns, sortCaseInsensitive, @@ -72,6 +73,7 @@ export const Table = memo((props: Props) => { const headerHeight = noHeader ? 0 : tableStyles.rowHeight; const [footerItems, setFooterItems] = useState(footerValues); const noValuesDisplayText = fieldConfig?.defaults?.noValue ?? NO_DATA_TEXT; + const [inspectCell, setInspectCell] = useState(null); const footerHeight = useMemo(() => { const EXTENDED_ROW_HEIGHT = FOOTER_ROW_HEIGHT; @@ -324,66 +326,82 @@ export const Table = memo((props: Props) => { } return ( -
- -
- {!noHeader && ( - - )} - {itemCount > 0 ? ( -
- +
+ +
+ {!noHeader && ( + + )} + {itemCount > 0 ? ( +
+ +
+ ) : ( +
+ {noValuesDisplayText} +
+ )} + {footerItems && ( + -
- ) : ( -
- {noValuesDisplayText} -
- )} - {footerItems && ( - - )} -
- - {paginationEl} -
+ )} +
+
+ {paginationEl} +
+ + {inspectCell !== null && ( + { + setInspectCell(null); + }} + /> + )} + ); }); diff --git a/packages/grafana-ui/src/components/Table/TableCell.tsx b/packages/grafana-ui/src/components/Table/TableCell.tsx index 8fa154d519e..1ca230db4d4 100644 --- a/packages/grafana-ui/src/components/Table/TableCell.tsx +++ b/packages/grafana-ui/src/components/Table/TableCell.tsx @@ -3,7 +3,7 @@ import { Cell } from 'react-table'; import { TimeRange, DataFrame, InterpolateFunction } from '@grafana/data'; import { TableStyles } from './styles'; -import { GetActionsFunction, GrafanaTableColumn, TableFilterActionCallback } from './types'; +import { GetActionsFunction, GrafanaTableColumn, TableFilterActionCallback, TableInspectCellCallback } from './types'; export interface Props { cell: Cell; @@ -20,6 +20,7 @@ export interface Props { height?: number; getActions?: GetActionsFunction; replaceVariables?: InterpolateFunction; + setInspectCell?: TableInspectCellCallback; } export const TableCell = ({ @@ -35,6 +36,7 @@ export const TableCell = ({ height, getActions, replaceVariables, + setInspectCell, }: Props) => { const cellProps = cell.getCellProps(); const field = (cell.column as unknown as GrafanaTableColumn).field; @@ -78,6 +80,7 @@ export const TableCell = ({ textWrapped, height, actions, + setInspectCell, })} ); diff --git a/packages/grafana-ui/src/components/Table/types.ts b/packages/grafana-ui/src/components/Table/types.ts index 94d0c1183a2..ce1a0809f9d 100644 --- a/packages/grafana-ui/src/components/Table/types.ts +++ b/packages/grafana-ui/src/components/Table/types.ts @@ -14,6 +14,7 @@ import { } from '@grafana/data'; import * as schema from '@grafana/schema'; +import { TableCellInspectorMode } from './TableCellInspector'; import { TableStyles } from './styles'; export { @@ -33,6 +34,8 @@ export interface TableRow { [x: string]: any; } +export type InspectCell = { value: any; mode: TableCellInspectorMode }; + export const FILTER_FOR_OPERATOR = '='; export const FILTER_OUT_OPERATOR = '!='; export type AdHocFilterOperator = typeof FILTER_FOR_OPERATOR | typeof FILTER_OUT_OPERATOR; @@ -40,6 +43,7 @@ export type AdHocFilterItem = { key: string; value: string; operator: AdHocFilte export type TableFilterActionCallback = (item: AdHocFilterItem) => void; export type TableColumnResizeActionCallback = (fieldDisplayName: string, width: number) => void; export type TableSortByActionCallback = (state: TableSortByFieldState[]) => void; +export type TableInspectCellCallback = (state: InspectCell) => void; export interface TableSortByFieldState { displayName: string; @@ -54,6 +58,7 @@ export interface TableCellProps extends CellProps { innerWidth: number; frame: DataFrame; actions?: ActionModel[]; + setInspectCell?: TableInspectCellCallback; } export type CellComponent = FC; From 4386cfc984dcc3752ec4545252260af01d5d6acb Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Thu, 16 Jan 2025 16:10:34 +0100 Subject: [PATCH 12/30] Prometheus: Support utf8 metrics and labels in variable editor (#98345) * utf8 metrics for prometheus devenv * introduce utf8 support * completions and suggestions * don't wrap the utf8 label in quotes * linting * support utf8 labels and metrics on visual query builder * lint * update raw view for utf8 metric syntax * betterer * support utf8 metric names in explore metrics * utf8 support in grouop by * utf8 support in label break down * utf8 metric and label support in metric_find_query for label values * use the same regex to check label values * no need to escape * support series endpoint * support series endpoint * support series endpoint * support series endpoint * fix tests * fix extracting labels from labelValuesQuery * betterer --- .../src/metric_find_query.test.ts | 47 +++++++++++++++++++ .../src/metric_find_query.ts | 11 ++++- .../src/migrations/variableMigration.ts | 5 +- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/packages/grafana-prometheus/src/metric_find_query.test.ts b/packages/grafana-prometheus/src/metric_find_query.test.ts index 347f2b30be3..8a0aabe6480 100644 --- a/packages/grafana-prometheus/src/metric_find_query.test.ts +++ b/packages/grafana-prometheus/src/metric_find_query.test.ts @@ -8,6 +8,7 @@ import { PrometheusDatasource } from './datasource'; import { getPrometheusTime } from './language_utils'; import { PrometheusMetricFindQuery } from './metric_find_query'; import { PromApplication, PromOptions } from './types'; +import { escapeForUtf8Support } from './utf8_support'; const fetchMock = jest.fn((options: BackendSrvRequest): Observable> => { return of({} as unknown as FetchResponse); @@ -413,5 +414,51 @@ describe('PrometheusMetricFindQuery', () => { }); }); // + describe('utf8 metric and label support', () => { + it('utf8 label - label_values(a_utf8_http_requests_total,instance.test) should generate label values query', () => { + const metricName = 'a_utf8_http_requests_total'; + const label = 'instance.test'; + const query = `label_values(${metricName},${label})`; + const metricFindQuery = new PrometheusMetricFindQuery(prometheusDatasource, query); + metricFindQuery.process(raw); + expect(fetchMock).toHaveBeenCalledTimes(1); + expect(fetchMock).toHaveBeenCalledWith({ + method: 'GET', + url: `/api/datasources/uid/ABCDEF/resources/api/v1/label/${escapeForUtf8Support(label)}/values?match%5B%5D=${metricName}&start=1524650400&end=1524654000`, + hideFromInspector: true, + headers: {}, + }); + }); + + it('utf8 metric - label_values(utf8.http_requests_total,instance_test) should generate label values query', () => { + const metricName = 'utf8.http_requests_total'; + const label = 'instance_test'; + const query = `label_values(${metricName},${label})`; + const metricFindQuery = new PrometheusMetricFindQuery(prometheusDatasource, query); + metricFindQuery.process(raw); + expect(fetchMock).toHaveBeenCalledTimes(1); + expect(fetchMock).toHaveBeenCalledWith({ + method: 'GET', + url: `/api/datasources/uid/ABCDEF/resources/api/v1/label/${label}/values?match%5B%5D=${metricName}&start=1524650400&end=1524654000`, + hideFromInspector: true, + headers: {}, + }); + }); + + it('utf8 metric and label - label_values(utf8.http_requests_total,instance.test) should generate label values query', () => { + const metricName = 'utf8.http_requests_total'; + const label = 'instance.test'; + const query = `label_values(${metricName},${label})`; + const metricFindQuery = new PrometheusMetricFindQuery(prometheusDatasource, query); + metricFindQuery.process(raw); + expect(fetchMock).toHaveBeenCalledTimes(1); + expect(fetchMock).toHaveBeenCalledWith({ + method: 'GET', + url: `/api/datasources/uid/ABCDEF/resources/api/v1/label/${escapeForUtf8Support(label)}/values?match%5B%5D=${metricName}&start=1524650400&end=1524654000`, + hideFromInspector: true, + headers: {}, + }); + }); + }); }); }); diff --git a/packages/grafana-prometheus/src/metric_find_query.ts b/packages/grafana-prometheus/src/metric_find_query.ts index 8be41c06364..69494f0f7fc 100644 --- a/packages/grafana-prometheus/src/metric_find_query.ts +++ b/packages/grafana-prometheus/src/metric_find_query.ts @@ -8,9 +8,11 @@ import { getPrometheusTime } from './language_utils'; import { PrometheusLabelNamesRegex, PrometheusLabelNamesRegexWithMatch, + PrometheusLabelValuesRegex, PrometheusMetricNamesRegex, PrometheusQueryResultRegex, } from './migrations/variableMigration'; +import { escapeForUtf8Support, isValidLegacyName } from './utf8_support'; export class PrometheusMetricFindQuery { range: TimeRange; @@ -28,7 +30,7 @@ export class PrometheusMetricFindQuery { this.range = timeRange; const labelNamesRegex = PrometheusLabelNamesRegex; const labelNamesRegexWithMatch = PrometheusLabelNamesRegexWithMatch; - const labelValuesRegex = /^label_values\((?:(.+),\s*)?([a-zA-Z_][a-zA-Z0-9_]*)\)\s*$/; + const labelValuesRegex = PrometheusLabelValuesRegex; const metricNamesRegex = PrometheusMetricNamesRegex; const queryResultRegex = PrometheusQueryResultRegex; const labelNamesQuery = this.query.match(labelNamesRegex); @@ -83,8 +85,13 @@ export class PrometheusMetricFindQuery { const end = getPrometheusTime(this.range.to, true); const params = { ...(metric && { 'match[]': metric }), start: start.toString(), end: end.toString() }; + let escapedLabel = label; + if (!isValidLegacyName(label)) { + escapedLabel = escapeForUtf8Support(label); + } + if (!metric || this.datasource.hasLabelsMatchAPISupport()) { - const url = `/api/v1/label/${label}/values`; + const url = `/api/v1/label/${escapedLabel}/values`; return this.datasource.metadataRequest(url, params).then((result) => { return _map(result.data.data, (value) => { diff --git a/packages/grafana-prometheus/src/migrations/variableMigration.ts b/packages/grafana-prometheus/src/migrations/variableMigration.ts index 08476c2f4b6..35c4c483180 100644 --- a/packages/grafana-prometheus/src/migrations/variableMigration.ts +++ b/packages/grafana-prometheus/src/migrations/variableMigration.ts @@ -4,8 +4,7 @@ import { buildVisualQueryFromString } from '../querybuilder/parsing'; import { PromVariableQuery, PromVariableQueryType as QueryType } from '../types'; export const PrometheusLabelNamesRegex = /^label_names\(\)\s*$/; -// Note that this regex is different from the one in metric_find_query.ts because this is used pre-interpolation -export const PrometheusLabelValuesRegex = /^label_values\((?:(.+),\s*)?([a-zA-Z_$][a-zA-Z0-9_]*)\)\s*$/; +export const PrometheusLabelValuesRegex = /^label_values\((?:(.+),\s*)?(.+)\)\s*$/; export const PrometheusMetricNamesRegex = /^metrics\((.+)\)\s*$/; export const PrometheusQueryResultRegex = /^query_result\((.+)\)\s*$/; export const PrometheusLabelNamesRegexWithMatch = /^label_names\((.+)\)\s*$/; @@ -97,7 +96,7 @@ export function migrateVariableQueryToEditor(rawQuery: string | PromVariableQuer return queryBase; } -// migrate it back to a string with the correct varialbes in place +// migrate it back to a string with the correct variables in place export function migrateVariableEditorBackToVariableSupport(QueryVariable: PromVariableQuery): string { switch (QueryVariable.qryType) { case QueryType.LabelNames: From 029edcb6be07dae27d2ae5d2e188b29b687a2aa5 Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Thu, 16 Jan 2025 16:30:29 +0100 Subject: [PATCH 13/30] Prometheus: Render metrics and labels in explanation with right syntax (#98591) * utf8 metrics for prometheus devenv * introduce utf8 support * completions and suggestions * don't wrap the utf8 label in quotes * linting * support utf8 labels and metrics on visual query builder * lint * update raw view for utf8 metric syntax * betterer * support utf8 metric names in explore metrics * utf8 support in grouop by * utf8 support in label break down * utf8 metric and label support in metric_find_query for label values * use the same regex to check label values * no need to escape * support series endpoint * support series endpoint * support series endpoint * support series endpoint * fix tests * fix extracting labels from labelValuesQuery * show explanation with right syntax * betterer --- .../src/querybuilder/components/PromQueryBuilder.tsx | 2 +- .../src/querybuilder/components/PromQueryBuilderExplained.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.tsx index a1d450b2452..fd99b883f6d 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.tsx @@ -93,7 +93,7 @@ export const PromQueryBuilder = memo((props) => { {showExplain && ( } + title={} > {EXPLAIN_LABEL_FILTER_CONTENT} diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderExplained.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderExplained.tsx index 4fa9503c34e..c7efa30900d 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderExplained.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderExplained.tsx @@ -25,7 +25,7 @@ export const PromQueryBuilderExplained = memo(({ } + title={} > {EXPLAIN_LABEL_FILTER_CONTENT} From 106af5d0ee299fbfe5830076b67abb5efcdab0ca Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Thu, 16 Jan 2025 16:50:35 +0100 Subject: [PATCH 14/30] Prometheus: UTF8 support in metrics browser (#98612) * utf8 metrics for prometheus devenv * introduce utf8 support * completions and suggestions * don't wrap the utf8 label in quotes * linting * support utf8 labels and metrics on visual query builder * lint * update raw view for utf8 metric syntax * betterer * support utf8 metric names in explore metrics * utf8 support in grouop by * utf8 support in label break down * utf8 metric and label support in metric_find_query for label values * use the same regex to check label values * no need to escape * support series endpoint * support series endpoint * support series endpoint * support series endpoint * fix tests * fix extracting labels from labelValuesQuery * show explanation with right syntax * support utf8 metrics and labels --- .../PrometheusMetricsBrowser.test.tsx | 43 +++++++++++++++++++ .../components/PrometheusMetricsBrowser.tsx | 25 +++++++++-- 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.test.tsx b/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.test.tsx index 58efb0e28f0..df14c9e02c8 100644 --- a/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.test.tsx +++ b/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.test.tsx @@ -54,6 +54,49 @@ describe('buildSelector()', () => { ]; expect(buildSelector(labels)).toEqual('foo{bar="baz"}'); }); + + describe('utf8 support', () => { + it('metric selector with utf8 metric', () => { + const labels: SelectableLabel[] = [ + { name: '__name__', selected: true, values: [{ name: 'utf8.metric', selected: true }] }, + ]; + expect(buildSelector(labels)).toEqual('{"utf8.metric"}'); + }); + + it('metric selector with utf8 labels', () => { + const labels: SelectableLabel[] = [ + { name: '__name__', selected: true, values: [{ name: 'foo', selected: true }] }, + { name: 'utf8.label', selected: true, values: [{ name: 'baz', selected: true }] }, + ]; + expect(buildSelector(labels)).toEqual('foo{"utf8.label"="baz"}'); + }); + + it('metric selector with utf8 labels and metrics', () => { + const labels: SelectableLabel[] = [ + { name: '__name__', selected: true, values: [{ name: 'utf8.metric', selected: true }] }, + { name: 'utf8.label', selected: true, values: [{ name: 'baz', selected: true }] }, + ]; + expect(buildSelector(labels)).toEqual('{"utf8.metric","utf8.label"="baz"}'); + }); + + it('metric selector with utf8 metric and with utf8/non-utf8 labels', () => { + const labels: SelectableLabel[] = [ + { name: '__name__', selected: true, values: [{ name: 'utf8.metric', selected: true }] }, + { name: 'utf8.label', selected: true, values: [{ name: 'uuu', selected: true }] }, + { name: 'bar', selected: true, values: [{ name: 'baz', selected: true }] }, + ]; + expect(buildSelector(labels)).toEqual('{"utf8.metric","utf8.label"="uuu",bar="baz"}'); + }); + + it('metric selector with non-utf8 metric with utf8/non-utf8 labels', () => { + const labels: SelectableLabel[] = [ + { name: '__name__', selected: true, values: [{ name: 'foo', selected: true }] }, + { name: 'utf8.label', selected: true, values: [{ name: 'uuu', selected: true }] }, + { name: 'bar', selected: true, values: [{ name: 'baz', selected: true }] }, + ]; + expect(buildSelector(labels)).toEqual('foo{"utf8.label"="uuu",bar="baz"}'); + }); + }); }); describe('facetLabels()', () => { diff --git a/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.tsx b/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.tsx index 963590f3667..1eeb59d35ed 100644 --- a/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.tsx +++ b/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.tsx @@ -19,6 +19,7 @@ import { import PromQlLanguageProvider from '../language_provider'; import { escapeLabelValueInExactSelector, escapeLabelValueInRegexSelector } from '../language_utils'; +import { isValidLegacyName, utf8Support } from '../utf8_support'; // Hard limit on labels to render const EMPTY_SELECTOR = '{}'; @@ -68,22 +69,38 @@ export interface SelectableLabel { export function buildSelector(labels: SelectableLabel[]): string { let singleMetric = ''; - const selectedLabels = []; + const selectedLabels: string[] = []; for (const label of labels) { if ((label.name === METRIC_LABEL || label.selected) && label.values && label.values.length > 0) { const selectedValues = label.values.filter((value) => value.selected).map((value) => value.name); if (selectedValues.length > 1) { - selectedLabels.push(`${label.name}=~"${selectedValues.map(escapeLabelValueInRegexSelector).join('|')}"`); + selectedLabels.push( + `${utf8Support(label.name)}=~"${selectedValues.map(escapeLabelValueInRegexSelector).join('|')}"` + ); } else if (selectedValues.length === 1) { if (label.name === METRIC_LABEL) { singleMetric = selectedValues[0]; } else { - selectedLabels.push(`${label.name}="${escapeLabelValueInExactSelector(selectedValues[0])}"`); + selectedLabels.push(`${utf8Support(label.name)}="${escapeLabelValueInExactSelector(selectedValues[0])}"`); } } } } - return [singleMetric, '{', selectedLabels.join(','), '}'].join(''); + + const selectorParts: string[] = []; + const isLegacyName = singleMetric === '' || isValidLegacyName(singleMetric); + + if (isLegacyName) { + selectorParts.push(singleMetric, '{'); + } else { + selectorParts.push('{', `"${singleMetric}"`); + if (selectedLabels.length > 0) { + selectorParts.push(','); + } + } + + selectorParts.push(selectedLabels.join(','), '}'); + return selectorParts.join(''); } export function facetLabels( From cff07c9fb65551059754d702f7bda8f141e6d4e3 Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Thu, 16 Jan 2025 15:58:02 +0000 Subject: [PATCH 15/30] Chore: Replace `rc-time-picker` with `rc-picker` (#99022) * replace rc-time-picker with rc-picker * remove unnecessary stack * remove TimePickerInput * make props stricter * fix type assertions * remove outdated comment * fix types * fix clear icon * fix styling * fix z-index and 6 tests * fix remaining unit tests * betterer results * styling tweaks * don't show/hide scrollbars on hover --- .betterer.results | 4 - .yarnrc.yml | 4 - package.json | 1 - packages/grafana-ui/package.json | 2 +- .../DateTimePicker/DateTimePicker.test.tsx | 26 +-- .../DateTimePickers/TimeOfDayPicker.story.tsx | 2 +- .../DateTimePickers/TimeOfDayPicker.tsx | 193 ++++++++++++------ .../src/themes/GlobalStyles/GlobalStyles.tsx | 2 - .../src/themes/GlobalStyles/rcTimePicker.ts | 43 ---- .../grafana/components/TimePickerInput.tsx | 185 ----------------- .../grafana/components/TimeRegionEditor.tsx | 27 +-- yarn.lock | 174 ++++++---------- 12 files changed, 225 insertions(+), 438 deletions(-) delete mode 100644 packages/grafana-ui/src/themes/GlobalStyles/rcTimePicker.ts delete mode 100644 public/app/plugins/datasource/grafana/components/TimePickerInput.tsx diff --git a/.betterer.results b/.betterer.results index 40e87849b9b..7f8289827a0 100644 --- a/.betterer.results +++ b/.betterer.results @@ -7323,10 +7323,6 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "1"], [0, 0, 0, "Unexpected any. Specify a different type.", "2"] ], - "public/app/plugins/datasource/grafana/components/TimePickerInput.tsx:5381": [ - [0, 0, 0, "\'@grafana/ui/src/components/Forms/commonStyles\' import is restricted from being used by a pattern. Import from the public export instead.", "0"], - [0, 0, 0, "\'@grafana/ui/src/themes/mixins\' import is restricted from being used by a pattern. Import from the public export instead.", "1"] - ], "public/app/plugins/datasource/grafana/components/TimeRegionEditor.tsx:5381": [ [0, 0, 0, "\'@grafana/ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneOffset\' import is restricted from being used by a pattern. Import from the public export instead.", "0"], [0, 0, 0, "\'@grafana/ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneTitle\' import is restricted from being used by a pattern. Import from the public export instead.", "1"] diff --git a/.yarnrc.yml b/.yarnrc.yml index f71bc901067..a5a0620502d 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -13,10 +13,6 @@ packageExtensions: doctrine@3.0.0: dependencies: assert: 2.0.0 - rc-time-picker@3.7.3: - peerDependencies: - react: 17.0.1 - react-dom: 17.0.1 rc-trigger@2.6.5: peerDependencies: react: 17.0.1 diff --git a/package.json b/package.json index e6bbe7d9342..a904ada7489 100644 --- a/package.json +++ b/package.json @@ -359,7 +359,6 @@ "pluralize": "^8.0.0", "prismjs": "1.29.0", "rc-slider": "11.1.8", - "rc-time-picker": "3.7.3", "rc-tree": "5.13.0", "re-resizable": "6.10.3", "react": "18.2.0", diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 67fcee3c097..1e8f79787fd 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -85,8 +85,8 @@ "prismjs": "1.29.0", "rc-cascader": "3.33.0", "rc-drawer": "7.2.0", + "rc-picker": "4.9.2", "rc-slider": "11.1.8", - "rc-time-picker": "^3.7.3", "rc-tooltip": "6.4.0", "react-calendar": "^5.1.0", "react-colorful": "5.6.1", diff --git a/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.test.tsx b/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.test.tsx index 0d83fc4a53d..ca99959c7d0 100644 --- a/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.test.tsx +++ b/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.test.tsx @@ -1,4 +1,4 @@ -import { render, screen } from '@testing-library/react'; +import { render, screen, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { dateTime, dateTimeAsMoment, dateTimeForTimeZone, getTimeZone, setTimeZoneResolver } from '@grafana/data'; @@ -86,23 +86,16 @@ describe('Date time picker', () => { // open the time of day overlay await userEvent.click(screen.getAllByRole('textbox')[1]); + const hourList = screen.getAllByRole('list')[0]; // change the hour - await userEvent.click( - screen.getAllByRole('button', { - name: '00', - })[0] - ); + await userEvent.click(within(hourList).getByText('00')); // Check the active day is the 5th expect(screen.getByRole('button', { name: 'May 5, 2021' })).toHaveClass('react-calendar__tile--active'); // change the hour - await userEvent.click( - screen.getAllByRole('button', { - name: '23', - })[0] - ); + await userEvent.click(within(hourList).getByText('23')); // Check the active day is the 5th expect(screen.getByRole('button', { name: 'May 5, 2021' })).toHaveClass('react-calendar__tile--active'); @@ -123,7 +116,6 @@ describe('Date time picker', () => { await userEvent.click(screen.getByRole('button', { name: 'May 15, 2021' })); const timeInput = screen.getAllByRole('textbox')[1]; - expect(timeInput).toHaveClass('rc-time-picker-input'); expect(timeInput).not.toHaveDisplayValue('00:00:00'); } ); @@ -216,9 +208,7 @@ describe('Date time picker', () => { await userEvent.click(screen.getAllByRole('textbox')[1]); // check the hour element is visible - const hourElement = screen.getAllByRole('button', { - name: '00', - })[0]; + const hourElement = screen.getAllByText('00')[0]; expect(hourElement).toBeVisible(); // select the hour value and check it's still visible @@ -227,11 +217,7 @@ describe('Date time picker', () => { // click outside the overlay and check the hour element is no longer visible await userEvent.click(document.body); - expect( - screen.queryByRole('button', { - name: '00', - }) - ).not.toBeInTheDocument(); + expect(screen.queryByText('00')).not.toBeInTheDocument(); } ); diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.story.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.story.tsx index bde38d03457..b75516367cc 100644 --- a/packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.story.tsx +++ b/packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.story.tsx @@ -24,7 +24,7 @@ export const Basic: StoryFn = (args) => { return ( { + onChange={(newValue?) => { action('on selected')(newValue); updateArgs({ value: newValue }); }} diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.tsx index 23e6e2d2870..4fbd2031927 100644 --- a/packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.tsx +++ b/packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.tsx @@ -1,5 +1,8 @@ import { css, cx } from '@emotion/css'; -import RcTimePicker from 'rc-time-picker'; +import { Moment } from 'moment'; +import RcPicker, { PickerProps } from 'rc-picker'; +import generateConfig from 'rc-picker/lib/generate/moment'; +import locale from 'rc-picker/lib/locale/en_US'; import { dateTime, DateTime, dateTimeAsMoment, GrafanaTheme2, isDateTimeInput } from '@grafana/data'; @@ -8,62 +11,102 @@ import { getFocusStyles } from '../../themes/mixins'; import { inputSizes } from '../Forms/commonStyles'; import { FormInputSize } from '../Forms/types'; import { Icon } from '../Icon/Icon'; +import 'rc-picker/assets/index.css'; -import 'rc-time-picker/assets/index.css'; - -export interface Props { - onChange: (value: DateTime) => void; +interface BaseProps { + onChange: (value: DateTime) => void | ((value?: DateTime) => void); value?: DateTime; showHour?: boolean; showSeconds?: boolean; - minuteStep?: number; + minuteStep?: PickerProps['minuteStep']; size?: FormInputSize; disabled?: boolean; disabledHours?: () => number[]; disabledMinutes?: () => number[]; disabledSeconds?: () => number[]; + placeholder?: string; + allowEmpty?: boolean; } +interface AllowEmptyProps extends BaseProps { + allowEmpty: true; + onChange: (value?: DateTime) => void; +} + +interface NoAllowEmptyProps extends BaseProps { + allowEmpty?: false; + onChange: (value: DateTime) => void; +} + +export type Props = AllowEmptyProps | NoAllowEmptyProps; + export const POPUP_CLASS_NAME = 'time-of-day-picker-panel'; export const TimeOfDayPicker = ({ minuteStep = 1, showHour = true, showSeconds = false, - onChange, value, size = 'auto', disabled, disabledHours, disabledMinutes, disabledSeconds, + placeholder, + // note: we can't destructure allowEmpty/onChange here + // in order to discriminate the types properly later in the onChange handler + ...restProps }: Props) => { const styles = useStyles2(getStyles); + const allowClear = restProps.allowEmpty ?? false; return ( - + generateConfig={generateConfig} + locale={locale} + allowClear={ + allowClear && { + clearIcon: , + } + } className={cx(inputSizes()[size], styles.input)} - popupClassName={cx(styles.picker, POPUP_CLASS_NAME)} - defaultValue={dateTimeAsMoment()} + classNames={{ + popup: cx(styles.picker, POPUP_CLASS_NAME), + }} + defaultValue={restProps.allowEmpty ? undefined : dateTimeAsMoment()} + disabled={disabled} + disabledTime={() => ({ + disabledHours, + disabledMinutes, + disabledSeconds, + })} + format={generateFormat(showHour, showSeconds)} + minuteStep={minuteStep} onChange={(value) => { if (isDateTimeInput(value)) { - return onChange(dateTime(value)); + if (restProps.allowEmpty) { + return restProps.onChange(value ? dateTime(value) : undefined); + } else { + return restProps.onChange(dateTime(value)); + } } }} - allowEmpty={false} - showSecond={showSeconds} - value={dateTimeAsMoment(value)} - showHour={showHour} - minuteStep={minuteStep} - inputIcon={} - disabled={disabled} - disabledHours={disabledHours} - disabledMinutes={disabledMinutes} - disabledSeconds={disabledSeconds} + picker="time" + placeholder={placeholder} + showNow={false} + needConfirm={false} + suffixIcon={} + value={value ? dateTimeAsMoment(value) : value} /> ); }; +function generateFormat(showHour = true, showSeconds = false) { + const maybeHour = showHour ? 'HH:' : ''; + const maybeSecond = showSeconds ? ':ss' : ''; + return maybeHour + 'mm' + maybeSecond; +} + interface CaretProps { wrapperStyle?: string; } @@ -78,31 +121,44 @@ const Caret = ({ wrapperStyle = '' }: CaretProps) => { const getStyles = (theme: GrafanaTheme2) => { const bgColor = theme.components.input.background; - const menuShadowColor = theme.v1.palette.black; - const optionBgHover = theme.colors.background.secondary; + const optionBgHover = theme.colors.action.hover; const borderRadius = theme.shape.radius.default; const borderColor = theme.components.input.borderColor; + return { caretWrapper: css({ - position: 'absolute', - right: '8px', + position: 'relative', top: '50%', transform: 'translateY(-50%)', display: 'inline-block', - textAlign: 'right', color: theme.colors.text.secondary, }), + clearIcon: css({ + color: theme.colors.text.secondary, + + '&:hover': { + color: theme.colors.text.maxContrast, + }, + }), picker: css({ - '.rc-time-picker-panel-select': { - fontSize: '14px', + '&.rc-picker-dropdown': { + boxShadow: 'none', + zIndex: theme.zIndex.portal, + }, + '.rc-picker-time-panel-column': { + fontSize: theme.typography.htmlFontSize, backgroundColor: bgColor, color: theme.colors.text.secondary, - borderColor, + padding: 'unset', + overflowY: 'auto', + scrollbarWidth: 'thin', + width: theme.spacing(8), li: { - outlineWidth: '2px', - '&.rc-time-picker-panel-select-option-selected': { + paddingRight: theme.spacing(2), + width: 'auto', + '&.rc-picker-time-panel-cell-selected': { backgroundColor: 'inherit', - border: `1px solid ${theme.v1.palette.orange}`, + border: `1px solid ${theme.colors.action.selectedBorder}`, borderRadius, color: theme.colors.text.primary, }, @@ -112,44 +168,37 @@ const getStyles = (theme: GrafanaTheme2) => { color: theme.colors.text.primary, }, - '&.rc-time-picker-panel-select-option-disabled': { + '&.rc-picker-time-panel-cell-disabled': { color: theme.colors.action.disabledText, }, }, + + '.rc-picker-time-panel-cell-inner': { + color: 'inherit', + }, + + '&:not(:last-of-type)': { + borderRight: `1px solid ${borderColor}`, + }, }, - '.rc-time-picker-panel-inner': { - boxShadow: `0px 4px 4px ${menuShadowColor}`, + '.rc-picker-panel': { + boxShadow: theme.shadows.z3, backgroundColor: bgColor, borderColor, borderRadius, - marginTop: '3px', - - '.rc-time-picker-panel-input-wrap': { - marginRight: '2px', - - '&, .rc-time-picker-panel-input': { - backgroundColor: bgColor, - paddingTop: '2px', - }, - }, - - '.rc-time-picker-panel-combobox': { - display: 'flex', - }, + overflow: 'hidden', }, }), input: css({ - '.rc-time-picker-input': { - backgroundColor: bgColor, - borderRadius, - borderColor, - color: theme.colors.text.primary, - height: theme.spacing(4), + '&.rc-picker-focused': { + border: 'none', - '&:focus': getFocusStyles(theme), + '.rc-picker-input': getFocusStyles(theme), + }, - '&:disabled': { + '&.rc-picker-disabled': { + '.rc-picker-input': { backgroundColor: theme.colors.action.disabledBackground, color: theme.colors.action.disabledText, border: `1px solid ${theme.colors.action.disabledBackground}`, @@ -158,6 +207,36 @@ const getStyles = (theme: GrafanaTheme2) => { }, }, }, + + '.rc-picker-input': { + backgroundColor: bgColor, + borderRadius, + borderColor, + borderStyle: 'solid', + borderWidth: '1px', + color: theme.colors.text.primary, + height: theme.spacing(4), + padding: theme.spacing(0, 1), + + input: { + color: 'unset', + backgroundColor: 'unset', + '&:focus': { + outline: 'none', + }, + + '&::placeholder': { + color: theme.colors.text.disabled, + }, + }, + }, + + '.rc-picker-clear': { + alignItems: 'center', + display: 'flex', + insetInlineEnd: 'unset', + position: 'relative', + }, }), }; }; diff --git a/packages/grafana-ui/src/themes/GlobalStyles/GlobalStyles.tsx b/packages/grafana-ui/src/themes/GlobalStyles/GlobalStyles.tsx index 0aacc8db438..12e094433d2 100644 --- a/packages/grafana-ui/src/themes/GlobalStyles/GlobalStyles.tsx +++ b/packages/grafana-ui/src/themes/GlobalStyles/GlobalStyles.tsx @@ -19,7 +19,6 @@ import { getLegacySelectStyles } from './legacySelect'; import { getMarkdownStyles } from './markdownStyles'; import { getPageStyles } from './page'; import { getQueryEditorStyles } from './queryEditor'; -import { getRcTimePickerStyles } from './rcTimePicker'; import { getSkeletonStyles } from './skeletonStyles'; import { getSlateStyles } from './slate'; import { getUplotStyles } from './uPlot'; @@ -48,7 +47,6 @@ export function GlobalStyles() { getMarkdownStyles(theme), getPageStyles(theme), getQueryEditorStyles(theme), - getRcTimePickerStyles(theme), getSkeletonStyles(theme), getSlateStyles(theme), getUplotStyles(theme), diff --git a/packages/grafana-ui/src/themes/GlobalStyles/rcTimePicker.ts b/packages/grafana-ui/src/themes/GlobalStyles/rcTimePicker.ts deleted file mode 100644 index 36df58946b6..00000000000 --- a/packages/grafana-ui/src/themes/GlobalStyles/rcTimePicker.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { css } from '@emotion/react'; - -import { GrafanaTheme2 } from '@grafana/data'; - -export function getRcTimePickerStyles(theme: GrafanaTheme2) { - return css({ - '.rc-time-picker-input,.rc-time-picker-panel-input-wrap,.rc-time-picker-panel-inner': { - backgroundColor: theme.components.input.background, - color: theme.colors.text.secondary, - borderColor: theme.components.input.borderColor, - fontSize: theme.typography.body.fontSize, - }, - - '.rc-time-picker-input': { - padding: theme.spacing(0, 1), - height: theme.spacing(4), - }, - - '.rc-time-picker-panel': { - width: '176px', - }, - - '.rc-time-picker-panel-select': { - width: '50%', - - '&:only-child': { - width: '100%', - }, - - '.rc-time-picker-panel-select-option-selected': { - backgroundColor: theme.colors.background.secondary, - }, - - 'li:hover': { - backgroundColor: theme.colors.background.secondary, - }, - }, - - '.rc-time-picker-panel-narrow': { - maxWidth: 'none', - }, - }); -} diff --git a/public/app/plugins/datasource/grafana/components/TimePickerInput.tsx b/public/app/plugins/datasource/grafana/components/TimePickerInput.tsx deleted file mode 100644 index 7526c5f0a9a..00000000000 --- a/public/app/plugins/datasource/grafana/components/TimePickerInput.tsx +++ /dev/null @@ -1,185 +0,0 @@ -import { css, cx } from '@emotion/css'; -import { Moment } from 'moment'; -import TimePicker from 'rc-time-picker'; - -import { GrafanaTheme2 } from '@grafana/data'; -import { FormInputSize, Icon, useStyles2 } from '@grafana/ui'; -import { inputSizes } from '@grafana/ui/src/components/Forms/commonStyles'; -import { getFocusStyles } from '@grafana/ui/src/themes/mixins'; - -export interface Props { - onChange: (value: Moment) => void; - value?: Moment; - defaultValue?: Moment; - showHour?: boolean; - showSeconds?: boolean; - minuteStep?: number; - size?: FormInputSize; - disabled?: boolean; - disabledHours?: () => number[]; - disabledMinutes?: () => number[]; - disabledSeconds?: () => number[]; - placeholder?: string; - format?: string; - allowEmpty?: boolean; - width?: number; -} - -export const POPUP_CLASS_NAME = 'time-of-day-picker-panel'; - -// @TODO fix TimeOfDayPicker and switch? -export const TimePickerInput = ({ - minuteStep = 1, - showHour = true, - showSeconds = false, - onChange, - value, - size = 'auto', - disabled, - disabledHours, - disabledMinutes, - disabledSeconds, - placeholder, - format = 'HH:mm', - defaultValue = undefined, - allowEmpty = false, - width, -}: Props) => { - const styles = useStyles2(getStyles); - - const getWidth = () => { - if (width) { - return css({ - width: `${width}px`, - }); - } - - return inputSizes()[size]; - }; - - return ( - onChange(v)} - showHour={showHour} - showSecond={showSeconds} - format={format} - allowEmpty={allowEmpty} - className={cx(getWidth(), styles.input)} - popupClassName={cx(styles.picker, POPUP_CLASS_NAME)} - minuteStep={minuteStep} - inputIcon={} - disabled={disabled} - disabledHours={disabledHours} - disabledMinutes={disabledMinutes} - disabledSeconds={disabledSeconds} - placeholder={placeholder} - /> - ); -}; - -interface CaretProps { - wrapperStyle?: string; -} - -const Caret = ({ wrapperStyle = '' }: CaretProps) => { - return ( -
- -
- ); -}; - -const getStyles = (theme: GrafanaTheme2) => { - const bgColor = theme.components.input.background; - const menuShadowColor = theme.v1.palette.black; - const optionBgHover = theme.colors.background.secondary; - const borderRadius = theme.shape.radius.default; - const borderColor = theme.components.input.borderColor; - - return { - caretWrapper: css({ - position: 'absolute', - right: '8px', - top: '50%', - transform: 'translateY(-50%)', - display: 'inline-block', - textAlign: 'right', - color: theme.colors.text.secondary, - }), - picker: css({ - '.rc-time-picker-panel-select': { - fontSize: '14px', - backgroundColor: bgColor, - borderColor: borderColor, - li: { - outlineWidth: '2px', - '&.rc-time-picker-panel-select-option-selected': { - backgroundColor: 'inherit', - border: `1px solid ${theme.v1.palette.orange}`, - borderRadius: borderRadius, - }, - - '&:hover': { - background: optionBgHover, - }, - - '&.rc-time-picker-panel-select-option-disabled': { - color: theme.colors.action.disabledText, - }, - }, - }, - - '.rc-time-picker-panel-inner': { - boxShadow: `0px 4px 4px ${menuShadowColor}`, - backgroundColor: bgColor, - borderColor: borderColor, - borderRadius: borderRadius, - marginTop: '3px', - - '.rc-time-picker-panel-input-wrap': { - marginRight: '2px', - - '&, .rc-time-picker-panel-input': { - backgroundColor: bgColor, - paddingTop: '2px', - }, - }, - - '.rc-time-picker-panel-combobox': { - display: 'flex', - }, - }, - }), - input: css({ - '.rc-time-picker-input': { - backgroundColor: bgColor, - borderRadius: borderRadius, - borderColor: borderColor, - height: theme.spacing(4), - - '&:focus': getFocusStyles(theme), - - '&:disabled': { - backgroundColor: theme.colors.action.disabledBackground, - color: theme.colors.action.disabledText, - border: `1px solid ${theme.colors.action.disabledBackground}`, - '&:focus': { - boxShadow: 'none', - }, - }, - }, - - '.rc-time-picker-clear': { - position: 'absolute', - right: '20px', - top: '50%', - cursor: 'pointer', - overflow: 'hidden', - transform: 'translateY(-50%)', - color: theme.colors.text.secondary, - }, - }), - }; -}; diff --git a/public/app/plugins/datasource/grafana/components/TimeRegionEditor.tsx b/public/app/plugins/datasource/grafana/components/TimeRegionEditor.tsx index 6fdec781340..9ba25879675 100644 --- a/public/app/plugins/datasource/grafana/components/TimeRegionEditor.tsx +++ b/public/app/plugins/datasource/grafana/components/TimeRegionEditor.tsx @@ -2,15 +2,13 @@ import { css } from '@emotion/css'; import moment, { Moment } from 'moment/moment'; import { useState } from 'react'; -import { getTimeZoneInfo, GrafanaTheme2, SelectableValue } from '@grafana/data'; -import { Button, Field, FieldSet, Select, Stack, TimeZonePicker, useStyles2 } from '@grafana/ui'; +import { dateTimeAsMoment, getTimeZoneInfo, GrafanaTheme2, isDateTime, SelectableValue } from '@grafana/data'; +import { Button, Field, FieldSet, Select, Stack, TimeOfDayPicker, TimeZonePicker, useStyles2 } from '@grafana/ui'; import { TimeZoneOffset } from '@grafana/ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneOffset'; import { TimeZoneTitle } from '@grafana/ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneTitle'; import { TimeRegionConfig } from 'app/core/utils/timeRegions'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; -import { TimePickerInput } from './TimePickerInput'; - interface Props { value: TimeRegionConfig; onChange: (value?: TimeRegionConfig) => void; @@ -74,7 +72,7 @@ export const TimeRegionEditor = ({ value, onChange }: Props) => { return timezone; }; - const onTimeChange = (v: Moment, field: string) => { + const onTimeChange = (v: Moment | undefined, field: string) => { const time = v ? v.format('HH:mm') : undefined; if (field === 'from') { onChange({ ...value, from: time }); @@ -122,6 +120,9 @@ export const TimeRegionEditor = ({ value, onChange }: Props) => { ); }; + const from = getTime(value.from); + const to = getTime(value.to); + return (
@@ -134,12 +135,12 @@ export const TimeRegionEditor = ({ value, onChange }: Props) => { onChange={(v) => onFromDayOfWeekChange(v)} width={20} /> - onTimeChange(v, 'from')} + onTimeChange(v ? dateTimeAsMoment(v) : v, 'from')} allowEmpty={true} placeholder="HH:mm" - width={100} + size="sm" /> @@ -155,12 +156,12 @@ export const TimeRegionEditor = ({ value, onChange }: Props) => { width={20} /> )} - onTimeChange(v, 'to')} + onTimeChange(v ? dateTimeAsMoment(v) : v, 'to')} allowEmpty={true} placeholder="HH:mm" - width={100} + size="sm" /> diff --git a/yarn.lock b/yarn.lock index d5581c46a4f..f44165df0ff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1438,7 +1438,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:7.26.0, @babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.11.1, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.14.0, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.0, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.24.1, @babel/runtime@npm:^7.24.5, @babel/runtime@npm:^7.25.0, @babel/runtime@npm:^7.25.6, @babel/runtime@npm:^7.25.7, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7": +"@babel/runtime@npm:7.26.0, @babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.11.1, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.14.0, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.0, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.24.1, @babel/runtime@npm:^7.24.5, @babel/runtime@npm:^7.24.7, @babel/runtime@npm:^7.25.0, @babel/runtime@npm:^7.25.6, @babel/runtime@npm:^7.25.7, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7": version: 7.26.0 resolution: "@babel/runtime@npm:7.26.0" dependencies: @@ -3895,8 +3895,8 @@ __metadata: process: "npm:^0.11.10" rc-cascader: "npm:3.33.0" rc-drawer: "npm:7.2.0" + rc-picker: "npm:4.9.2" rc-slider: "npm:11.1.8" - rc-time-picker: "npm:^3.7.3" rc-tooltip: "npm:6.4.0" react: "npm:18.2.0" react-calendar: "npm:^5.1.0" @@ -11522,16 +11522,6 @@ __metadata: languageName: node linkType: hard -"babel-runtime@npm:6.x, babel-runtime@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-runtime@npm:6.26.0" - dependencies: - core-js: "npm:^2.4.0" - regenerator-runtime: "npm:^0.11.0" - checksum: 10/2cdf0f083b9598a43cdb11cbf1e7060584079a9a2230f06aec997ba81e887ef17fdcb5ad813a484ee099e06d2de0cea832bdd3011c06325acb284284c754ee8f - languageName: node - linkType: hard - "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" @@ -12819,22 +12809,6 @@ __metadata: languageName: node linkType: hard -"component-classes@npm:^1.2.5": - version: 1.2.6 - resolution: "component-classes@npm:1.2.6" - dependencies: - component-indexof: "npm:0.0.3" - checksum: 10/aa70f282b85a19d7a190dabb2c72c9b8a2a5565fc42d72ca0661e8ce47e55e53da29f468467771d7e0bf4ba8c9723e5a21954fc38b942d9d873ee56be856adfc - languageName: node - linkType: hard - -"component-indexof@npm:0.0.3": - version: 0.0.3 - resolution: "component-indexof@npm:0.0.3" - checksum: 10/34a720e96fc0be1043a4517845b1b7483989736c559089eca285f7ac9ef049eacc8ab12fc31f924dfa2d4ecea0714611a695d087ce11caf30502b5a80646e9e9 - languageName: node - linkType: hard - "compressible@npm:~2.0.16": version: 2.0.18 resolution: "compressible@npm:2.0.18" @@ -13126,7 +13100,7 @@ __metadata: languageName: node linkType: hard -"core-js@npm:^2.4.0, core-js@npm:^2.6.5": +"core-js@npm:^2.6.5": version: 2.6.12 resolution: "core-js@npm:2.6.12" checksum: 10/7c624eb00a59c74c769d5d80f751f3bf1fc6201205b6562f27286ad5e00bbca1483f2f7eb0c2854b86f526ef5c7dc958b45f2ff536f8a31b8e9cb1a13a96efca @@ -13298,16 +13272,6 @@ __metadata: languageName: node linkType: hard -"css-animation@npm:^1.3.2": - version: 1.6.1 - resolution: "css-animation@npm:1.6.1" - dependencies: - babel-runtime: "npm:6.x" - component-classes: "npm:^1.2.5" - checksum: 10/5aea8fd333300c6b15f523ac741dd2ed367489485c7a9a43647f7779fef9e5f338c405e3ad9ed8db338503b4aefea86108112a01bf78651b623f8bd2e146e0e0 - languageName: node - linkType: hard - "css-box-model@npm:^1.2.1": version: 1.2.1 resolution: "css-box-model@npm:1.2.1" @@ -17642,7 +17606,6 @@ __metadata: prismjs: "npm:1.29.0" pseudoizer: "npm:^0.1.0" rc-slider: "npm:11.1.8" - rc-time-picker: "npm:3.7.3" rc-tree: "npm:5.13.0" re-resizable: "npm:6.10.3" react: "npm:18.2.0" @@ -22053,7 +22016,7 @@ __metadata: languageName: node linkType: hard -"moment@npm:2.30.1, moment@npm:2.x, moment@npm:^2.20.1, moment@npm:^2.29.4, moment@npm:^2.30.1": +"moment@npm:2.30.1, moment@npm:^2.20.1, moment@npm:^2.29.4, moment@npm:^2.30.1": version: 2.30.1 resolution: "moment@npm:2.30.1" checksum: 10/ae42d876d4ec831ef66110bdc302c0657c664991e45cf2afffc4b0f6cd6d251dde11375c982a5c0564ccc0fa593fc564576ddceb8c8845e87c15f58aa6baca69 @@ -24710,7 +24673,7 @@ __metadata: languageName: node linkType: hard -"raf@npm:^3.1.0, raf@npm:^3.4.0, raf@npm:^3.4.1": +"raf@npm:^3.1.0, raf@npm:^3.4.1": version: 3.4.1 resolution: "raf@npm:3.4.1" dependencies: @@ -24792,18 +24755,6 @@ __metadata: languageName: node linkType: hard -"rc-align@npm:^2.4.0": - version: 2.4.5 - resolution: "rc-align@npm:2.4.5" - dependencies: - babel-runtime: "npm:^6.26.0" - dom-align: "npm:^1.7.0" - prop-types: "npm:^15.5.8" - rc-util: "npm:^4.0.4" - checksum: 10/6a82f7b47dda397b90c7b6d41e5500b9e3e427891d15a54f95708abf31a8aba19d882bd9e5ab42f4979b455aa2236b96cf6403152507bcd1fd7663be08a0ceb5 - languageName: node - linkType: hard - "rc-align@npm:^4.0.0": version: 4.0.15 resolution: "rc-align@npm:4.0.15" @@ -24820,21 +24771,6 @@ __metadata: languageName: node linkType: hard -"rc-animate@npm:2.x": - version: 2.11.1 - resolution: "rc-animate@npm:2.11.1" - dependencies: - babel-runtime: "npm:6.x" - classnames: "npm:^2.2.6" - css-animation: "npm:^1.3.2" - prop-types: "npm:15.x" - raf: "npm:^3.4.0" - rc-util: "npm:^4.15.3" - react-lifecycles-compat: "npm:^3.0.4" - checksum: 10/afb54ad896c9d50af212ae7a56a216b47b38238a4e8e187437fe965c2cf100f1ca82668ed90d38dcd3b0e3ced53f54383e417af09c6dc09f6db0f78cba2aa9e4 - languageName: node - linkType: hard - "rc-cascader@npm:1.0.1": version: 1.0.1 resolution: "rc-cascader@npm:1.0.1" @@ -24926,6 +24862,51 @@ __metadata: languageName: node linkType: hard +"rc-overflow@npm:^1.3.2": + version: 1.4.1 + resolution: "rc-overflow@npm:1.4.1" + dependencies: + "@babel/runtime": "npm:^7.11.1" + classnames: "npm:^2.2.1" + rc-resize-observer: "npm:^1.0.0" + rc-util: "npm:^5.37.0" + peerDependencies: + react: ">=16.9.0" + react-dom: ">=16.9.0" + checksum: 10/c5f1daf4ed74ff4d76d593237233a28260d48170deaa87e48b552c0a60ed9cffd23be78bf04472b98da91c2a17f8182589aff7a865c2d66a04731bab6455d216 + languageName: node + linkType: hard + +"rc-picker@npm:4.9.2": + version: 4.9.2 + resolution: "rc-picker@npm:4.9.2" + dependencies: + "@babel/runtime": "npm:^7.24.7" + "@rc-component/trigger": "npm:^2.0.0" + classnames: "npm:^2.2.1" + rc-overflow: "npm:^1.3.2" + rc-resize-observer: "npm:^1.4.0" + rc-util: "npm:^5.43.0" + peerDependencies: + date-fns: ">= 2.x" + dayjs: ">= 1.x" + luxon: ">= 3.x" + moment: ">= 2.x" + react: ">=16.9.0" + react-dom: ">=16.9.0" + peerDependenciesMeta: + date-fns: + optional: true + dayjs: + optional: true + luxon: + optional: true + moment: + optional: true + checksum: 10/5bf0abec3b0fc778a8b0d64023d395f22692b910ead0e63b1f9b941ee510769c814525733bf9084d504567aa449fa50c4dafb18ae95b8e1a291c857e535aeb28 + languageName: node + linkType: hard + "rc-resize-observer@npm:^1.0.0, rc-resize-observer@npm:^1.3.1": version: 1.3.1 resolution: "rc-resize-observer@npm:1.3.1" @@ -24941,6 +24922,21 @@ __metadata: languageName: node linkType: hard +"rc-resize-observer@npm:^1.4.0": + version: 1.4.3 + resolution: "rc-resize-observer@npm:1.4.3" + dependencies: + "@babel/runtime": "npm:^7.20.7" + classnames: "npm:^2.2.1" + rc-util: "npm:^5.44.1" + resize-observer-polyfill: "npm:^1.5.1" + peerDependencies: + react: ">=16.9.0" + react-dom: ">=16.9.0" + checksum: 10/aff63c93e811440617d0d2c628a8c1b5e2516e5a26e2d8fc99560fd822d06b9de56cd826fb64b094fc3dc8e926e60e2e38bf594134b17a5024c61cd5a406e4cd + languageName: node + linkType: hard + "rc-select@npm:~14.16.2": version: 14.16.3 resolution: "rc-select@npm:14.16.3" @@ -24973,20 +24969,6 @@ __metadata: languageName: node linkType: hard -"rc-time-picker@npm:3.7.3, rc-time-picker@npm:^3.7.3": - version: 3.7.3 - resolution: "rc-time-picker@npm:3.7.3" - dependencies: - classnames: "npm:2.x" - moment: "npm:2.x" - prop-types: "npm:^15.5.8" - raf: "npm:^3.4.1" - rc-trigger: "npm:^2.2.0" - react-lifecycles-compat: "npm:^3.0.4" - checksum: 10/236ba0dd1b1cee4dd398d2542c251a7e0da21b31d3390a23c45cc7f2ea266cfddd1f0b7f681fe205f2d92edaa72771cb087505790b5124eb0ca31668feb74da5 - languageName: node - linkType: hard - "rc-tooltip@npm:6.4.0": version: 6.4.0 resolution: "rc-tooltip@npm:6.4.0" @@ -25018,21 +25000,6 @@ __metadata: languageName: node linkType: hard -"rc-trigger@npm:^2.2.0": - version: 2.6.5 - resolution: "rc-trigger@npm:2.6.5" - dependencies: - babel-runtime: "npm:6.x" - classnames: "npm:^2.2.6" - prop-types: "npm:15.x" - rc-align: "npm:^2.4.0" - rc-animate: "npm:2.x" - rc-util: "npm:^4.4.0" - react-lifecycles-compat: "npm:^3.0.4" - checksum: 10/a3ed5f0c453a37ab00fce302e9f40daa64870eb001576a3409a94550802af1e01cbd7b050b3adf7225af03e82e2070d095477957fcd07209ee32602a2f3fba31 - languageName: node - linkType: hard - "rc-trigger@npm:^4.0.0": version: 4.4.3 resolution: "rc-trigger@npm:4.4.3" @@ -25047,7 +25014,7 @@ __metadata: languageName: node linkType: hard -"rc-util@npm:^4.0.4, rc-util@npm:^4.15.3, rc-util@npm:^4.4.0": +"rc-util@npm:^4.0.4": version: 4.21.1 resolution: "rc-util@npm:4.21.1" dependencies: @@ -25060,7 +25027,7 @@ __metadata: languageName: node linkType: hard -"rc-util@npm:^5.0.1, rc-util@npm:^5.0.6, rc-util@npm:^5.15.0, rc-util@npm:^5.16.1, rc-util@npm:^5.21.0, rc-util@npm:^5.24.4, rc-util@npm:^5.26.0, rc-util@npm:^5.27.0, rc-util@npm:^5.36.0, rc-util@npm:^5.37.0, rc-util@npm:^5.38.0, rc-util@npm:^5.38.1, rc-util@npm:^5.43.0, rc-util@npm:^5.44.3": +"rc-util@npm:^5.0.1, rc-util@npm:^5.0.6, rc-util@npm:^5.15.0, rc-util@npm:^5.16.1, rc-util@npm:^5.21.0, rc-util@npm:^5.24.4, rc-util@npm:^5.26.0, rc-util@npm:^5.27.0, rc-util@npm:^5.36.0, rc-util@npm:^5.37.0, rc-util@npm:^5.38.0, rc-util@npm:^5.38.1, rc-util@npm:^5.43.0, rc-util@npm:^5.44.1, rc-util@npm:^5.44.3": version: 5.44.3 resolution: "rc-util@npm:5.44.3" dependencies: @@ -26248,13 +26215,6 @@ __metadata: languageName: node linkType: hard -"regenerator-runtime@npm:^0.11.0": - version: 0.11.1 - resolution: "regenerator-runtime@npm:0.11.1" - checksum: 10/64e62d78594c227e7d5269811bca9e4aa6451332adaae8c79a30cab0fa98733b1ad90bdb9d038095c340c6fad3b414a49a8d9e0b6b424ab7ff8f94f35704f8a2 - languageName: node - linkType: hard - "regenerator-runtime@npm:^0.13.4, regenerator-runtime@npm:^0.13.7": version: 0.13.11 resolution: "regenerator-runtime@npm:0.13.11" From 1eb45dd0f80e86bc78bb96977de9a9e03da8ab7a Mon Sep 17 00:00:00 2001 From: Brendan O'Handley Date: Thu, 16 Jan 2025 10:00:39 -0600 Subject: [PATCH 16/30] Explore metrics: Do not show otel switch in related metrics tab (#99054) do not show otel switch in related metrics tab --- public/app/features/trails/MetricSelect/MetricSelectScene.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/app/features/trails/MetricSelect/MetricSelectScene.tsx b/public/app/features/trails/MetricSelect/MetricSelectScene.tsx index ce3d0c86dd3..99fcd423fe7 100644 --- a/public/app/features/trails/MetricSelect/MetricSelectScene.tsx +++ b/public/app/features/trails/MetricSelect/MetricSelectScene.tsx @@ -512,7 +512,7 @@ export class MetricSelectScene extends SceneObjectBase i const [warningDismissed, dismissWarning] = useReducer(() => true, false); - const { metricSearch, useOtelExperience, hasOtelResources, isStandardOtel } = trail.useState(); + const { metricSearch, useOtelExperience, hasOtelResources, isStandardOtel, metric } = trail.useState(); const tooStrict = children.length === 0 && metricSearch; const noMetrics = !metricNamesLoading && metricNames && metricNames.length === 0; @@ -573,7 +573,7 @@ export class MetricSelectScene extends SceneObjectBase i ]} /> - {hasOtelResources && ( + {!metric && hasOtelResources && ( From c0b3932168f488c883a39ad68b5628709fa06b6d Mon Sep 17 00:00:00 2001 From: kay delaney <45561153+kaydelaney@users.noreply.github.com> Date: Thu, 16 Jan 2025 16:07:57 +0000 Subject: [PATCH 17/30] Graphite: Fix issue where duplicated panels share same query object (#99077) --- public/app/plugins/datasource/graphite/state/context.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/plugins/datasource/graphite/state/context.tsx b/public/app/plugins/datasource/graphite/state/context.tsx index a15853875a7..1a9aa76b37b 100644 --- a/public/app/plugins/datasource/graphite/state/context.tsx +++ b/public/app/plugins/datasource/graphite/state/context.tsx @@ -88,7 +88,7 @@ export const GraphiteQueryEditorContext = ({ if (!state) { dispatch( actions.init({ - target: query, + target: { ...query }, datasource: datasource, range: range, templateSrv: getTemplateSrv(), From e96b5a68c4faedb314659d3051180a73cc262a17 Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Thu, 16 Jan 2025 17:11:44 +0100 Subject: [PATCH 18/30] Prometheus: Support utf8 metrics and labels in scopes (#99015) * support utf8 in scopes * separate the utf8 tests * remove redundant test after enabling utf8 validation in prometheus --- pkg/promlib/models/scope.go | 5 + pkg/promlib/models/scope_test.go | 138 +++++++++++++++++- pkg/services/ngalert/store/alert_rule_test.go | 9 -- 3 files changed, 141 insertions(+), 11 deletions(-) diff --git a/pkg/promlib/models/scope.go b/pkg/promlib/models/scope.go index 41fbbb43444..767a98a854e 100644 --- a/pkg/promlib/models/scope.go +++ b/pkg/promlib/models/scope.go @@ -4,10 +4,15 @@ import ( "fmt" "strings" + "github.com/prometheus/common/model" "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/promql/parser" ) +func init() { + model.NameValidationScheme = model.UTF8Validation +} + // ApplyFiltersAndGroupBy takes a raw promQL expression, converts the filters into PromQL matchers, and applies these matchers to the parsed expression. It also applies the group by clause to any aggregate expressions in the parsed expression. func ApplyFiltersAndGroupBy(rawExpr string, scopeFilters, adHocFilters []ScopeFilter, groupBy []string) (string, error) { expr, err := parser.ParseExpr(rawExpr) diff --git a/pkg/promlib/models/scope_test.go b/pkg/promlib/models/scope_test.go index fc7d972eb44..fb6d5f4c1a3 100644 --- a/pkg/promlib/models/scope_test.go +++ b/pkg/promlib/models/scope_test.go @@ -145,6 +145,37 @@ func TestApplyQueryFiltersAndGroupBy_Filters(t *testing.T) { } } +func TestApplyQueryFiltersAndGroupBy_Filters_utf8(t *testing.T) { + tests := []struct { + name string + query string + adhocFilters []ScopeFilter + scopeFilters []ScopeFilter + expected string + expectErr bool + }{ + { + name: "No filters with existing utf8 filter", + query: `http_requests_total{"job.name"="prometheus"}`, + expected: `http_requests_total{"job.name"="prometheus"}`, + expectErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + expr, err := ApplyFiltersAndGroupBy(tt.query, tt.scopeFilters, tt.adhocFilters, nil) + + if tt.expectErr { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tt.expected, expr, tt.name) + } + }) + } +} + func TestApplyQueryFiltersAndGroupBy_GroupBy(t *testing.T) { tests := []struct { name string @@ -197,7 +228,45 @@ func TestApplyQueryFiltersAndGroupBy_GroupBy(t *testing.T) { require.Error(t, err) } else { require.NoError(t, err) - require.Equal(t, expr, tt.expected) + require.Equal(t, tt.expected, expr) + } + }) + } +} + +func TestApplyQueryFiltersAndGroupBy_GroupBy_utf8(t *testing.T) { + tests := []struct { + name string + query string + groupBy []string + expected string + expectErr bool + }{ + { + name: "GroupBy with no aggregate expression and utf8 metric", + groupBy: []string{"job"}, + query: `{"http.requests_total"}`, + expected: `{__name__="http.requests_total"}`, + expectErr: false, + }, + { + name: "GroupBy with aggregate expression with existing utf8 group by", + groupBy: []string{"status"}, + query: `sum by ("utf8.job") (http_requests_total)`, + expected: `sum by ("utf8.job", status) (http_requests_total)`, + expectErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + expr, err := ApplyFiltersAndGroupBy(tt.query, nil, nil, tt.groupBy) + + if tt.expectErr { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tt.expected, expr) } }) } @@ -237,7 +306,72 @@ func TestApplyQueryFiltersAndGroupBy(t *testing.T) { require.Error(t, err) } else { require.NoError(t, err) - require.Equal(t, expr, tt.expected) + require.Equal(t, tt.expected, expr) + } + }) + } +} + +func TestApplyQueryFiltersAndGroupBy_utf8(t *testing.T) { + tests := []struct { + name string + query string + adhocFilters []ScopeFilter + scopeFilters []ScopeFilter + groupby []string + expected string + expectErr bool + }{ + { + name: "Adhoc filters with more complex expression and utf8 metric name", + query: `sum({"capacity_bytes", job="prometheus"} + {"available_bytes", job="grafana"}) / 1024`, + adhocFilters: []ScopeFilter{ + {Key: "job", Value: "alloy", Operator: FilterOperatorEquals}, + }, + scopeFilters: []ScopeFilter{ + {Key: "vol", Value: "/", Operator: FilterOperatorEquals}, + }, + groupby: []string{"job"}, + expected: `sum by (job) ({__name__="capacity_bytes",job="alloy",vol="/"} + {__name__="available_bytes",job="alloy",vol="/"}) / 1024`, + expectErr: false, + }, + { + name: "Adhoc filters with more complex expression with utf8 label", + query: `sum(capacity_bytes{job="prometheus", "utf8.label"="value"} + available_bytes{job="grafana"}) / 1024`, + adhocFilters: []ScopeFilter{ + {Key: "job", Value: "alloy", Operator: FilterOperatorEquals}, + }, + scopeFilters: []ScopeFilter{ + {Key: "vol", Value: "/", Operator: FilterOperatorEquals}, + }, + groupby: []string{"job"}, + expected: `sum by (job) (capacity_bytes{"utf8.label"="value",job="alloy",vol="/"} + available_bytes{job="alloy",vol="/"}) / 1024`, + expectErr: false, + }, + { + name: "Adhoc filters with more complex expression with utf8 metric and label", + query: `sum({"capacity_bytes", job="prometheus", "utf8.label"="value"} + available_bytes{job="grafana"}) / 1024`, + adhocFilters: []ScopeFilter{ + {Key: "job", Value: "alloy", Operator: FilterOperatorEquals}, + }, + scopeFilters: []ScopeFilter{ + {Key: "vol", Value: "/", Operator: FilterOperatorEquals}, + }, + groupby: []string{"job"}, + expected: `sum by (job) ({"utf8.label"="value",__name__="capacity_bytes",job="alloy",vol="/"} + available_bytes{job="alloy",vol="/"}) / 1024`, + expectErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + expr, err := ApplyFiltersAndGroupBy(tt.query, tt.scopeFilters, tt.adhocFilters, tt.groupby) + + if tt.expectErr { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tt.expected, expr) } }) } diff --git a/pkg/services/ngalert/store/alert_rule_test.go b/pkg/services/ngalert/store/alert_rule_test.go index 2ccfd9ee5f1..dd55c5df488 100644 --- a/pkg/services/ngalert/store/alert_rule_test.go +++ b/pkg/services/ngalert/store/alert_rule_test.go @@ -785,15 +785,6 @@ func TestIntegrationInsertAlertRules(t *testing.T) { require.ErrorIs(t, err, models.ErrAlertRuleFailedValidation) require.ErrorContains(t, err, "metric name for recording rule must be a valid utf8 string") }) - - t.Run("invalid metric name", func(t *testing.T) { - invalidMetric := "with-dashes" - invalidRule := recordingRulesGen.Generate() - invalidRule.Record.Metric = invalidMetric - _, err := store.InsertAlertRules(context.Background(), []models.AlertRule{invalidRule}) - require.ErrorIs(t, err, models.ErrAlertRuleFailedValidation) - require.ErrorContains(t, err, "metric name for recording rule must be a valid Prometheus metric name") - }) }) t.Run("clears fields that should not exist on recording rules", func(t *testing.T) { From 54440811b351a8ceafb224284f8fa0ed2ae814e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20Rodr=C3=ADguez?= Date: Thu, 16 Jan 2025 17:32:13 +0100 Subject: [PATCH 19/30] Add DynamoDB to unconfirmed list (#99087) --- .../share-dashboards-panels/shared-dashboards/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/sources/dashboards/share-dashboards-panels/shared-dashboards/index.md b/docs/sources/dashboards/share-dashboards-panels/shared-dashboards/index.md index f30bcd6337e..63dc3b499e3 100644 --- a/docs/sources/dashboards/share-dashboards-panels/shared-dashboards/index.md +++ b/docs/sources/dashboards/share-dashboards-panels/shared-dashboards/index.md @@ -266,6 +266,7 @@ guaranteed because plugin developers can override this functionality. The follow - Datadog - Dataset - Druid +- DynamoDB - GitHub - Google BigQuery - Grafana for YNAB From 8e59f618c11e72bdf190c64d1e237a6dd92e09f7 Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Thu, 16 Jan 2025 16:54:16 +0000 Subject: [PATCH 20/30] CodeEditor: Fix cursor alignment (#99090) * remeasure fonts once they've loaded * add test mock * fix unit test * remeasure fonts after the editor has mounted just to be safe --- .../src/components/Monaco/ReactMonacoEditor.tsx | 11 ++++++++++- .../plugins/panel/datagrid/DataGridPanel.test.tsx | 12 +++++++----- public/test/jest-setup.ts | 3 +++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/packages/grafana-ui/src/components/Monaco/ReactMonacoEditor.tsx b/packages/grafana-ui/src/components/Monaco/ReactMonacoEditor.tsx index 2a5dfa1ea85..2d095d6d182 100644 --- a/packages/grafana-ui/src/components/Monaco/ReactMonacoEditor.tsx +++ b/packages/grafana-ui/src/components/Monaco/ReactMonacoEditor.tsx @@ -11,7 +11,7 @@ import type { ReactMonacoEditorProps } from './types'; monacoEditorLoader.config({ monaco }); export const ReactMonacoEditor = (props: ReactMonacoEditorProps) => { - const { beforeMount, options, ...restProps } = props; + const { beforeMount, onMount, options, ...restProps } = props; const theme = useTheme2(); const onMonacoBeforeMount = useCallback( @@ -31,6 +31,15 @@ export const ReactMonacoEditor = (props: ReactMonacoEditorProps) => { }} theme={theme.isDark ? 'grafana-dark' : 'grafana-light'} beforeMount={onMonacoBeforeMount} + onMount={(editor, monaco) => { + // we use a custom font in our monaco editor + // we need monaco to remeasure the fonts after they are loaded to prevent alignment issues + // see https://github.com/microsoft/monaco-editor/issues/648#issuecomment-564978560 + document.fonts.ready.then(() => { + monaco.editor.remeasureFonts(); + }); + onMount?.(editor, monaco); + }} /> ); }; diff --git a/public/app/plugins/panel/datagrid/DataGridPanel.test.tsx b/public/app/plugins/panel/datagrid/DataGridPanel.test.tsx index 79651066698..d08e7f2be33 100644 --- a/public/app/plugins/panel/datagrid/DataGridPanel.test.tsx +++ b/public/app/plugins/panel/datagrid/DataGridPanel.test.tsx @@ -59,15 +59,17 @@ describe('DataGrid', () => { jest.clearAllMocks(); }); - it('converts dataframe values to cell values properly', () => { + it('converts dataframe values to cell values properly', async () => { jest.useFakeTimers(); render(); prep(false); - expect(screen.getByTestId('glide-cell-1-0')).toHaveTextContent('1'); - expect(screen.getByTestId('glide-cell-2-1')).toHaveTextContent('b'); - expect(screen.getByTestId('glide-cell-3-2')).toHaveTextContent('c'); - expect(screen.getByTestId('glide-cell-3-3')).toHaveTextContent('d'); + await waitFor(() => { + expect(screen.getByTestId('glide-cell-1-0')).toHaveTextContent('1'); + expect(screen.getByTestId('glide-cell-2-1')).toHaveTextContent('b'); + expect(screen.getByTestId('glide-cell-3-2')).toHaveTextContent('c'); + expect(screen.getByTestId('glide-cell-3-3')).toHaveTextContent('d'); + }); }); it('should open context menu on right click', async () => { diff --git a/public/test/jest-setup.ts b/public/test/jest-setup.ts index c0286b53e06..72a8d66c0dc 100644 --- a/public/test/jest-setup.ts +++ b/public/test/jest-setup.ts @@ -61,6 +61,9 @@ const mockIntersectionObserver = jest disconnect: jest.fn(), })); global.IntersectionObserver = mockIntersectionObserver; +Object.defineProperty(document, 'fonts', { + value: { ready: Promise.resolve({}) }, +}); global.TextEncoder = TextEncoder; global.TextDecoder = TextDecoder; From b4ec11e15010995e280d4944f859b48761a16277 Mon Sep 17 00:00:00 2001 From: maicon Date: Thu, 16 Jan 2025 15:01:00 -0300 Subject: [PATCH 21/30] Unistore: Ensure deprecated Folder ID gets stored on all modes (#99043) * Unistore: Ensure deprecated Folder ID gets stored on all modes Signed-off-by: Maicon Costa --------- Signed-off-by: Maicon Costa --- pkg/registry/apis/folders/conversions.go | 25 +++--------------------- pkg/registry/apis/folders/register.go | 9 ++++++--- pkg/tests/apis/folder/folders_test.go | 1 + 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/pkg/registry/apis/folders/conversions.go b/pkg/registry/apis/folders/conversions.go index 811fe274f31..4cc10fdbb73 100644 --- a/pkg/registry/apis/folders/conversions.go +++ b/pkg/registry/apis/folders/conversions.go @@ -3,7 +3,6 @@ package folders import ( "fmt" "regexp" - "strconv" "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -80,10 +79,7 @@ func UnstructuredToLegacyFolder(item unstructured.Unstructured, orgID int64) (*f return nil, "" } - id, err := getLegacyID(meta) - if err != nil { - return nil, "" - } + id := meta.GetDeprecatedInternalID() // nolint:staticcheck created, err := getCreated(meta) if err != nil { @@ -161,6 +157,8 @@ func convertToK8sResource(v *folder.Folder, namespacer request.NamespaceMapper) meta.SetUpdatedTimestamp(&v.Updated) if v.ID > 0 { // nolint:staticcheck + meta.SetDeprecatedInternalID(v.ID) // nolint:staticcheck + meta.SetRepositoryInfo(&utils.ResourceRepositoryInfo{ Name: "SQL", Path: fmt.Sprintf("%d", v.ID), // nolint:staticcheck @@ -201,23 +199,6 @@ func setParentUID(u *unstructured.Unstructured, parentUid string) error { return nil } -func getLegacyID(meta utils.GrafanaMetaAccessor) (int64, error) { - var i int64 - - repo, err := meta.GetRepositoryInfo() - if err != nil { - return i, err - } - - if repo != nil && repo.Name == "SQL" { - i, err = strconv.ParseInt(repo.Path, 10, 64) - if err != nil { - return i, err - } - } - return i, nil -} - func getURL(meta utils.GrafanaMetaAccessor, title string) string { slug := slugify.Slugify(title) uid := meta.GetName() diff --git a/pkg/registry/apis/folders/register.go b/pkg/registry/apis/folders/register.go index 3c43e5fb668..ffc15901864 100644 --- a/pkg/registry/apis/folders/register.go +++ b/pkg/registry/apis/folders/register.go @@ -18,13 +18,11 @@ import ( common "k8s.io/kube-openapi/pkg/common" "k8s.io/kube-openapi/pkg/spec3" - grafanarest "github.com/grafana/grafana/pkg/apiserver/rest" - "github.com/grafana/grafana/pkg/storage/unified/resource" - "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/apis/folder/v0alpha1" grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic" + grafanarest "github.com/grafana/grafana/pkg/apiserver/rest" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/apiserver/builder" "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" @@ -32,6 +30,8 @@ import ( "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/storage/unified/apistore" + "github.com/grafana/grafana/pkg/storage/unified/resource" ) var _ builder.APIGroupBuilder = (*FolderAPIBuilder)(nil) @@ -134,6 +134,9 @@ func (b *FolderAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.API cfg: b.cfg, } + opts.StorageOptions(resourceInfo.GroupResource(), apistore.StorageOptions{ + RequireDeprecatedInternalID: true}) + storage := map[string]rest.Storage{} storage[resourceInfo.StoragePath()] = legacyStore if optsGetter != nil && dualWriteBuilder != nil { diff --git a/pkg/tests/apis/folder/folders_test.go b/pkg/tests/apis/folder/folders_test.go index b696918ff93..748acf1aa4d 100644 --- a/pkg/tests/apis/folder/folders_test.go +++ b/pkg/tests/apis/folder/folders_test.go @@ -398,6 +398,7 @@ func doFolderTests(t *testing.T, helper *apis.K8sTestHelper) *apis.K8sTestHelper "kind": "Folder", "metadata": { "creationTimestamp": "${creationTimestamp}", + "labels": {"grafana.app/deprecatedInternalID":"1"}, "name": "` + uid + `", "namespace": "default", "resourceVersion": "${resourceVersion}", From f6194931f59382e4e9089d1e0a79936c9ccc1b3c Mon Sep 17 00:00:00 2001 From: Andreas Christou Date: Thu, 16 Jan 2025 18:38:20 +0000 Subject: [PATCH 22/30] Azure: Improve resource request error handling (#99017) * Improve resource request error handling - Correctly parse JSON responses - Log erroneous failures in JSON marshalling/unmarshalling - Correctly set response status code - Do not attempt to use the response writer as it will be nil * Minor change * Improve type assertion handling --- .../azuremonitor-resource-handler.go | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/pkg/tsdb/azuremonitor/azuremonitor-resource-handler.go b/pkg/tsdb/azuremonitor/azuremonitor-resource-handler.go index c761b271f88..0ee66507768 100644 --- a/pkg/tsdb/azuremonitor/azuremonitor-resource-handler.go +++ b/pkg/tsdb/azuremonitor/azuremonitor-resource-handler.go @@ -33,30 +33,36 @@ func (s *httpServiceProxy) writeErrorResponse(rw http.ResponseWriter, statusCode rw.Header().Set("Content-Type", "application/json") rw.WriteHeader(statusCode) + // Set error response to initial error message + errorBody := map[string]string{"error": message} + // Attempt to locate JSON portion in error message re := regexp.MustCompile(`\{.*?\}`) jsonPart := re.FindString(message) + if jsonPart != "" { + var jsonData map[string]interface{} + if unmarshalErr := json.Unmarshal([]byte(jsonPart), &jsonData); unmarshalErr != nil { + errorBody["error"] = fmt.Sprintf("Invalid JSON format in error message. Raw error: %s", message) + s.logger.Error("failed to unmarshal JSON error message", "error", unmarshalErr) + } else { + // Extract relevant fields for a formatted error message + errorType, _ := jsonData["error"].(string) + errorDescription, ok := jsonData["error_description"].(string) + if !ok { + s.logger.Error("unable to convert error_description to string", "rawError", jsonData["error_description"]) + // Attempt to just format the error as a string + errorDescription = fmt.Sprintf("%v", jsonData["error_description"]) + } + if errorType == "" { + errorType = "UnknownError" + } - var jsonData map[string]interface{} - if unmarshalErr := json.Unmarshal([]byte(jsonPart), &jsonData); unmarshalErr != nil { - errorMsg, _ := json.Marshal(map[string]string{"error": "Invalid JSON format in error message"}) - _, err := rw.Write(errorMsg) - if err != nil { - return fmt.Errorf("unable to write HTTP response: %v", err) + errorBody["error"] = fmt.Sprintf("%s: %s", errorType, errorDescription) } - return unmarshalErr } - // Extract relevant fields for a formatted error message - errorType, _ := jsonData["error"].(string) - errorDescription, _ := jsonData["error_description"].(string) - if errorType == "" { - errorType = "UnknownError" - } - formattedError := fmt.Sprintf("%s: %s", errorType, errorDescription) - - errorMsg, _ := json.Marshal(map[string]string{"error": formattedError}) - _, err := rw.Write(errorMsg) + jsonRes, _ := json.Marshal(errorBody) + _, err := rw.Write(jsonRes) if err != nil { return fmt.Errorf("unable to write HTTP response: %v", err) } @@ -117,7 +123,7 @@ func (s *Service) getDataSourceFromHTTPReq(req *http.Request) (types.DatasourceI } func writeErrorResponse(rw http.ResponseWriter, code int, msg string) { - rw.WriteHeader(http.StatusBadRequest) + rw.WriteHeader(code) errorBody := map[string]string{ "error": msg, } @@ -154,9 +160,11 @@ func (s *Service) handleResourceReq(subDataSource string) func(rw http.ResponseW req.URL.Host = serviceURL.Host req.URL.Scheme = serviceURL.Scheme - rw, err = s.executors[subDataSource].ResourceRequest(rw, req, service.HTTPClient) + _, err = s.executors[subDataSource].ResourceRequest(rw, req, service.HTTPClient) if err != nil { - writeErrorResponse(rw, http.StatusInternalServerError, fmt.Sprintf("unexpected error %v", err)) + // The ResourceRequest function should handle writing the error response + // We log the error here to ensure it's captured + s.logger.Error("error in resource request", "error", err) return } } From c63c869bcadf46bf30b6993348a7fadeff019566 Mon Sep 17 00:00:00 2001 From: Nick Richmond <5732000+NWRichmond@users.noreply.github.com> Date: Thu, 16 Jan 2025 14:29:17 -0500 Subject: [PATCH 23/30] ExploreMetrics: Add label cross-reference technique in Related Logs tab (#98775) * feat: fetch logs containing active labels * refactor: simplify & handle unhappy path * refactor: avoid local plugins * refactor: simplify, clarify, and add operator flexibility * fix: messaging for no related logs * refactor: prefer early return * refactor: avoid problematic `instanceof` checks * test: `getDataSources` + `getLokiQueryExpr` functionality * refactor: add clarity * refactor: clean up * refactor: add clarity * feat: account for known label name differences * refactor: prefer shared type * test: label name conversions * test: update to match refactor * fix: multi-connector query combination * perf: prefer labels queries to full Loki queries * fix: limit number of Loki data sources * docs: explain purpose of parsing solution * refactor: simplify logs queries * docs: add clarity * fix: handle unhappy path w/variable updates * fix: handle unhealthy Loki data sources --- .../features/trails/Integrations/logs/base.ts | 5 + .../logs/labelsCrossReference.test.ts | 263 ++++++++++++++++++ .../Integrations/logs/labelsCrossReference.ts | 120 ++++++++ .../logs/lokiRecordingRules.test.ts | 6 +- .../Integrations/logs/lokiRecordingRules.ts | 20 +- .../RelatedLogs/NoRelatedLogsFoundScene.tsx | 35 ++- .../trails/RelatedLogs/RelatedLogsScene.tsx | 185 ++++++++---- public/app/features/trails/utils.ts | 14 + public/locales/en-US/grafana.json | 5 +- public/locales/pseudo-LOCALE/grafana.json | 5 +- 10 files changed, 571 insertions(+), 87 deletions(-) create mode 100644 public/app/features/trails/Integrations/logs/labelsCrossReference.test.ts create mode 100644 public/app/features/trails/Integrations/logs/labelsCrossReference.ts diff --git a/public/app/features/trails/Integrations/logs/base.ts b/public/app/features/trails/Integrations/logs/base.ts index 629e148b889..7fd2a84a00f 100644 --- a/public/app/features/trails/Integrations/logs/base.ts +++ b/public/app/features/trails/Integrations/logs/base.ts @@ -12,6 +12,11 @@ export type FoundLokiDataSource = Pick; * associating logs with a given metric. */ export interface MetricsLogsConnector { + /** + * The name of the connector + */ + name: string; + /** * Retrieves the Loki data sources associated with the specified metric. */ diff --git a/public/app/features/trails/Integrations/logs/labelsCrossReference.test.ts b/public/app/features/trails/Integrations/logs/labelsCrossReference.test.ts new file mode 100644 index 00000000000..299d9c81d35 --- /dev/null +++ b/public/app/features/trails/Integrations/logs/labelsCrossReference.test.ts @@ -0,0 +1,263 @@ +import { type AdHocVariableFilter } from '@grafana/data'; +import { AdHocFiltersVariable, sceneGraph } from '@grafana/scenes'; + +import { DataTrail } from '../../DataTrail'; +import { RelatedLogsScene } from '../../RelatedLogs/RelatedLogsScene'; +import { VAR_FILTERS } from '../../shared'; +import * as utils from '../../utils'; + +import { createLabelsCrossReferenceConnector } from './labelsCrossReference'; + +// Create multiple mock Loki datasources with different behaviors +const mockLokiDS1 = { + uid: 'loki1', + name: 'Loki Production', + getTagKeys: jest.fn(), + getTagValues: jest.fn(), +}; + +const mockLokiDS2 = { + uid: 'loki2', + name: 'Loki Staging', + getTagKeys: jest.fn(), + getTagValues: jest.fn(), +}; + +const mockLokiDS3 = { + uid: 'loki3', + name: 'Loki Development', + getTagKeys: jest.fn(), + getTagValues: jest.fn(), +}; + +function setVariables(variables: AdHocVariableFilter[] | null) { + sceneGraphSpy.mockReturnValue(variables ? createAdHocVariableStub(variables) : null); +} + +const createAdHocVariableStub = (filters: AdHocVariableFilter[]) => { + return { + __typename: 'AdHocFiltersVariable', + state: { + name: VAR_FILTERS, + type: 'adhoc', + filters, + }, + } as unknown as AdHocFiltersVariable; +}; + +const filtersStub: AdHocVariableFilter[] = [ + { key: 'environment', operator: '=', value: 'production' }, + { key: 'app', operator: '=', value: 'frontend' }, +]; + +const mockDatasources = [mockLokiDS1, mockLokiDS2, mockLokiDS3]; +const getListSpy = jest.fn().mockReturnValue(mockDatasources); +const getSpy = jest.fn().mockImplementation(async (uid: string) => { + const ds = mockDatasources.find((ds) => ds.uid === uid); + if (!ds) { + throw new Error(`Datasource with uid ${uid} not found`); + } + return ds; +}); + +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), + getDataSourceSrv: () => ({ + getList: getListSpy, + get: getSpy, + }), + getTemplateSrv: () => ({ + getAdhocFilters: jest.fn(), + }), + getBackendSrv: () => ({ + get: jest.fn().mockResolvedValue({ status: 'OK' }), // Mock successful health checks + }), +})); + +const getTrailForSpy = jest.spyOn(utils, 'getTrailFor'); +const sceneGraphSpy = jest.spyOn(sceneGraph, 'lookupVariable'); + +const mockScene = { + state: {}, + useState: jest.fn(), +} as unknown as RelatedLogsScene; + +describe('LabelsCrossReferenceConnector', () => { + beforeEach(() => { + getListSpy.mockClear(); + sceneGraphSpy.mockClear(); + getTrailForSpy.mockReturnValue(new DataTrail({})); + [mockLokiDS1, mockLokiDS2, mockLokiDS3].forEach((mockLokiDs) => { + mockLokiDs.getTagKeys.mockClear(); + mockLokiDs.getTagValues.mockClear(); + }); + }); + + describe('getDataSources', () => { + it('should find multiple Loki data sources with matching labels', async () => { + // DS1: Has all required labels and values + mockLokiDS1.getTagKeys.mockResolvedValue([{ text: 'environment' }, { text: 'app' }]); + mockLokiDS1.getTagValues.mockResolvedValue([{ text: 'production' }, { text: 'frontend' }]); + + // DS2: Has labels but missing values + mockLokiDS2.getTagKeys.mockResolvedValue([{ text: 'environment' }, { text: 'app' }]); + mockLokiDS2.getTagValues.mockResolvedValue([ + { text: 'staging' }, // Different value + { text: 'frontend' }, + ]); + + // DS3: Has all required labels and values + mockLokiDS3.getTagKeys.mockResolvedValue([{ text: 'environment' }, { text: 'app' }]); + mockLokiDS3.getTagValues.mockResolvedValue([{ text: 'production' }, { text: 'frontend' }]); + + setVariables(filtersStub); + + const connector = createLabelsCrossReferenceConnector(mockScene); + const result = await connector.getDataSources(); + + expect(result).toHaveLength(2); + expect(result).toEqual([ + { uid: 'loki1', name: 'Loki Production' }, + { uid: 'loki3', name: 'Loki Development' }, + ]); + + // Verify that getTagKeys was called for all datasources + expect(mockLokiDS1.getTagKeys).toHaveBeenCalled(); + expect(mockLokiDS2.getTagKeys).toHaveBeenCalled(); + expect(mockLokiDS3.getTagKeys).toHaveBeenCalled(); + + // Verify filters were passed correctly + const expectedFilters = [ + { key: 'environment', operator: '=', value: 'production' }, + { key: 'app', operator: '=', value: 'frontend' }, + ]; + + expect(mockLokiDS1.getTagKeys).toHaveBeenCalledWith( + expect.objectContaining({ + filters: expect.arrayContaining(expectedFilters), + }) + ); + }); + + it('should handle mixed availability of label keys across datasources', async () => { + // DS1: Has all required labels + mockLokiDS1.getTagKeys.mockResolvedValue([{ text: 'environment' }, { text: 'app' }]); + mockLokiDS1.getTagValues.mockResolvedValue([{ text: 'production' }, { text: 'frontend' }]); + + // DS2: Missing some required labels + mockLokiDS2.getTagKeys.mockResolvedValue([ + { text: 'environment' }, // missing 'app' + ]); + + // DS3: Has different set of labels + mockLokiDS3.getTagKeys.mockResolvedValue([{ text: 'region' }, { text: 'cluster' }]); + + setVariables(filtersStub); + + const connector = createLabelsCrossReferenceConnector(mockScene); + const result = await connector.getDataSources(); + + expect(result).toHaveLength(1); + expect(result).toEqual([{ uid: 'loki1', name: 'Loki Production' }]); + + // DS2 and DS3 should not have getTagValues called since they don't have all required labels + expect(mockLokiDS1.getTagValues).toHaveBeenCalled(); + expect(mockLokiDS2.getTagValues).not.toHaveBeenCalled(); + expect(mockLokiDS3.getTagValues).not.toHaveBeenCalled(); + }); + + it('should handle known label name discrepancies across multiple datasources', async () => { + const filtersWithKnownLabels: AdHocVariableFilter[] = [ + { key: 'job', operator: '=', value: 'grafana' }, + { key: 'instance', operator: '=', value: 'instance1' }, + ]; + + // DS1: Has matching labels with known discrepancies + mockLokiDS1.getTagKeys.mockResolvedValue([{ text: 'service_name' }, { text: 'service_instance_id' }]); + mockLokiDS1.getTagValues.mockResolvedValue([{ text: 'grafana' }, { text: 'instance1' }]); + + // DS2: Also has transformed label names + mockLokiDS2.getTagKeys.mockResolvedValue([{ text: 'service_name' }, { text: 'service_instance_id' }]); + mockLokiDS2.getTagValues.mockResolvedValue([{ text: 'grafana' }, { text: 'instance1' }]); + + // DS3: Missing required labels + mockLokiDS3.getTagKeys.mockResolvedValue([ + { text: 'service_name' }, // missing service_instance_id + ]); + + setVariables(filtersWithKnownLabels); + + const connector = createLabelsCrossReferenceConnector(mockScene); + const result = await connector.getDataSources(); + + expect(result).toHaveLength(2); + expect(result).toEqual([ + { uid: 'loki1', name: 'Loki Production' }, + { uid: 'loki2', name: 'Loki Staging' }, + ]); + + // Verify that label name mapping was applied correctly + expect(mockLokiDS1.getTagKeys).toHaveBeenCalledWith( + expect.objectContaining({ + filters: expect.arrayContaining([ + expect.objectContaining({ key: 'service_name' }), + expect.objectContaining({ key: 'service_instance_id' }), + ]), + }) + ); + }); + }); + + // Rest of the tests remain the same... + describe('getLokiQueryExpr', () => { + it('should generate correct Loki query expression from filters', () => { + setVariables(filtersStub); + const connector = createLabelsCrossReferenceConnector(mockScene); + const result = connector.getLokiQueryExpr(); + + expect(result).toBe('{environment="production",app="frontend"}'); + }); + + it('should handle conversion of known label names', () => { + const filtersWithKnownLabels: AdHocVariableFilter[] = [ + { key: 'job', operator: '=', value: 'grafana' }, + { key: 'instance', operator: '=', value: 'instance1' }, + ]; + setVariables(filtersWithKnownLabels); + + const connector = createLabelsCrossReferenceConnector(mockScene); + const result = connector.getLokiQueryExpr(); + + expect(result).toBe('{service_name="grafana",service_instance_id="instance1"}'); + }); + + it('should return empty string when no filters are present', () => { + setVariables([]); + const connector = createLabelsCrossReferenceConnector(mockScene); + const result = connector.getLokiQueryExpr(); + + expect(result).toBe(''); + }); + + it('should handle missing filters variable', () => { + setVariables(null); + const connector = createLabelsCrossReferenceConnector(mockScene); + const result = connector.getLokiQueryExpr(); + + expect(result).toBe(''); + }); + + it('should handle different filter operators', () => { + const filtersWithOperators: AdHocVariableFilter[] = [ + { key: 'environment', operator: '!=', value: 'dev' }, + { key: 'level', operator: '=~', value: 'error|warn' }, + ]; + setVariables(filtersWithOperators); + + const connector = createLabelsCrossReferenceConnector(mockScene); + const result = connector.getLokiQueryExpr(); + + expect(result).toBe('{environment!="dev",level=~"error|warn"}'); + }); + }); +}); diff --git a/public/app/features/trails/Integrations/logs/labelsCrossReference.ts b/public/app/features/trails/Integrations/logs/labelsCrossReference.ts new file mode 100644 index 00000000000..4631d218c1c --- /dev/null +++ b/public/app/features/trails/Integrations/logs/labelsCrossReference.ts @@ -0,0 +1,120 @@ +import { TimeRange, type AdHocVariableFilter } from '@grafana/data'; +import { getDataSourceSrv } from '@grafana/runtime'; +import { sceneGraph } from '@grafana/scenes'; + +import { findHealthyLokiDataSources, RelatedLogsScene } from '../../RelatedLogs/RelatedLogsScene'; +import { VAR_FILTERS } from '../../shared'; +import { getTrailFor, isAdHocVariable } from '../../utils'; + +import { createMetricsLogsConnector, type FoundLokiDataSource } from './base'; + +const knownLabelNameDiscrepancies = { + job: 'service_name', // `service.name` is `job` in Mimir and `service_name` in Loki + instance: 'service_instance_id', // `service.instance.id` is `instance` in Mimir and `service_instance_id` in Loki +} as const; + +function isLabelNameThatShouldBeReplaced(x: string): x is keyof typeof knownLabelNameDiscrepancies { + return x in knownLabelNameDiscrepancies; +} + +function replaceKnownLabelNames(labelName: string): string { + if (isLabelNameThatShouldBeReplaced(labelName)) { + return knownLabelNameDiscrepancies[labelName]; + } + + return labelName; +} + +/** + * Checks if a Loki data source has labels matching the current filters + */ +async function hasMatchingLabels(datasourceUid: string, filters: AdHocVariableFilter[], timeRange?: TimeRange) { + const ds = await getDataSourceSrv().get(datasourceUid); + + // Get all available label keys for this data source + const labelKeys = await ds.getTagKeys?.({ + timeRange, + filters: filters.map(({ key, operator, value }) => ({ + key: replaceKnownLabelNames(key), + operator, + value, + })), + }); + + if (!Array.isArray(labelKeys)) { + return false; + } + + const availableLabels = new Set(labelKeys.map((key) => key.text)); + + // Early return if none of our filter labels exist in this data source + const mappedFilterLabels = filters.map((f) => replaceKnownLabelNames(f.key)); + const hasRequiredLabels = mappedFilterLabels.every((label) => availableLabels.has(label)); + if (!hasRequiredLabels) { + return false; + } + + // Check if each filter's value exists for its label + const results = await Promise.all( + filters.map(async (filter) => { + const lokiLabelName = replaceKnownLabelNames(filter.key); + const values = await ds.getTagValues?.({ + key: lokiLabelName, + timeRange, + filters, + }); + + if (!Array.isArray(values)) { + return false; + } + + return values.some((v) => v.text === filter.value); + }) + ); + + // If any of the filters have no matching values, return false + return results.every(Boolean); +} + +export const createLabelsCrossReferenceConnector = (scene: RelatedLogsScene) => { + return createMetricsLogsConnector({ + name: 'labelsCrossReference', + async getDataSources(): Promise { + const trail = getTrailFor(scene); + const filtersVariable = sceneGraph.lookupVariable(VAR_FILTERS, trail); + + if (!isAdHocVariable(filtersVariable) || !filtersVariable.state.filters.length) { + return []; + } + + const filters = filtersVariable.state.filters.map(({ key, operator, value }) => ({ key, operator, value })); + + // Get current time range if available + const timeRange = scene.state.$timeRange?.state.value; + + const lokiDataSources = await findHealthyLokiDataSources(); + const results = await Promise.all( + lokiDataSources.map(async ({ uid, name }) => { + const hasLabels = await hasMatchingLabels(uid, filters, timeRange); + return hasLabels ? { uid, name } : null; + }) + ); + + return results.filter((ds): ds is FoundLokiDataSource => ds !== null); + }, + getLokiQueryExpr(): string { + const trail = getTrailFor(scene); + const filtersVariable = sceneGraph.lookupVariable(VAR_FILTERS, trail); + + if (!isAdHocVariable(filtersVariable) || !filtersVariable.state.filters.length) { + return ''; + } + + const labelValuePairs = filtersVariable.state.filters.map( + (filter) => `${replaceKnownLabelNames(filter.key)}${filter.operator}"${filter.value}"` + ); + + return `{${labelValuePairs.join(',')}}`; // e.g. `{environment="dev",region="us-west-1"}` + }, + }); +}; diff --git a/public/app/features/trails/Integrations/logs/lokiRecordingRules.test.ts b/public/app/features/trails/Integrations/logs/lokiRecordingRules.test.ts index 1bcae3e228c..673cb2d5348 100644 --- a/public/app/features/trails/Integrations/logs/lokiRecordingRules.test.ts +++ b/public/app/features/trails/Integrations/logs/lokiRecordingRules.test.ts @@ -105,7 +105,7 @@ jest.mock('@grafana/runtime', () => ({ getBackendSrv: () => ({ fetch: fetchSpy, delete: jest.fn(), - get: jest.fn(), + get: jest.fn().mockResolvedValue({ status: 'OK' }), // Mock successful health checks patch: jest.fn(), post: jest.fn(), put: jest.fn(), @@ -121,7 +121,7 @@ describe('LokiRecordingRulesConnector', () => { getListSpy.mockClear(); fetchSpy.mockClear(); fetchSpy.mockImplementation(defaultFetchImpl); - consoleSpy = jest.spyOn(console, 'error').mockImplementation(); + consoleSpy = jest.spyOn(console, 'warn').mockImplementation(); }); afterEach(() => { @@ -138,7 +138,7 @@ describe('LokiRecordingRulesConnector', () => { expect(result).toContainEqual({ name: 'Loki Secondary', uid: 'loki2' }); // Verify underlying calls - expect(getListSpy).toHaveBeenCalledWith({ logs: true }); + expect(getListSpy).toHaveBeenCalledWith({ logs: true, type: 'loki', filter: expect.any(Function) }); expect(fetchSpy).toHaveBeenCalledTimes(2); }); diff --git a/public/app/features/trails/Integrations/logs/lokiRecordingRules.ts b/public/app/features/trails/Integrations/logs/lokiRecordingRules.ts index bb741b5507d..15c10f64042 100644 --- a/public/app/features/trails/Integrations/logs/lokiRecordingRules.ts +++ b/public/app/features/trails/Integrations/logs/lokiRecordingRules.ts @@ -1,9 +1,11 @@ import { lastValueFrom } from 'rxjs'; import type { DataSourceInstanceSettings, DataSourceJsonData } from '@grafana/data'; -import { getBackendSrv, getDataSourceSrv, type BackendSrvRequest, type FetchResponse } from '@grafana/runtime'; +import { getBackendSrv, type BackendSrvRequest, type FetchResponse } from '@grafana/runtime'; import { getLogQueryFromMetricsQuery } from 'app/plugins/datasource/loki/queryUtils'; +import { findHealthyLokiDataSources } from '../../RelatedLogs/RelatedLogsScene'; + import { createMetricsLogsConnector, type FoundLokiDataSource } from './base'; export interface RecordingRuleGroup { @@ -36,13 +38,18 @@ export interface ExtractedRecordingRules { async function fetchRecordingRuleGroups(datasourceSettings: DataSourceInstanceSettings) { const recordingRuleUrl = `api/prometheus/${datasourceSettings.uid}/api/v1/rules`; const recordingRules: BackendSrvRequest = { url: recordingRuleUrl, showErrorAlert: false, showSuccessAlert: false }; - const { data } = await lastValueFrom< + const res = await lastValueFrom< FetchResponse<{ data: { groups: RecordingRuleGroup[] }; }> >(getBackendSrv().fetch(recordingRules)); - return data.data.groups; + if (!res.ok) { + console.warn(`Failed to fetch recording rules from Loki data source: ${datasourceSettings.name}`); + return []; + } + + return res.data.data.groups; } /** @@ -150,9 +157,7 @@ export function getLokiQueryForRelatedMetric( * @throws Will log an error to the console if fetching or extracting rules fails for any data source. */ export async function fetchAndExtractLokiRecordingRules() { - const lokiDataSources = getDataSourceSrv() - .getList({ logs: true }) - .filter((ds) => ds.type === 'loki'); + const lokiDataSources = await findHealthyLokiDataSources(); const extractedRecordingRules: ExtractedRecordingRules = {}; await Promise.all( lokiDataSources.map(async (dataSource) => { @@ -161,7 +166,7 @@ export async function fetchAndExtractLokiRecordingRules() { const extractedRules = extractRecordingRulesFromRuleGroups(ruleGroups, dataSource); extractedRecordingRules[dataSource.uid] = extractedRules; } catch (err) { - console.error(err); + console.warn(err); } }) ); @@ -173,6 +178,7 @@ const createLokiRecordingRulesConnector = () => { let lokiRecordingRules: ExtractedRecordingRules = {}; return createMetricsLogsConnector({ + name: 'lokiRecordingRules', async getDataSources(selectedMetric: string): Promise { lokiRecordingRules = await fetchAndExtractLokiRecordingRules(); const lokiDataSources = getDataSourcesWithRecordingRulesContainingMetric(selectedMetric, lokiRecordingRules); diff --git a/public/app/features/trails/RelatedLogs/NoRelatedLogsFoundScene.tsx b/public/app/features/trails/RelatedLogs/NoRelatedLogsFoundScene.tsx index 2c9230e994e..ba5e3aec54d 100644 --- a/public/app/features/trails/RelatedLogs/NoRelatedLogsFoundScene.tsx +++ b/public/app/features/trails/RelatedLogs/NoRelatedLogsFoundScene.tsx @@ -1,9 +1,14 @@ +import { css } from '@emotion/css'; + +import { GrafanaTheme2 } from '@grafana/data'; import { SceneObjectBase, type SceneObjectState } from '@grafana/scenes'; -import { Stack, Text, TextLink } from '@grafana/ui'; +import { Stack, Text, TextLink, useStyles2 } from '@grafana/ui'; import { Trans } from 'app/core/internationalization'; export class NoRelatedLogsScene extends SceneObjectBase { static readonly Component = () => { + const styles = useStyles2(getStyles); + return ( @@ -12,18 +17,28 @@ export class NoRelatedLogsScene extends SceneObjectBase { - - Related logs are not available for this metric. Try selecting a metric created by a{' '} - - - Loki Recording Rule - - - , or check back later as we expand the various methods for establishing connections between metrics and - logs. + + No related logs found. To see related logs, you can either: +
    +
  • adjust the label filter to find logs with the same labels as the currently-selected metric
  • +
  • + select a metric created by a{' '} + + Loki Recording Rule + +
  • +
); }; } + +function getStyles(theme: GrafanaTheme2) { + return { + list: css({ + paddingLeft: theme.spacing(2), + }), + }; +} diff --git a/public/app/features/trails/RelatedLogs/RelatedLogsScene.tsx b/public/app/features/trails/RelatedLogs/RelatedLogsScene.tsx index 376f1c52ccb..e5f28ae9d5f 100644 --- a/public/app/features/trails/RelatedLogs/RelatedLogsScene.tsx +++ b/public/app/features/trails/RelatedLogs/RelatedLogsScene.tsx @@ -1,4 +1,5 @@ -import { config } from '@grafana/runtime'; +import { DataSourceInstanceSettings, DataSourceJsonData } from '@grafana/data'; +import { config, getBackendSrv, getDataSourceSrv } from '@grafana/runtime'; import { CustomVariable, PanelBuilders, @@ -19,9 +20,11 @@ import { Stack, LinkButton } from '@grafana/ui'; import { Trans } from 'app/core/internationalization'; import { MetricsLogsConnector } from '../Integrations/logs/base'; +import { createLabelsCrossReferenceConnector } from '../Integrations/logs/labelsCrossReference'; import { lokiRecordingRulesConnector } from '../Integrations/logs/lokiRecordingRules'; import { reportExploreMetrics } from '../interactions'; -import { VAR_LOGS_DATASOURCE, VAR_LOGS_DATASOURCE_EXPR, VAR_METRIC_EXPR } from '../shared'; +import { VAR_FILTERS, VAR_LOGS_DATASOURCE, VAR_LOGS_DATASOURCE_EXPR, VAR_METRIC, VAR_METRIC_EXPR } from '../shared'; +import { isConstantVariable, isCustomVariable } from '../utils'; import { NoRelatedLogsScene } from './NoRelatedLogsFoundScene'; @@ -48,7 +51,7 @@ export class RelatedLogsScene extends SceneObjectBase { }), ], }), - connectors: [lokiRecordingRulesConnector], + connectors: [], ...state, }); @@ -56,68 +59,99 @@ export class RelatedLogsScene extends SceneObjectBase { } private onActivate() { - const selectedMetric = sceneGraph.interpolate(this, VAR_METRIC_EXPR); - Promise.all(this.state.connectors.map((connector) => connector.getDataSources(selectedMetric))).then((results) => { - const lokiDataSources = results.flat(); - const logsPanelContainer = sceneGraph.findByKeyAndType(this, LOGS_PANEL_CONTAINER_KEY, SceneFlexItem); + this.setState({ + connectors: [lokiRecordingRulesConnector, createLabelsCrossReferenceConnector(this)], + }); + this.setLogsDataSourceVar(); + } - if (!lokiDataSources?.length) { - logsPanelContainer.setState({ - body: new NoRelatedLogsScene({}), - }); - } else { - logsPanelContainer.setState({ - body: PanelBuilders.logs() - .setTitle('Logs') - .setData( - new SceneQueryRunner({ - datasource: { uid: VAR_LOGS_DATASOURCE_EXPR }, - queries: [], - key: RELATED_LOGS_QUERY_KEY, - }) - ) - .build(), - }); - this.setState({ - $variables: new SceneVariableSet({ - variables: [ - new CustomVariable({ - name: VAR_LOGS_DATASOURCE, - label: 'Logs data source', - query: lokiDataSources?.map((ds) => `${ds.name} : ${ds.uid}`).join(','), - }), - ], - }), - controls: [new VariableValueSelectors({ layout: 'vertical' })], - }); + private setLogsDataSourceVar(): Promise { + const selectedMetric = sceneGraph.interpolate(this, VAR_METRIC_EXPR); + return Promise.all(this.state.connectors.map((connector) => connector.getDataSources(selectedMetric))).then( + (results) => { + const lokiDataSources = results.flat().slice(0, 10); // limit to the first ten matching Loki data sources + const logsPanelContainer = sceneGraph.findByKeyAndType(this, LOGS_PANEL_CONTAINER_KEY, SceneFlexItem); + + if (!lokiDataSources?.length) { + logsPanelContainer.setState({ + body: new NoRelatedLogsScene({}), + }); + this.setState({ $variables: undefined, controls: undefined }); + } else { + logsPanelContainer.setState({ + body: PanelBuilders.logs() + .setTitle('Logs') + .setData( + new SceneQueryRunner({ + datasource: { uid: VAR_LOGS_DATASOURCE_EXPR }, + queries: [], + key: RELATED_LOGS_QUERY_KEY, + }) + ) + .build(), + }); + this.setState({ + $variables: new SceneVariableSet({ + variables: [ + new CustomVariable({ + name: VAR_LOGS_DATASOURCE, + label: 'Logs data source', + query: lokiDataSources?.map((ds) => `${ds.name} : ${ds.uid}`).join(','), + }), + ], + }), + controls: [new VariableValueSelectors({ layout: 'vertical' })], + }); + } } + ); + } + + private updateLokiQuery() { + const selectedDatasourceVar = sceneGraph.lookupVariable(VAR_LOGS_DATASOURCE, this); + const selectedMetricVar = sceneGraph.lookupVariable(VAR_METRIC, this); + + if (!isCustomVariable(selectedDatasourceVar) || !isConstantVariable(selectedMetricVar)) { + return; + } + + const selectedMetric = selectedMetricVar.getValue(); + const selectedDatasourceUid = selectedDatasourceVar.getValue(); + + if (typeof selectedMetric !== 'string' || typeof selectedDatasourceUid !== 'string') { + return; + } + + const lokiQueries = this.state.connectors.reduce>((acc, connector, idx) => { + const lokiExpr = connector.getLokiQueryExpr(selectedMetric, selectedDatasourceUid); + + if (lokiExpr) { + acc[connector.name ?? `connector-${idx}`] = lokiExpr; + } + + return acc; + }, {}); + const relatedLogsQuery = sceneGraph.findByKeyAndType(this, RELATED_LOGS_QUERY_KEY, SceneQueryRunner); + relatedLogsQuery.setState({ + queries: Object.keys(lokiQueries).map((connectorName) => ({ + refId: `RelatedLogs-${connectorName}`, + expr: lokiQueries[connectorName], + maxLines: 100, + })), }); } protected _variableDependency = new VariableDependencyConfig(this, { - variableNames: [VAR_LOGS_DATASOURCE], + variableNames: [VAR_LOGS_DATASOURCE, VAR_FILTERS], onReferencedVariableValueChanged: (variable: SceneVariable) => { const { name } = variable.state; if (name === VAR_LOGS_DATASOURCE) { - const selectedMetric = sceneGraph.interpolate(this, VAR_METRIC_EXPR); - const selectedDatasourceUid = sceneGraph.interpolate(this, VAR_LOGS_DATASOURCE_EXPR); - const lokiQuery = this.state.connectors - .map((connector) => `(${connector.getLokiQueryExpr(selectedMetric, selectedDatasourceUid)})`) - .join(' and '); + this.updateLokiQuery(); + } - if (lokiQuery) { - const relatedLogsQuery = sceneGraph.findByKeyAndType(this, RELATED_LOGS_QUERY_KEY, SceneQueryRunner); - relatedLogsQuery.setState({ - queries: [ - { - refId: 'A', - expr: lokiQuery, - maxLines: 100, - }, - ], - }); - } + if (name === VAR_FILTERS) { + this.setLogsDataSourceVar().then(() => this.updateLokiQuery()); } }, }); @@ -129,13 +163,10 @@ export class RelatedLogsScene extends SceneObjectBase {
- {controls && ( - - {controls.map((control) => ( - - ))} - - )} + + {controls?.map((control) => )} + + { export function buildRelatedLogsScene() { return new RelatedLogsScene({}); } + +export async function findHealthyLokiDataSources() { + const lokiDataSources = getDataSourceSrv().getList({ + logs: true, + type: 'loki', + filter: (ds) => ds.uid !== 'grafana', + }); + const healthyLokiDataSources: Array> = []; + const unhealthyLokiDataSources: Array> = []; + + await Promise.all( + lokiDataSources.map((ds) => + getBackendSrv() + .get(`/api/datasources/${ds.id}/health`, undefined, undefined, { + showSuccessAlert: false, + showErrorAlert: false, + }) + .then((health) => + health?.status === 'OK' ? healthyLokiDataSources.push(ds) : unhealthyLokiDataSources.push(ds) + ) + .catch(() => unhealthyLokiDataSources.push(ds)) + ) + ); + + if (unhealthyLokiDataSources.length) { + console.warn( + `Found ${unhealthyLokiDataSources.length} unhealthy Loki data sources: ${unhealthyLokiDataSources.map((ds) => ds.name).join(', ')}` + ); + } + + return healthyLokiDataSources; +} diff --git a/public/app/features/trails/utils.ts b/public/app/features/trails/utils.ts index abacfb7a5a6..76ff2cc1a74 100644 --- a/public/app/features/trails/utils.ts +++ b/public/app/features/trails/utils.ts @@ -14,6 +14,8 @@ import { getPrometheusTime } from '@grafana/prometheus/src/language_utils'; import { config, FetchResponse, getBackendSrv, getDataSourceSrv } from '@grafana/runtime'; import { AdHocFiltersVariable, + ConstantVariable, + CustomVariable, sceneGraph, SceneObject, SceneObjectState, @@ -35,6 +37,18 @@ import { MetricDatasourceHelper } from './helpers/MetricDatasourceHelper'; import { sortResources } from './otel/util'; import { LOGS_METRIC, TRAILS_ROUTE, VAR_DATASOURCE_EXPR, VAR_OTEL_AND_METRIC_FILTERS } from './shared'; +export function isAdHocVariable(variable: SceneVariable | null): variable is AdHocFiltersVariable { + return variable !== null && variable.state.type === 'adhoc'; +} + +export function isCustomVariable(variable: SceneVariable | null): variable is CustomVariable { + return variable !== null && variable.state.type === 'custom'; +} + +export function isConstantVariable(variable: SceneVariable | null): variable is ConstantVariable { + return variable !== null && variable.state.type === 'constant'; +} + export function getTrailFor(model: SceneObject): DataTrail { return sceneGraph.getAncestor(model, DataTrail); } diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index ae10eb7c4e2..e63fbcbfd10 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -1323,10 +1323,9 @@ "sortBy": "Sort by" }, "related-logs": { - "docsLink": "Loki Recording Rule", + "LrrDocsLink": "Loki Recording Rule", "openExploreLogs": "Open Explore Logs", - "relatedLogsUnavailableAfterDocsLink": ", or check back later as we expand the various methods for establishing connections between metrics and logs.", - "relatedLogsUnavailableBeforeDocsLink": "Related logs are not available for this metric. Try selecting a metric created by a ", + "relatedLogsUnavailable": "No related logs found. To see related logs, you can either:<1><0>adjust the label filter to find logs with the same labels as the currently-selected metric<1>select a metric created by a <2><0>Loki Recording Rule", "warnExperimentalFeature": "Related logs is an experimental feature." }, "viewBy": "View by" diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json index 705aa03d6e9..a15602395c9 100644 --- a/public/locales/pseudo-LOCALE/grafana.json +++ b/public/locales/pseudo-LOCALE/grafana.json @@ -1323,10 +1323,9 @@ "sortBy": "Ŝőřŧ þy" }, "related-logs": { - "docsLink": "Ŀőĸį Ŗęčőřđįʼnģ Ŗūľę", + "LrrDocsLink": "Ŀőĸį Ŗęčőřđįʼnģ Ŗūľę", "openExploreLogs": "Øpęʼn Ēχpľőřę Ŀőģş", - "relatedLogsUnavailableAfterDocsLink": ", őř čĥęčĸ þäčĸ ľäŧęř äş ŵę ęχpäʼnđ ŧĥę väřįőūş męŧĥőđş ƒőř ęşŧäþľįşĥįʼnģ čőʼnʼnęčŧįőʼnş þęŧŵęęʼn męŧřįčş äʼnđ ľőģş.", - "relatedLogsUnavailableBeforeDocsLink": "Ŗęľäŧęđ ľőģş äřę ʼnőŧ äväįľäþľę ƒőř ŧĥįş męŧřįč. Ŧřy şęľęčŧįʼnģ ä męŧřįč čřęäŧęđ þy ä ", + "relatedLogsUnavailable": "Ńő řęľäŧęđ ľőģş ƒőūʼnđ. Ŧő şęę řęľäŧęđ ľőģş, yőū čäʼn ęįŧĥęř:<1><0>äđĵūşŧ ŧĥę ľäþęľ ƒįľŧęř ŧő ƒįʼnđ ľőģş ŵįŧĥ ŧĥę şämę ľäþęľş äş ŧĥę čūřřęʼnŧľy-şęľęčŧęđ męŧřįč<1>şęľęčŧ ä męŧřįč čřęäŧęđ þy ä <2><0>Ŀőĸį Ŗęčőřđįʼnģ Ŗūľę", "warnExperimentalFeature": "Ŗęľäŧęđ ľőģş įş äʼn ęχpęřįmęʼnŧäľ ƒęäŧūřę." }, "viewBy": "Vįęŵ þy" From 6901bad03bdc63a7f6ba005a85a94f961d4e755b Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Thu, 16 Jan 2025 22:38:40 +0100 Subject: [PATCH 24/30] Chore: Export some more from index for explore metrics (#99110) * export some more from index.ts for explore metrics * lint * export default member * update imports in explore metrics * Update packages/grafana-prometheus/src/index.ts Co-authored-by: Nick Richmond <5732000+NWRichmond@users.noreply.github.com> * Update public/app/features/trails/helpers/MetricDatasourceHelper.ts Co-authored-by: Nick Richmond <5732000+NWRichmond@users.noreply.github.com> --------- Co-authored-by: Nick Richmond <5732000+NWRichmond@users.noreply.github.com> --- packages/grafana-prometheus/src/index.ts | 8 ++++++++ .../features/trails/ActionTabs/MetricOverviewScene.tsx | 3 +-- .../features/trails/Breakdown/LabelBreakdownScene.tsx | 2 +- .../app/features/trails/Integrations/getQueryMetrics.ts | 3 +-- public/app/features/trails/Integrations/utils.ts | 2 +- public/app/features/trails/MetricSelect/api.ts | 4 +--- .../features/trails/autoQuery/getAutoQueriesForMetric.ts | 2 +- .../features/trails/helpers/MetricDatasourceHelper.ts | 9 +++++++-- public/app/features/trails/otel/api.ts | 3 +-- public/app/features/trails/otel/util.ts | 2 +- public/app/features/trails/utils.ts | 2 +- 11 files changed, 24 insertions(+), 16 deletions(-) diff --git a/packages/grafana-prometheus/src/index.ts b/packages/grafana-prometheus/src/index.ts index acf324f7e92..4eb15995aae 100644 --- a/packages/grafana-prometheus/src/index.ts +++ b/packages/grafana-prometheus/src/index.ts @@ -85,3 +85,11 @@ export { type StandardPromVariableQuery, } from './types'; export { PrometheusVariableSupport } from './variables'; + +// For explore metrics +export { default as PromQlLanguageProvider } from './language_provider'; +export { getPrometheusTime } from './language_utils'; +export { isValidLegacyName, utf8Support, wrapUtf8Filters } from './utf8_support'; +export { buildVisualQueryFromString } from './querybuilder/parsing'; +export { PromQueryModeller } from './querybuilder/PromQueryModeller'; +export { type QueryBuilderLabelFilter } from './querybuilder/shared/types'; diff --git a/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx b/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx index 4f3807c6034..021a6cbe26e 100644 --- a/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx +++ b/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx @@ -1,7 +1,6 @@ import { useEffect } from 'react'; -import { PromMetricsMetadataItem } from '@grafana/prometheus'; -import { isValidLegacyName } from '@grafana/prometheus/src/utf8_support'; +import { isValidLegacyName, PromMetricsMetadataItem } from '@grafana/prometheus'; import { QueryVariable, SceneComponentProps, diff --git a/public/app/features/trails/Breakdown/LabelBreakdownScene.tsx b/public/app/features/trails/Breakdown/LabelBreakdownScene.tsx index c650e3876ae..8b9e014aa57 100644 --- a/public/app/features/trails/Breakdown/LabelBreakdownScene.tsx +++ b/public/app/features/trails/Breakdown/LabelBreakdownScene.tsx @@ -4,7 +4,7 @@ import { isNumber, max, min, throttle } from 'lodash'; import { useEffect, useState } from 'react'; import { DataFrame, FieldType, GrafanaTheme2, PanelData, SelectableValue } from '@grafana/data'; -import { isValidLegacyName, utf8Support } from '@grafana/prometheus/src/utf8_support'; +import { isValidLegacyName, utf8Support } from '@grafana/prometheus'; import { config } from '@grafana/runtime'; import { ConstantVariable, diff --git a/public/app/features/trails/Integrations/getQueryMetrics.ts b/public/app/features/trails/Integrations/getQueryMetrics.ts index 5273756dc22..784808ca16f 100644 --- a/public/app/features/trails/Integrations/getQueryMetrics.ts +++ b/public/app/features/trails/Integrations/getQueryMetrics.ts @@ -1,5 +1,4 @@ -import { buildVisualQueryFromString } from '@grafana/prometheus/src/querybuilder/parsing'; -import { QueryBuilderLabelFilter } from '@grafana/prometheus/src/querybuilder/shared/types'; +import { buildVisualQueryFromString, QueryBuilderLabelFilter } from '@grafana/prometheus'; import { isEquals } from './utils'; diff --git a/public/app/features/trails/Integrations/utils.ts b/public/app/features/trails/Integrations/utils.ts index 9cb4b51e592..8e8af363e1a 100644 --- a/public/app/features/trails/Integrations/utils.ts +++ b/public/app/features/trails/Integrations/utils.ts @@ -1,4 +1,4 @@ -import { QueryBuilderLabelFilter } from '@grafana/prometheus/src/querybuilder/shared/types'; +import { QueryBuilderLabelFilter } from '@grafana/prometheus'; import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene'; import { QueryMetric } from './getQueryMetrics'; // We only support label filters with the '=' operator diff --git a/public/app/features/trails/MetricSelect/api.ts b/public/app/features/trails/MetricSelect/api.ts index cd61a3782d5..bb807ee31e9 100644 --- a/public/app/features/trails/MetricSelect/api.ts +++ b/public/app/features/trails/MetricSelect/api.ts @@ -1,7 +1,5 @@ import { AdHocVariableFilter, RawTimeRange, Scope } from '@grafana/data'; -import { getPrometheusTime } from '@grafana/prometheus/src/language_utils'; -import { PromQueryModeller } from '@grafana/prometheus/src/querybuilder/PromQueryModeller'; -import { utf8Support } from '@grafana/prometheus/src/utf8_support'; +import { getPrometheusTime, PromQueryModeller, utf8Support } from '@grafana/prometheus'; import { config, getBackendSrv } from '@grafana/runtime'; import { limitOtelMatchTerms } from '../otel/util'; diff --git a/public/app/features/trails/autoQuery/getAutoQueriesForMetric.ts b/public/app/features/trails/autoQuery/getAutoQueriesForMetric.ts index 01b74f22ace..77ddceff54f 100644 --- a/public/app/features/trails/autoQuery/getAutoQueriesForMetric.ts +++ b/public/app/features/trails/autoQuery/getAutoQueriesForMetric.ts @@ -1,4 +1,4 @@ -import { isValidLegacyName } from '@grafana/prometheus/src/utf8_support'; +import { isValidLegacyName } from '@grafana/prometheus'; import { createDefaultMetricQueryDefs } from './queryGenerators/default'; import { createHistogramMetricQueryDefs } from './queryGenerators/histogram'; diff --git a/public/app/features/trails/helpers/MetricDatasourceHelper.ts b/public/app/features/trails/helpers/MetricDatasourceHelper.ts index b77a28d2c3c..ae473d5c7e9 100644 --- a/public/app/features/trails/helpers/MetricDatasourceHelper.ts +++ b/public/app/features/trails/helpers/MetricDatasourceHelper.ts @@ -4,8 +4,13 @@ import { DataSourceGetTagValuesOptions, MetricFindValue, } from '@grafana/data'; -import { PrometheusDatasource, PromMetricsMetadata, PromMetricsMetadataItem, PromQuery } from '@grafana/prometheus'; -import PromQlLanguageProvider from '@grafana/prometheus/src/language_provider'; +import { + PrometheusDatasource, + PromMetricsMetadata, + PromMetricsMetadataItem, + PromQlLanguageProvider, + PromQuery, +} from '@grafana/prometheus'; import { getDataSourceSrv } from '@grafana/runtime'; import { DataTrail } from '../DataTrail'; diff --git a/public/app/features/trails/otel/api.ts b/public/app/features/trails/otel/api.ts index 083d1bef15e..542e9b2cd70 100644 --- a/public/app/features/trails/otel/api.ts +++ b/public/app/features/trails/otel/api.ts @@ -1,6 +1,5 @@ import { RawTimeRange, Scope } from '@grafana/data'; -import { getPrometheusTime } from '@grafana/prometheus/src/language_utils'; -import { isValidLegacyName } from '@grafana/prometheus/src/utf8_support'; +import { getPrometheusTime, isValidLegacyName } from '@grafana/prometheus'; import { config, getBackendSrv } from '@grafana/runtime'; import { callSuggestionsApi } from '../utils'; diff --git a/public/app/features/trails/otel/util.ts b/public/app/features/trails/otel/util.ts index b0f95dabd51..7f0e1ad4f61 100644 --- a/public/app/features/trails/otel/util.ts +++ b/public/app/features/trails/otel/util.ts @@ -1,5 +1,5 @@ import { AdHocVariableFilter, MetricFindValue, RawTimeRange, VariableHide } from '@grafana/data'; -import { isValidLegacyName } from '@grafana/prometheus/src/utf8_support'; +import { isValidLegacyName } from '@grafana/prometheus'; import { config } from '@grafana/runtime'; import { AdHocFiltersVariable, ConstantVariable, sceneGraph, SceneObject } from '@grafana/scenes'; diff --git a/public/app/features/trails/utils.ts b/public/app/features/trails/utils.ts index 76ff2cc1a74..860dc630a30 100644 --- a/public/app/features/trails/utils.ts +++ b/public/app/features/trails/utils.ts @@ -10,7 +10,7 @@ import { ScopeSpecFilter, urlUtil, } from '@grafana/data'; -import { getPrometheusTime } from '@grafana/prometheus/src/language_utils'; +import { getPrometheusTime } from '@grafana/prometheus'; import { config, FetchResponse, getBackendSrv, getDataSourceSrv } from '@grafana/runtime'; import { AdHocFiltersVariable, From 5a930e0ec6c1170bfc387f47ca5a767d715dd8d3 Mon Sep 17 00:00:00 2001 From: Stephanie Hingtgen Date: Thu, 16 Jan 2025 22:16:48 -0700 Subject: [PATCH 25/30] K8s search: add legacy id to dashboard response (#99132) --- pkg/services/dashboards/service/dashboard_service.go | 4 +++- pkg/storage/unified/search/dashboard.go | 10 +++++++--- .../unified/search/testdata/doc/dashboard-aaa-out.json | 1 + .../unified/search/testdata/doc/dashboard-aaa.json | 3 ++- .../unified/search/testdata/manual-dashboard.json | 10 ++++++++++ 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/pkg/services/dashboards/service/dashboard_service.go b/pkg/services/dashboards/service/dashboard_service.go index e9fa15309de..188200725e9 100644 --- a/pkg/services/dashboards/service/dashboard_service.go +++ b/pkg/services/dashboards/service/dashboard_service.go @@ -52,6 +52,7 @@ import ( "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/grafana/grafana/pkg/storage/unified/search" "github.com/grafana/grafana/pkg/util" ) @@ -1215,6 +1216,7 @@ func (dr *DashboardServiceImpl) FindDashboards(ctx context.Context, query *dashb finalResults := make([]dashboards.DashboardSearchProjection, len(response.Hits)) for i, hit := range response.Hits { finalResults[i] = dashboards.DashboardSearchProjection{ + ID: hit.Field.GetNestedInt64(search.DASHBOARD_LEGACY_ID), UID: hit.Name, OrgID: query.OrgId, Title: hit.Title, @@ -1980,7 +1982,7 @@ func ParseResults(result *resource.ResourceSearchResponse, offset int64) (*v0alp for i, row := range result.Results.Rows { fields := &common.Unstructured{} for colIndex, col := range result.Results.Columns { - if _, ok := excludedFields[col.Name]; ok { + if _, ok := excludedFields[col.Name]; !ok { val, err := resource.DecodeCell(col, colIndex, row.Cells[colIndex]) if err != nil { return nil, err diff --git a/pkg/storage/unified/search/dashboard.go b/pkg/storage/unified/search/dashboard.go index b96cbf4ae0e..20daca89039 100644 --- a/pkg/storage/unified/search/dashboard.go +++ b/pkg/storage/unified/search/dashboard.go @@ -189,6 +189,11 @@ func DashboardBuilder(namespaced resource.NamespacedDocumentSupplier) (resource. Filterable: true, }, }, + { + Name: DASHBOARD_LEGACY_ID, + Type: resource.ResourceTableColumnDefinition_INT64, + Description: "Deprecated legacy id of the dashboard", + }, }) if namespaced == nil { namespaced = func(ctx context.Context, namespace string, blob resource.BlobSupport) (resource.DocumentBuilder, error) { @@ -267,6 +272,7 @@ func (s *DashboardDocumentBuilder) BuildDocument(ctx context.Context, key *resou // metadata name is the dashboard uid summary.UID = obj.GetName() + summary.ID = obj.GetDeprecatedInternalID() // nolint:staticcheck doc := resource.NewIndexableDocument(key, rv, obj) doc.Title = summary.Title @@ -310,11 +316,9 @@ func (s *DashboardDocumentBuilder) BuildDocument(ctx context.Context, key *resou doc.Fields = map[string]any{ DASHBOARD_SCHEMA_VERSION: summary.SchemaVersion, DASHBOARD_LINK_COUNT: summary.LinkCount, + DASHBOARD_LEGACY_ID: summary.ID, } - if summary.ID > 0 { - doc.Fields[DASHBOARD_LEGACY_ID] = summary.ID - } if len(panelTypes) > 0 { sort.Strings(panelTypes) doc.Fields[DASHBOARD_PANEL_TYPES] = panelTypes diff --git a/pkg/storage/unified/search/testdata/doc/dashboard-aaa-out.json b/pkg/storage/unified/search/testdata/doc/dashboard-aaa-out.json index cf5f5485a95..04278a03fde 100644 --- a/pkg/storage/unified/search/testdata/doc/dashboard-aaa-out.json +++ b/pkg/storage/unified/search/testdata/doc/dashboard-aaa-out.json @@ -16,6 +16,7 @@ "c" ], "labels": { + "grafana.app/deprecatedInternalID": "141", "host": "abc", "region": "xyz" }, diff --git a/pkg/storage/unified/search/testdata/doc/dashboard-aaa.json b/pkg/storage/unified/search/testdata/doc/dashboard-aaa.json index d7e09d40570..d9ecbfc6aec 100644 --- a/pkg/storage/unified/search/testdata/doc/dashboard-aaa.json +++ b/pkg/storage/unified/search/testdata/doc/dashboard-aaa.json @@ -13,7 +13,8 @@ }, "labels": { "host": "abc", - "region": "xyz" + "region": "xyz", + "grafana.app/deprecatedInternalID": "141" } }, "spec": { diff --git a/pkg/storage/unified/search/testdata/manual-dashboard.json b/pkg/storage/unified/search/testdata/manual-dashboard.json index c8375063dbc..21aeada431c 100644 --- a/pkg/storage/unified/search/testdata/manual-dashboard.json +++ b/pkg/storage/unified/search/testdata/manual-dashboard.json @@ -168,6 +168,13 @@ "format": "int64", "description": "Total number of views", "priority": 0 + }, + { + "name": "legacy_id", + "type": "number", + "format": "int64", + "description": "Deprecated legacy id of the dashboard", + "priority": 0 } ], "rows": [ @@ -198,6 +205,7 @@ null, null, null, + null, null ], "object": { @@ -239,6 +247,7 @@ 100, null, null, + null, null ], "object": { @@ -282,6 +291,7 @@ 50, null, null, + null, null ], "object": { From e019e34eb5cdce1234b96702dbdc57fd6d489e6f Mon Sep 17 00:00:00 2001 From: Stephanie Hingtgen Date: Thu, 16 Jan 2025 22:19:56 -0700 Subject: [PATCH 26/30] Stats: use dashboard stats rather than list (#99130) --- .../statscollector/concurrent_users_test.go | 5 +- pkg/registry/apis/dashboard/legacy/storage.go | 33 ++++++- pkg/services/dashboards/dashboard.go | 2 + .../dashboards/dashboard_service_mock.go | 30 +++++++ pkg/services/dashboards/database/database.go | 18 ++++ .../dashboards/database/database_test.go | 12 +++ .../dashboards/service/dashboard_service.go | 27 +++++- .../service/dashboard_service_test.go | 88 ++++++++++--------- pkg/services/dashboards/store_mock.go | 31 +++++++ pkg/services/stats/statsimpl/stats.go | 59 ++++--------- pkg/services/stats/statsimpl/stats_test.go | 21 ++--- 11 files changed, 226 insertions(+), 100 deletions(-) diff --git a/pkg/infra/usagestats/statscollector/concurrent_users_test.go b/pkg/infra/usagestats/statscollector/concurrent_users_test.go index 4d89fb51a4a..dbe348c4c8c 100644 --- a/pkg/infra/usagestats/statscollector/concurrent_users_test.go +++ b/pkg/infra/usagestats/statscollector/concurrent_users_test.go @@ -13,6 +13,7 @@ import ( "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/folder/foldertest" "github.com/grafana/grafana/pkg/services/org/orgtest" "github.com/grafana/grafana/pkg/services/stats/statsimpl" @@ -28,7 +29,7 @@ func TestMain(m *testing.M) { func TestConcurrentUsersMetrics(t *testing.T) { sqlStore, cfg := db.InitTestDBWithCfg(t) - statsService := statsimpl.ProvideService(&setting.Cfg{}, sqlStore, &dashboards.FakeDashboardService{}, &foldertest.FakeService{}, &orgtest.FakeOrgService{}) + statsService := statsimpl.ProvideService(&setting.Cfg{}, sqlStore, &dashboards.FakeDashboardService{}, &foldertest.FakeService{}, &orgtest.FakeOrgService{}, featuremgmt.WithFeatures()) s := createService(t, cfg, sqlStore, statsService) createConcurrentTokens(t, sqlStore) @@ -46,7 +47,7 @@ func TestConcurrentUsersMetrics(t *testing.T) { func TestConcurrentUsersStats(t *testing.T) { sqlStore, cfg := db.InitTestDBWithCfg(t) - statsService := statsimpl.ProvideService(&setting.Cfg{}, sqlStore, &dashboards.FakeDashboardService{}, &foldertest.FakeService{}, &orgtest.FakeOrgService{}) + statsService := statsimpl.ProvideService(&setting.Cfg{}, sqlStore, &dashboards.FakeDashboardService{}, &foldertest.FakeService{}, &orgtest.FakeOrgService{}, featuremgmt.WithFeatures()) s := createService(t, cfg, sqlStore, statsService) createConcurrentTokens(t, sqlStore) diff --git a/pkg/registry/apis/dashboard/legacy/storage.go b/pkg/registry/apis/dashboard/legacy/storage.go index 10aece31f31..f48a98a35fd 100644 --- a/pkg/registry/apis/dashboard/legacy/storage.go +++ b/pkg/registry/apis/dashboard/legacy/storage.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "net/http" + "strings" "time" "github.com/grafana/authlib/claims" @@ -340,5 +341,35 @@ func (a *dashboardSqlAccess) CountRepositoryObjects(context.Context, *resource.C // GetStats implements ResourceServer. func (a *dashboardSqlAccess) GetStats(ctx context.Context, req *resource.ResourceStatsRequest) (*resource.ResourceStatsResponse, error) { - return nil, fmt.Errorf("not yet (GetStats)") + info, err := claims.ParseNamespace(req.Namespace) + if err != nil { + return nil, fmt.Errorf("unable to read namespace") + } + if info.OrgID == 0 { + return nil, fmt.Errorf("invalid OrgID found in namespace") + } + + if len(req.Kinds) != 1 { + return nil, fmt.Errorf("only can query for dashboard kind in legacy fallback") + } + + parts := strings.SplitN(req.Kinds[0], "/", 2) + if len(parts) != 2 { + return nil, fmt.Errorf("invalid kind") + } + + count, err := a.dashStore.CountInOrg(ctx, info.OrgID) + if err != nil { + return nil, err + } + + return &resource.ResourceStatsResponse{ + Stats: []*resource.ResourceStatsResponse_Stats{ + { + Group: parts[0], + Resource: parts[1], + Count: count, + }, + }, + }, nil } diff --git a/pkg/services/dashboards/dashboard.go b/pkg/services/dashboards/dashboard.go index ff51f66622c..ff46fbd5567 100644 --- a/pkg/services/dashboards/dashboard.go +++ b/pkg/services/dashboards/dashboard.go @@ -36,6 +36,7 @@ type DashboardService interface { RestoreDashboard(ctx context.Context, dashboard *Dashboard, user identity.Requester, optionalFolderUID string) error CleanUpDeletedDashboards(ctx context.Context) (int64, error) GetSoftDeletedDashboard(ctx context.Context, orgID int64, uid string) (*Dashboard, error) + CountDashboardsInOrg(ctx context.Context, orgID int64) (int64, error) } // PluginService is a service for operating on plugin dashboards. @@ -82,6 +83,7 @@ type Store interface { ValidateDashboardBeforeSave(ctx context.Context, dashboard *Dashboard, overwrite bool) (bool, error) Count(context.Context, *quota.ScopeParameters) (*quota.Map, error) + CountInOrg(ctx context.Context, orgID int64) (int64, error) // CountDashboardsInFolder returns the number of dashboards associated with // the given parent folder ID. CountDashboardsInFolders(ctx context.Context, request *CountDashboardsInFolderRequest) (int64, error) diff --git a/pkg/services/dashboards/dashboard_service_mock.go b/pkg/services/dashboards/dashboard_service_mock.go index 329efe73e0b..af8a6184e2a 100644 --- a/pkg/services/dashboards/dashboard_service_mock.go +++ b/pkg/services/dashboards/dashboard_service_mock.go @@ -168,6 +168,36 @@ func (_m *FakeDashboardService) FindDashboards(ctx context.Context, query *FindP return r0, r1 } +// CountDashboardsInOrg provides a mock function with given fields: ctx, orgID +func (_m *FakeDashboardService) CountDashboardsInOrg(ctx context.Context, orgID int64) (int64, error) { + ret := _m.Called(ctx, orgID) + + if len(ret) == 0 { + panic("no return value specified for CountDashboardsInOrg") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (int64, error)); ok { + return rf(ctx, orgID) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) int64); ok { + r0 = rf(ctx, orgID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(int64) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, orgID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetAllDashboards provides a mock function with given fields: ctx func (_m *FakeDashboardService) GetAllDashboards(ctx context.Context) ([]*Dashboard, error) { ret := _m.Called(ctx) diff --git a/pkg/services/dashboards/database/database.go b/pkg/services/dashboards/database/database.go index 5c19adb9427..6a3fe404504 100644 --- a/pkg/services/dashboards/database/database.go +++ b/pkg/services/dashboards/database/database.go @@ -266,6 +266,24 @@ func (d *dashboardStore) Count(ctx context.Context, scopeParams *quota.ScopePara return u, nil } +func (d *dashboardStore) CountInOrg(ctx context.Context, orgID int64) (int64, error) { + type result struct { + Count int64 + } + r := result{} + if err := d.store.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + rawSQL := fmt.Sprintf("SELECT COUNT(*) AS count FROM dashboard WHERE org_id=? AND is_folder=%s", d.store.GetDialect().BooleanStr(false)) + if _, err := sess.SQL(rawSQL, orgID).Get(&r); err != nil { + return err + } + return nil + }); err != nil { + return 0, err + } + + return r.Count, nil +} + func getExistingDashboardByIDOrUIDForUpdate(sess *db.Session, dash *dashboards.Dashboard, overwrite bool) (bool, error) { dashWithIdExists := false isParentFolderChanged := false diff --git a/pkg/services/dashboards/database/database_test.go b/pkg/services/dashboards/database/database_test.go index d54dd4066cc..34453b818c4 100644 --- a/pkg/services/dashboards/database/database_test.go +++ b/pkg/services/dashboards/database/database_test.go @@ -61,6 +61,7 @@ func TestIntegrationDashboardDataAccess(t *testing.T) { savedDash = insertTestDashboard(t, dashboardStore, "test dash 23", 1, savedFolder.ID, savedFolder.UID, false, "prod", "webapp") insertTestDashboard(t, dashboardStore, "test dash 45", 1, savedFolder.ID, savedFolder.UID, false, "prod") savedDash2 = insertTestDashboard(t, dashboardStore, "test dash 67", 1, 0, "", false, "prod") + insertTestDashboard(t, dashboardStore, "test dash org2", 2, 0, "", false, "") insertTestRule(t, sqlStore, savedFolder.OrgID, savedFolder.UID) } @@ -81,6 +82,17 @@ func TestIntegrationDashboardDataAccess(t *testing.T) { require.Positive(t, len(savedFolder.UID)) }) + t.Run("Should be able to get dashboard counts per org", func(t *testing.T) { + setup() + count, err := dashboardStore.CountInOrg(context.Background(), 1) + require.NoError(t, err) + require.Equal(t, int64(3), count) + + count, err = dashboardStore.CountInOrg(context.Background(), 2) + require.NoError(t, err) + require.Equal(t, int64(1), count) + }) + t.Run("Should be able to get dashboard by id", func(t *testing.T) { setup() query := dashboards.GetDashboardQuery{ diff --git a/pkg/services/dashboards/service/dashboard_service.go b/pkg/services/dashboards/service/dashboard_service.go index 188200725e9..2bb3d84aa0c 100644 --- a/pkg/services/dashboards/service/dashboard_service.go +++ b/pkg/services/dashboards/service/dashboard_service.go @@ -180,11 +180,10 @@ func (dr *DashboardServiceImpl) Count(ctx context.Context, scopeParams *quota.Sc total := int64(0) for _, org := range orgs { ctx = identity.WithRequester(ctx, getDashboardBackgroundRequester(org.ID)) - dashs, err := dr.listDashboardsThroughK8s(ctx, org.ID) + orgDashboards, err := dr.CountDashboardsInOrg(ctx, org.ID) if err != nil { - return u, err + return nil, err } - orgDashboards := int64(len(dashs)) total += orgDashboards tag, err := quota.NewTag(dashboards.QuotaTargetSrv, dashboards.QuotaTarget, quota.OrgScope) @@ -206,6 +205,28 @@ func (dr *DashboardServiceImpl) Count(ctx context.Context, scopeParams *quota.Sc return dr.dashboardStore.Count(ctx, scopeParams) } +func (dr *DashboardServiceImpl) CountDashboardsInOrg(ctx context.Context, orgID int64) (int64, error) { + if dr.features.IsEnabledGlobally(featuremgmt.FlagKubernetesCliDashboards) { + resp, err := dr.k8sclient.getSearcher().GetStats(ctx, &resource.ResourceStatsRequest{ + Namespace: dr.k8sclient.getNamespace(orgID), + Kinds: []string{ + v0alpha1.GROUP + "/" + v0alpha1.DashboardResourceInfo.GetName(), + }, + }) + if err != nil { + return 0, err + } + + if len(resp.Stats) != 1 { + return 0, fmt.Errorf("expected 1 stat, got %d", len(resp.Stats)) + } + + return resp.Stats[0].Count, nil + } + + return dr.dashboardStore.CountInOrg(ctx, orgID) +} + func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) { limits := "a.Map{} diff --git a/pkg/services/dashboards/service/dashboard_service_test.go b/pkg/services/dashboards/service/dashboard_service_test.go index a8768008f2b..2236b87caef 100644 --- a/pkg/services/dashboards/service/dashboard_service_test.go +++ b/pkg/services/dashboards/service/dashboard_service_test.go @@ -271,6 +271,11 @@ func (m *mockResourceIndexClient) Search(ctx context.Context, req *resource.Reso return args.Get(0).(*resource.ResourceSearchResponse), args.Error(1) } +func (m *mockResourceIndexClient) GetStats(ctx context.Context, in *resource.ResourceStatsRequest, opts ...grpc.CallOption) (*resource.ResourceStatsResponse, error) { + args := m.Called(in) + return args.Get(0).(*resource.ResourceStatsResponse), args.Error(1) +} + type mockResourceInterface struct { mock.Mock dynamic.ResourceInterface @@ -1779,44 +1784,17 @@ func TestQuotaCount(t *testing.T) { }, } - dashboardUnstructuredOrg1 := unstructured.UnstructuredList{ - Items: []unstructured.Unstructured{{ - Object: map[string]any{ - "metadata": map[string]any{ - "name": "uid", - }, - "spec": map[string]any{ - "test": "test", - "version": int64(1), - "title": "testing slugify", - }, - }, - }}, - } - dashboardUnstructuredOrg2 := unstructured.UnstructuredList{ - Items: []unstructured.Unstructured{{ - Object: map[string]any{ - "metadata": map[string]any{ - "name": "uid", - }, - "spec": map[string]any{ - "test": "test", - "version": int64(1), - "title": "testing slugify", - }, + countOrg1 := resource.ResourceStatsResponse{ + Stats: []*resource.ResourceStatsResponse_Stats{ + { + Count: 1, }, }, + } + countOrg2 := resource.ResourceStatsResponse{ + Stats: []*resource.ResourceStatsResponse_Stats{ { - Object: map[string]any{ - "metadata": map[string]any{ - "name": "uid2", - }, - "spec": map[string]any{ - "test": "test2", - "version": int64(1), - "title": "testing slugify2", - }, - }, + Count: 2, }, }, } @@ -1833,13 +1811,11 @@ func TestQuotaCount(t *testing.T) { }) t.Run("Should use Kubernetes client if feature flags are enabled", func(t *testing.T) { - ctx, k8sClientMock, k8sResourceMock := setupK8sDashboardTests(service) + ctx, k8sClientMock, _ := setupK8sDashboardTests(service) orgSvc := orgtest.FakeOrgService{ExpectedOrgs: orgs} service.orgService = &orgSvc - k8sClientMock.On("getClient", mock.Anything, int64(1)).Return(k8sResourceMock, true).Once() - k8sClientMock.On("getClient", mock.Anything, int64(2)).Return(k8sResourceMock, true).Once() - k8sResourceMock.On("List", mock.Anything, mock.Anything).Return(&dashboardUnstructuredOrg2, nil).Once() - k8sResourceMock.On("List", mock.Anything, mock.Anything).Return(&dashboardUnstructuredOrg1, nil).Once() + k8sClientMock.searcher.On("GetStats", mock.Anything).Return(&countOrg2, nil).Once() + k8sClientMock.searcher.On("GetStats", mock.Anything).Return(&countOrg1, nil).Once() result, err := service.Count(ctx, query) require.NoError(t, err) @@ -1858,6 +1834,38 @@ func TestQuotaCount(t *testing.T) { }) } +func TestCountDashboardsInOrg(t *testing.T) { + fakeStore := dashboards.FakeDashboardStore{} + defer fakeStore.AssertExpectations(t) + service := &DashboardServiceImpl{ + cfg: setting.NewCfg(), + dashboardStore: &fakeStore, + } + count := resource.ResourceStatsResponse{ + Stats: []*resource.ResourceStatsResponse_Stats{ + { + Count: 3, + }, + }, + } + + t.Run("Should fallback to dashboard store if Kubernetes feature flags are not enabled", func(t *testing.T) { + service.features = featuremgmt.WithFeatures() + fakeStore.On("CountInOrg", mock.Anything, mock.Anything).Return(nil, nil).Once() + _, err := service.CountDashboardsInOrg(context.Background(), 1) + require.NoError(t, err) + fakeStore.AssertExpectations(t) + }) + + t.Run("Should use Kubernetes client if feature flags are enabled", func(t *testing.T) { + ctx, k8sClientMock, _ := setupK8sDashboardTests(service) + k8sClientMock.searcher.On("GetStats", mock.Anything).Return(&count, nil).Once() + result, err := service.CountDashboardsInOrg(ctx, 1) + require.NoError(t, err) + require.Equal(t, result, int64(3)) + }) +} + func TestLegacySaveCommandToUnstructured(t *testing.T) { namespace := "test-namespace" t.Run("successfully converts save command to unstructured", func(t *testing.T) { diff --git a/pkg/services/dashboards/store_mock.go b/pkg/services/dashboards/store_mock.go index 0d1e385f1dc..070c45e641b 100644 --- a/pkg/services/dashboards/store_mock.go +++ b/pkg/services/dashboards/store_mock.go @@ -48,6 +48,37 @@ func (_m *FakeDashboardStore) Count(_a0 context.Context, _a1 *quota.ScopeParamet return r0, r1 } +// CountInOrg provides a mock function with given fields: _a0, _a1 +func (_m *FakeDashboardStore) CountInOrg(_a0 context.Context, _a1 int64) (int64, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for Count") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (int64, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) int64); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(int64) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + + // CountDashboardsInFolders provides a mock function with given fields: ctx, request func (_m *FakeDashboardStore) CountDashboardsInFolders(ctx context.Context, request *CountDashboardsInFolderRequest) (int64, error) { ret := _m.Called(ctx, request) diff --git a/pkg/services/stats/statsimpl/stats.go b/pkg/services/stats/statsimpl/stats.go index c8c25319f46..5e909ef6571 100644 --- a/pkg/services/stats/statsimpl/stats.go +++ b/pkg/services/stats/statsimpl/stats.go @@ -10,6 +10,7 @@ import ( "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/libraryelements/model" "github.com/grafana/grafana/pkg/services/org" @@ -21,13 +22,14 @@ import ( const activeUserTimeLimit = time.Hour * 24 * 30 const dailyActiveUserTimeLimit = time.Hour * 24 -func ProvideService(cfg *setting.Cfg, db db.DB, dashSvc dashboards.DashboardService, folderSvc folder.Service, orgSvc org.Service) stats.Service { +func ProvideService(cfg *setting.Cfg, db db.DB, dashSvc dashboards.DashboardService, folderSvc folder.Service, orgSvc org.Service, features featuremgmt.FeatureToggles) stats.Service { return &sqlStatsService{ cfg: cfg, db: db, folderSvc: folderSvc, dashSvc: dashSvc, orgSvc: orgSvc, + features: features, } } @@ -35,48 +37,23 @@ type sqlStatsService struct { db db.DB cfg *setting.Cfg dashSvc dashboards.DashboardService + features featuremgmt.FeatureToggles folderSvc folder.Service orgSvc org.Service } -type dashboardStats struct { - count int - bytesTotal int - bytesMax int -} - -func (ss *sqlStatsService) collectDashboardStats(ctx context.Context, orgs []*org.OrgDTO, calculateByteSize bool) (dashboardStats, error) { - stats := dashboardStats{ - count: 0, - bytesTotal: 0, - bytesMax: 0, - } - +func (ss *sqlStatsService) getDashboardCount(ctx context.Context, orgs []*org.OrgDTO) (int64, error) { + count := int64(0) for _, org := range orgs { ctx = identity.WithRequester(ctx, getStatsRequester(org.ID)) - dashs, err := ss.dashSvc.GetAllDashboardsByOrgId(ctx, org.ID) + dashsCount, err := ss.dashSvc.CountDashboardsInOrg(ctx, org.ID) if err != nil { - return stats, err - } - stats.count += len(dashs) - - // only calculate bytes if needed - if calculateByteSize { - for _, dash := range dashs { - b, err := dash.Data.ToDB() - if err != nil { - return stats, err - } - stats.bytesTotal += len(b) - - if len(b) > stats.bytesMax { - stats.bytesMax = len(b) - } - } + return 0, err } + count += dashsCount } - return stats, nil + return count, nil } func (ss *sqlStatsService) getTagCount(ctx context.Context, orgs []*org.OrgDTO) (int64, error) { @@ -172,7 +149,6 @@ func (ss *sqlStatsService) GetSystemStats(ctx context.Context, query *stats.GetS monthlyActiveUserDeadlineDate := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) sb.Write(`(SELECT COUNT(*) FROM `+dialect.Quote("user")+` WHERE `+ notServiceAccount(dialect)+` AND last_seen_at > ?) AS monthly_active_users,`, monthlyActiveUserDeadlineDate) - sb.Write(`(SELECT COUNT(id) FROM ` + dialect.Quote("dashboard_provisioning") + `) AS provisioned_dashboards,`) sb.Write(`(SELECT COUNT(id) FROM ` + dialect.Quote("dashboard_snapshot") + `) AS snapshots,`) sb.Write(`(SELECT COUNT(id) FROM ` + dialect.Quote("dashboard_version") + `) AS dashboard_versions,`) @@ -190,6 +166,11 @@ func (ss *sqlStatsService) GetSystemStats(ctx context.Context, query *stats.GetS if ss.IsUnifiedAlertingEnabled() { sb.Write(`(SELECT COUNT(DISTINCT (` + dialect.Quote("rule_group") + `)) FROM ` + dialect.Quote("alert_rule") + `) AS rule_groups,`) } + // currently not supported when dashboards are in unified storage + if !ss.features.IsEnabledGlobally(featuremgmt.FlagKubernetesCliDashboards) { + sb.Write(`(SELECT SUM(LENGTH(data)) FROM `+dialect.Quote("dashboard")+` WHERE is_folder = ?) AS dashboard_bytes_total,`, dialect.BooleanStr(false)) + sb.Write(`(SELECT MAX(LENGTH(data)) FROM `+dialect.Quote("dashboard")+` WHERE is_folder = ?) AS dashboard_bytes_max,`, dialect.BooleanStr(false)) + } sb.Write(ss.roleCounterSQL(ctx)) @@ -216,13 +197,11 @@ func (ss *sqlStatsService) GetSystemStats(ctx context.Context, query *stats.GetS result.Orgs = int64(len(orgs)) // for services in unified storage, get the stats through the service rather than the db directly - dashStats, err := ss.collectDashboardStats(ctx, orgs, true) + dashCount, err := ss.getDashboardCount(ctx, orgs) if err != nil { return result, err } - result.DashboardBytesMax = int64(dashStats.bytesMax) - result.DashboardBytesTotal = int64(dashStats.bytesTotal) - result.Dashboards = int64(dashStats.count) + result.Dashboards = dashCount folderCount, err := ss.getFolderCount(ctx, orgs) if err != nil { @@ -329,11 +308,11 @@ func (ss *sqlStatsService) GetAdminStats(ctx context.Context, query *stats.GetAd result.Orgs = int64(len(orgs)) // for services in unified storage, get the stats through the service rather than the db directly - dashStats, err := ss.collectDashboardStats(ctx, orgs, false) + dashCount, err := ss.getDashboardCount(ctx, orgs) if err != nil { return result, err } - result.Dashboards = int64(dashStats.count) + result.Dashboards = dashCount tagCount, err := ss.getTagCount(ctx, orgs) if err != nil { diff --git a/pkg/services/stats/statsimpl/stats_test.go b/pkg/services/stats/statsimpl/stats_test.go index 3b3951ed27b..324a83c6788 100644 --- a/pkg/services/stats/statsimpl/stats_test.go +++ b/pkg/services/stats/statsimpl/stats_test.go @@ -10,12 +10,12 @@ import ( "github.com/stretchr/testify/require" "github.com/grafana/grafana/pkg/bus" - "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/services/correlations" "github.com/grafana/grafana/pkg/services/correlations/correlationstest" "github.com/grafana/grafana/pkg/services/dashboards" + "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/folder/foldertest" "github.com/grafana/grafana/pkg/services/org" @@ -40,15 +40,9 @@ func TestIntegrationStatsDataAccess(t *testing.T) { db, cfg := db.InitTestDBWithCfg(t) orgSvc := populateDB(t, db, cfg) dashSvc := &dashboards.FakeDashboardService{} - emptyJson := simplejson.New() - emptyJsonBytes, err := emptyJson.ToDB() - require.NoError(t, err) - largerJson := simplejson.NewFromAny(map[string]string{"key": "value"}) - largerJsonBytes, err := largerJson.ToDB() - require.NoError(t, err) - dashSvc.On("GetAllDashboardsByOrgId", mock.Anything, int64(1)).Return([]*dashboards.Dashboard{{Data: largerJson}, {Data: emptyJson}}, nil) - dashSvc.On("GetAllDashboardsByOrgId", mock.Anything, int64(2)).Return([]*dashboards.Dashboard{}, nil) - dashSvc.On("GetAllDashboardsByOrgId", mock.Anything, int64(3)).Return([]*dashboards.Dashboard{}, nil) + dashSvc.On("CountDashboardsInOrg", mock.Anything, int64(1)).Return(int64(2), nil) + dashSvc.On("CountDashboardsInOrg", mock.Anything, int64(2)).Return(int64(1), nil) + dashSvc.On("CountDashboardsInOrg", mock.Anything, int64(3)).Return(int64(0), nil) dashSvc.On("GetDashboardTags", mock.Anything, &dashboards.GetDashboardTagsQuery{OrgID: 1}).Return([]*dashboards.DashboardTagCloudItem{{Term: "test"}}, nil) dashSvc.On("GetDashboardTags", mock.Anything, &dashboards.GetDashboardTagsQuery{OrgID: 2}).Return([]*dashboards.DashboardTagCloudItem{}, nil) dashSvc.On("GetDashboardTags", mock.Anything, &dashboards.GetDashboardTagsQuery{OrgID: 3}).Return([]*dashboards.DashboardTagCloudItem{}, nil) @@ -61,6 +55,7 @@ func TestIntegrationStatsDataAccess(t *testing.T) { dashSvc: dashSvc, orgSvc: orgSvc, folderSvc: folderService, + features: featuremgmt.WithFeatures(), } t.Run("Get system stats should not results in error", func(t *testing.T) { @@ -76,10 +71,8 @@ func TestIntegrationStatsDataAccess(t *testing.T) { assert.Equal(t, int64(0), result.APIKeys) assert.Equal(t, int64(2), result.Correlations) assert.Equal(t, int64(3), result.Orgs) - assert.Equal(t, int64(2), result.Dashboards) + assert.Equal(t, int64(3), result.Dashboards) assert.Equal(t, int64(9), result.Folders) // will return 3 folders for each org - assert.Equal(t, int64(len(largerJsonBytes)+len(emptyJsonBytes)), result.DashboardBytesTotal) - assert.Equal(t, int64(len(largerJsonBytes)), result.DashboardBytesMax) assert.NotNil(t, result.DatabaseCreatedTime) assert.Equal(t, db.GetDialect().DriverName(), result.DatabaseDriver) }) @@ -113,7 +106,7 @@ func TestIntegrationStatsDataAccess(t *testing.T) { stats, err := statsService.GetAdminStats(context.Background(), &query) assert.NoError(t, err) assert.Equal(t, int64(1), stats.Tags) - assert.Equal(t, int64(2), stats.Dashboards) + assert.Equal(t, int64(3), stats.Dashboards) assert.Equal(t, int64(3), stats.Orgs) }) } From a08f4067813f850a396474e85c4d2fd23b98c345 Mon Sep 17 00:00:00 2001 From: Mariell Hoversholm Date: Fri, 17 Jan 2025 09:29:52 +0100 Subject: [PATCH 27/30] Security: Update to Go 1.23.5 (#99121) * feat: update to Go 1.23.5 * chore: make drone * chore: make update-workspace * CI: Force re-build * CI: Force re-build --- .drone.yml | 210 ++++++++++++++-------------- Dockerfile | 2 +- Makefile | 2 +- apps/alerting/notifications/go.mod | 2 +- go.mod | 2 +- go.work | 2 +- pkg/storage/unified/apistore/go.mod | 2 +- pkg/storage/unified/resource/go.mod | 2 +- scripts/drone/variables.star | 2 +- 9 files changed, 113 insertions(+), 113 deletions(-) diff --git a/.drone.yml b/.drone.yml index 6c5961a92d4..f81d8bbbc69 100644 --- a/.drone.yml +++ b/.drone.yml @@ -25,7 +25,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: compile-build-cmd - commands: - ./bin/build verify-drone @@ -75,7 +75,7 @@ steps: - go install github.com/bazelbuild/buildtools/buildifier@latest - buildifier --lint=warn -mode=check -r . depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: lint-starlark trigger: event: @@ -427,7 +427,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -436,21 +436,21 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: wire-install - commands: - apk add --update build-base shared-mime-info shared-mime-info-lang - go list -f '{{.Dir}}/...' -m | xargs go test -short -covermode=atomic -timeout=5m depends_on: - wire-install - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: test-backend - commands: - apk add --update build-base @@ -459,7 +459,7 @@ steps: | grep -o '\(.*\)/' | sort -u) depends_on: - wire-install - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: test-backend-integration trigger: event: @@ -513,7 +513,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: compile-build-cmd - commands: - echo $(/usr/bin/github-app-external-token) > /github-app/token @@ -558,16 +558,16 @@ steps: - apk add --update make - make gen-go depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: wire-install - commands: - go run scripts/modowners/modowners.go check go.mod - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: validate-modfile - commands: - apk add --update make - make swagger-validate - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: validate-openapi-spec trigger: event: @@ -643,7 +643,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: compile-build-cmd - commands: - '# It is required that code generated from Thema/CUE be committed and in sync @@ -653,7 +653,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -662,7 +662,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-jsonnet - commands: - yarn install --immutable || yarn install --immutable @@ -698,7 +698,7 @@ steps: - /src/grafana-build artifacts -a targz:grafana:linux/amd64 -a targz:grafana:linux/arm64 -a targz:grafana:linux/arm/v7 -a docker:grafana:linux/amd64 -a docker:grafana:linux/amd64:ubuntu -a docker:grafana:linux/arm64 -a docker:grafana:linux/arm64:ubuntu -a docker:grafana:linux/arm/v7 - -a docker:grafana:linux/arm/v7:ubuntu --go-version=1.23.4 --yarn-cache=$$YARN_CACHE_FOLDER + -a docker:grafana:linux/arm/v7:ubuntu --go-version=1.23.5 --yarn-cache=$$YARN_CACHE_FOLDER --build-id=$$DRONE_BUILD_NUMBER --ubuntu-base=ubuntu:22.04 --alpine-base=alpine:3.20.3 --tag-format='{{ .version_base }}-{{ .buildID }}-{{ .arch }}' --ubuntu-tag-format='{{ .version_base }}-{{ .buildID }}-ubuntu-{{ .arch }}' --verify='false' --grafana-dir=$$PWD @@ -1096,7 +1096,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: compile-build-cmd - commands: - echo $DRONE_RUNNER_NAME @@ -1110,7 +1110,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -1119,14 +1119,14 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: wire-install - commands: - dockerize -wait tcp://postgres:5432 -timeout 120s @@ -1147,7 +1147,7 @@ steps: GRAFANA_TEST_DB: postgres PGPASSWORD: grafanatest POSTGRES_HOST: postgres - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: postgres-integration-tests - commands: - dockerize -wait tcp://mysql80:3306 -timeout 120s @@ -1168,7 +1168,7 @@ steps: environment: GRAFANA_TEST_DB: mysql MYSQL_HOST: mysql80 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: mysql-8.0-integration-tests - commands: - dockerize -wait tcp://redis:6379 -timeout 120s @@ -1184,7 +1184,7 @@ steps: - wait-for-redis environment: REDIS_URL: redis://redis:6379/0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: redis-integration-tests - commands: - dockerize -wait tcp://memcached:11211 -timeout 120s @@ -1200,7 +1200,7 @@ steps: - wait-for-memcached environment: MEMCACHED_HOSTS: memcached:11211 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: memcached-integration-tests - commands: - dockerize -wait tcp://mimir_backend:8080 -timeout 120s @@ -1216,7 +1216,7 @@ steps: environment: AM_TENANT_ID: test AM_URL: http://mimir_backend:8080 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: remote-alertmanager-integration-tests trigger: event: @@ -1298,7 +1298,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-cue trigger: event: @@ -1419,7 +1419,7 @@ steps: && return 1; fi depends_on: - clone-enterprise - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: swagger-gen trigger: event: @@ -1524,7 +1524,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: compile-build-cmd - commands: - '# It is required that code generated from Thema/CUE be committed and in sync @@ -1535,7 +1535,7 @@ steps: - CODEGEN_VERIFY=1 make gen-cue depends_on: - clone-enterprise - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -1545,14 +1545,14 @@ steps: - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: - clone-enterprise - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: wire-install - commands: - apk add --update build-base @@ -1560,7 +1560,7 @@ steps: - go test -v -run=^$ -benchmem -timeout=1h -count=8 -bench=. ${GO_PACKAGES} depends_on: - wire-install - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: sqlite-benchmark-integration-tests - commands: - apk add --update build-base @@ -1572,7 +1572,7 @@ steps: GRAFANA_TEST_DB: postgres PGPASSWORD: grafanatest POSTGRES_HOST: postgres - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: postgres-benchmark-integration-tests - commands: - apk add --update build-base @@ -1583,7 +1583,7 @@ steps: environment: GRAFANA_TEST_DB: mysql MYSQL_HOST: mysql80 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: mysql-8.0-benchmark-integration-tests trigger: event: @@ -1655,7 +1655,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-cue trigger: branch: main @@ -1828,7 +1828,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -1837,21 +1837,21 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: wire-install - commands: - apk add --update build-base shared-mime-info shared-mime-info-lang - go list -f '{{.Dir}}/...' -m | xargs go test -short -covermode=atomic -timeout=5m depends_on: - wire-install - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: test-backend - commands: - apk add --update build-base @@ -1860,7 +1860,7 @@ steps: | grep -o '\(.*\)/' | sort -u) depends_on: - wire-install - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: test-backend-integration trigger: branch: main @@ -1905,22 +1905,22 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: compile-build-cmd - commands: - apk add --update make - make gen-go depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: wire-install - commands: - go run scripts/modowners/modowners.go check go.mod - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: validate-modfile - commands: - apk add --update make - make swagger-validate - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: validate-openapi-spec - commands: - ./bin/build verify-drone @@ -2052,7 +2052,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: compile-build-cmd - commands: - '# It is required that code generated from Thema/CUE be committed and in sync @@ -2062,7 +2062,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -2071,7 +2071,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-jsonnet - commands: - yarn install --immutable || yarn install --immutable @@ -2106,7 +2106,7 @@ steps: - /src/grafana-build artifacts -a targz:grafana:linux/amd64 -a targz:grafana:linux/arm64 -a targz:grafana:linux/arm/v7 -a docker:grafana:linux/amd64 -a docker:grafana:linux/amd64:ubuntu -a docker:grafana:linux/arm64 -a docker:grafana:linux/arm64:ubuntu -a docker:grafana:linux/arm/v7 - -a docker:grafana:linux/arm/v7:ubuntu --go-version=1.23.4 --yarn-cache=$$YARN_CACHE_FOLDER + -a docker:grafana:linux/arm/v7:ubuntu --go-version=1.23.5 --yarn-cache=$$YARN_CACHE_FOLDER --build-id=$$DRONE_BUILD_NUMBER --ubuntu-base=ubuntu:22.04 --alpine-base=alpine:3.20.3 --tag-format='{{ .version_base }}-{{ .buildID }}-{{ .arch }}' --ubuntu-tag-format='{{ .version_base }}-{{ .buildID }}-ubuntu-{{ .arch }}' --verify='false' --grafana-dir=$$PWD @@ -2581,7 +2581,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: compile-build-cmd - commands: - echo $DRONE_RUNNER_NAME @@ -2595,7 +2595,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -2604,14 +2604,14 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: wire-install - commands: - dockerize -wait tcp://postgres:5432 -timeout 120s @@ -2632,7 +2632,7 @@ steps: GRAFANA_TEST_DB: postgres PGPASSWORD: grafanatest POSTGRES_HOST: postgres - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: postgres-integration-tests - commands: - dockerize -wait tcp://mysql80:3306 -timeout 120s @@ -2653,7 +2653,7 @@ steps: environment: GRAFANA_TEST_DB: mysql MYSQL_HOST: mysql80 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: mysql-8.0-integration-tests - commands: - dockerize -wait tcp://redis:6379 -timeout 120s @@ -2669,7 +2669,7 @@ steps: - wait-for-redis environment: REDIS_URL: redis://redis:6379/0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: redis-integration-tests - commands: - dockerize -wait tcp://memcached:11211 -timeout 120s @@ -2685,7 +2685,7 @@ steps: - wait-for-memcached environment: MEMCACHED_HOSTS: memcached:11211 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: memcached-integration-tests - commands: - dockerize -wait tcp://mimir_backend:8080 -timeout 120s @@ -2701,7 +2701,7 @@ steps: environment: AM_TENANT_ID: test AM_URL: http://mimir_backend:8080 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: remote-alertmanager-integration-tests trigger: branch: main @@ -2960,7 +2960,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -2969,21 +2969,21 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: wire-install - commands: - apk add --update build-base shared-mime-info shared-mime-info-lang - go list -f '{{.Dir}}/...' -m | xargs go test -short -covermode=atomic -timeout=5m depends_on: - wire-install - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: test-backend - commands: - apk add --update build-base @@ -2992,7 +2992,7 @@ steps: | grep -o '\(.*\)/' | sort -u) depends_on: - wire-install - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: test-backend-integration trigger: branch: @@ -3035,22 +3035,22 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: compile-build-cmd - commands: - apk add --update make - make gen-go depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: wire-install - commands: - go run scripts/modowners/modowners.go check go.mod - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: validate-modfile - commands: - apk add --update make - make swagger-validate - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: validate-openapi-spec trigger: branch: @@ -3129,7 +3129,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: compile-build-cmd - commands: - echo $DRONE_RUNNER_NAME @@ -3143,7 +3143,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -3152,14 +3152,14 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: wire-install - commands: - dockerize -wait tcp://postgres:5432 -timeout 120s @@ -3180,7 +3180,7 @@ steps: GRAFANA_TEST_DB: postgres PGPASSWORD: grafanatest POSTGRES_HOST: postgres - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: postgres-integration-tests - commands: - dockerize -wait tcp://mysql80:3306 -timeout 120s @@ -3201,7 +3201,7 @@ steps: environment: GRAFANA_TEST_DB: mysql MYSQL_HOST: mysql80 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: mysql-8.0-integration-tests - commands: - dockerize -wait tcp://redis:6379 -timeout 120s @@ -3217,7 +3217,7 @@ steps: - wait-for-redis environment: REDIS_URL: redis://redis:6379/0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: redis-integration-tests - commands: - dockerize -wait tcp://memcached:11211 -timeout 120s @@ -3233,7 +3233,7 @@ steps: - wait-for-memcached environment: MEMCACHED_HOSTS: memcached:11211 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: memcached-integration-tests - commands: - dockerize -wait tcp://mimir_backend:8080 -timeout 120s @@ -3249,7 +3249,7 @@ steps: environment: AM_TENANT_ID: test AM_URL: http://mimir_backend:8080 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: remote-alertmanager-integration-tests trigger: branch: @@ -3349,7 +3349,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: compile-build-cmd - commands: - ./bin/build artifacts docker fetch --edition oss @@ -3481,7 +3481,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: compile-build-cmd - commands: - ./bin/build artifacts docker fetch --edition oss @@ -3622,7 +3622,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: compile-build-cmd - commands: - ./bin/build artifacts packages --artifacts-editions=oss --tag $${DRONE_TAG} --src-bucket @@ -3714,7 +3714,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: compile-build-cmd - commands: - yarn install --immutable || yarn install --immutable @@ -3814,7 +3814,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: compile-build-cmd - depends_on: - compile-build-cmd @@ -3911,7 +3911,7 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: compile-build-cmd - commands: - ./bin/build publish grafana-com --edition oss ${DRONE_TAG} @@ -3973,7 +3973,7 @@ steps: from_secret: grafana_api_key GCP_KEY_BASE64: from_secret: gcp_key_base64 - GO_VERSION: 1.23.4 + GO_VERSION: 1.23.5 GPG_PASSPHRASE: from_secret: packages_gpg_passphrase GPG_PRIVATE_KEY: @@ -4048,7 +4048,7 @@ steps: from_secret: grafana_api_key GCP_KEY_BASE64: from_secret: gcp_key_base64 - GO_VERSION: 1.23.4 + GO_VERSION: 1.23.5 GPG_PASSPHRASE: from_secret: packages_gpg_passphrase GPG_PRIVATE_KEY: @@ -4105,13 +4105,13 @@ steps: depends_on: [] environment: CGO_ENABLED: 0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: compile-build-cmd - commands: - ./bin/build whatsnew-checker depends_on: - compile-build-cmd - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: whats-new-checker trigger: event: @@ -4210,7 +4210,7 @@ steps: from_secret: grafana_api_key GCP_KEY_BASE64: from_secret: gcp_key_base64 - GO_VERSION: 1.23.4 + GO_VERSION: 1.23.5 GPG_PASSPHRASE: from_secret: packages_gpg_passphrase GPG_PRIVATE_KEY: @@ -4361,7 +4361,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -4370,21 +4370,21 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: wire-install - commands: - apk add --update build-base shared-mime-info shared-mime-info-lang - go list -f '{{.Dir}}/...' -m | xargs go test -short -covermode=atomic -timeout=5m depends_on: - wire-install - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: test-backend - commands: - apk add --update build-base @@ -4393,7 +4393,7 @@ steps: | grep -o '\(.*\)/' | sort -u) depends_on: - wire-install - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: test-backend-integration trigger: cron: @@ -4447,7 +4447,7 @@ steps: from_secret: grafana_api_key GCP_KEY_BASE64: from_secret: gcp_key_base64 - GO_VERSION: 1.23.4 + GO_VERSION: 1.23.5 GPG_PASSPHRASE: from_secret: packages_gpg_passphrase GPG_PRIVATE_KEY: @@ -4591,7 +4591,7 @@ steps: from_secret: grafana_api_key GCP_KEY_BASE64: from_secret: gcp_key_base64 - GO_VERSION: 1.23.4 + GO_VERSION: 1.23.5 GPG_PASSPHRASE: from_secret: packages_gpg_passphrase GPG_PRIVATE_KEY: @@ -4698,7 +4698,7 @@ steps: - export GITHUB_TOKEN=$(cat /github-app/token) - 'dagger run --silent /src/grafana-build artifacts -a $${ARTIFACTS} --grafana-ref=$${GRAFANA_REF} --enterprise-ref=$${ENTERPRISE_REF} --grafana-repo=$${GRAFANA_REPO} --version=$${VERSION} ' - - --go-version=1.23.4 + - --go-version=1.23.5 depends_on: - github-app-generate-token environment: @@ -4719,7 +4719,7 @@ steps: from_secret: grafana_api_key GCP_KEY_BASE64: from_secret: gcp_key_base64 - GO_VERSION: 1.23.4 + GO_VERSION: 1.23.5 GPG_PASSPHRASE: from_secret: packages_gpg_passphrase GPG_PRIVATE_KEY: @@ -4853,7 +4853,7 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-cue depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-cue - commands: - '# It is required that generated jsonnet is committed and in sync with its inputs.' @@ -4862,14 +4862,14 @@ steps: - apk add --update make - CODEGEN_VERIFY=1 make gen-jsonnet depends_on: [] - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: verify-gen-jsonnet - commands: - apk add --update make - make gen-go depends_on: - verify-gen-cue - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: wire-install - commands: - dockerize -wait tcp://postgres:5432 -timeout 120s @@ -4890,7 +4890,7 @@ steps: GRAFANA_TEST_DB: postgres PGPASSWORD: grafanatest POSTGRES_HOST: postgres - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: postgres-integration-tests - commands: - dockerize -wait tcp://mysql80:3306 -timeout 120s @@ -4911,7 +4911,7 @@ steps: environment: GRAFANA_TEST_DB: mysql MYSQL_HOST: mysql80 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: mysql-8.0-integration-tests - commands: - dockerize -wait tcp://redis:6379 -timeout 120s @@ -4927,7 +4927,7 @@ steps: - wait-for-redis environment: REDIS_URL: redis://redis:6379/0 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: redis-integration-tests - commands: - dockerize -wait tcp://memcached:11211 -timeout 120s @@ -4943,7 +4943,7 @@ steps: - wait-for-memcached environment: MEMCACHED_HOSTS: memcached:11211 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: memcached-integration-tests - commands: - dockerize -wait tcp://mimir_backend:8080 -timeout 120s @@ -4959,7 +4959,7 @@ steps: environment: AM_TENANT_ID: test AM_URL: http://mimir_backend:8080 - image: golang:1.23.4-alpine + image: golang:1.23.5-alpine name: remote-alertmanager-integration-tests trigger: event: @@ -5262,7 +5262,7 @@ steps: - commands: - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM docker:27-cli - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM alpine/git:2.40.1 - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM golang:1.23.4-alpine + - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM golang:1.23.5-alpine - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM node:22.11.0-alpine - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM node:22-bookworm - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM google/cloud-sdk:431.0.0 @@ -5300,7 +5300,7 @@ steps: - commands: - trivy --exit-code 1 --severity HIGH,CRITICAL docker:27-cli - trivy --exit-code 1 --severity HIGH,CRITICAL alpine/git:2.40.1 - - trivy --exit-code 1 --severity HIGH,CRITICAL golang:1.23.4-alpine + - trivy --exit-code 1 --severity HIGH,CRITICAL golang:1.23.5-alpine - trivy --exit-code 1 --severity HIGH,CRITICAL node:22.11.0-alpine - trivy --exit-code 1 --severity HIGH,CRITICAL node:22-bookworm - trivy --exit-code 1 --severity HIGH,CRITICAL google/cloud-sdk:431.0.0 @@ -5569,6 +5569,6 @@ kind: secret name: gcr_credentials --- kind: signature -hmac: be82e983dfa15f85f82935674ec109056f519ff99c7ab1f4be71f9ce62b571a7 +hmac: 154c1f072294cef09ba4f579eed30b1e29bc5c263897c862f4574432d321502c ... diff --git a/Dockerfile b/Dockerfile index ceaa2f35279..719a3009a25 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ ARG BASE_IMAGE=alpine:3.20 ARG JS_IMAGE=node:22-alpine ARG JS_PLATFORM=linux/amd64 -ARG GO_IMAGE=golang:1.23.1-alpine +ARG GO_IMAGE=golang:1.23.5-alpine ARG GO_SRC=go-builder ARG JS_SRC=js-builder diff --git a/Makefile b/Makefile index bf00ee389ab..3df11c69545 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ WIRE_TAGS = "oss" include .bingo/Variables.mk GO = go -GO_VERSION = 1.23.4 +GO_VERSION = 1.23.5 GO_LINT_FILES ?= $(shell ./scripts/go-workspace/golangci-lint-includes.sh) GO_TEST_FILES ?= $(shell ./scripts/go-workspace/test-includes.sh) SH_FILES ?= $(shell find ./scripts -name *.sh) diff --git a/apps/alerting/notifications/go.mod b/apps/alerting/notifications/go.mod index 8652ac7f708..2d88581dc52 100644 --- a/apps/alerting/notifications/go.mod +++ b/apps/alerting/notifications/go.mod @@ -1,6 +1,6 @@ module github.com/grafana/grafana/apps/alerting/notifications -go 1.23.4 +go 1.23.5 replace github.com/grafana/grafana => ../../.. diff --git a/go.mod b/go.mod index 30fc9daa77a..1b2a6556e0e 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/grafana/grafana -go 1.23.4 +go 1.23.5 require ( buf.build/gen/go/parca-dev/parca/connectrpc/go v1.17.0-20240902100956-02fd72488966.1 // @grafana/observability-traces-and-profiling diff --git a/go.work b/go.work index e33309c0552..6fb73b7dde6 100644 --- a/go.work +++ b/go.work @@ -1,4 +1,4 @@ -go 1.23.4 +go 1.23.5 // The `skip:golangci-lint` comment tag is used to exclude the package from the `golangci-lint` GitHub Action. // The module at the root of the repo (`.`) is excluded because ./pkg/... is included manually in the `golangci-lint` configuration. diff --git a/pkg/storage/unified/apistore/go.mod b/pkg/storage/unified/apistore/go.mod index c512b9bfe00..a2350ab1a9d 100644 --- a/pkg/storage/unified/apistore/go.mod +++ b/pkg/storage/unified/apistore/go.mod @@ -1,6 +1,6 @@ module github.com/grafana/grafana/pkg/storage/unified/apistore -go 1.23.4 +go 1.23.5 replace ( github.com/grafana/grafana => ../../../.. diff --git a/pkg/storage/unified/resource/go.mod b/pkg/storage/unified/resource/go.mod index f3428da429a..36be0fe79ac 100644 --- a/pkg/storage/unified/resource/go.mod +++ b/pkg/storage/unified/resource/go.mod @@ -1,6 +1,6 @@ module github.com/grafana/grafana/pkg/storage/unified/resource -go 1.23.4 +go 1.23.5 replace ( github.com/grafana/grafana => ../../../.. diff --git a/scripts/drone/variables.star b/scripts/drone/variables.star index ec9e803a101..01147f6df17 100644 --- a/scripts/drone/variables.star +++ b/scripts/drone/variables.star @@ -3,7 +3,7 @@ global variables """ grabpl_version = "v3.1.1" -golang_version = "1.23.4" +golang_version = "1.23.5" # nodejs_version should match what's in ".nvmrc", but without the v prefix. nodejs_version = "22.11.0" From 17a09c28dd4840dc986a53ece519e973fd3bb26f Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Fri, 17 Jan 2025 09:36:08 +0100 Subject: [PATCH 28/30] Chore: Upgrade openfga to 1.8.4 (#99095) --- apps/alerting/notifications/go.mod | 6 +- apps/alerting/notifications/go.sum | 12 +-- apps/investigation/go.mod | 6 +- apps/investigation/go.sum | 12 +-- apps/playlist/go.mod | 6 +- apps/playlist/go.sum | 12 +-- go.mod | 24 ++--- go.sum | 48 ++++----- go.work.sum | 146 ++++++++++++++++++++++++++++ pkg/aggregator/go.mod | 8 +- pkg/aggregator/go.sum | 16 +-- pkg/apiserver/go.mod | 6 +- pkg/apiserver/go.sum | 12 +-- pkg/build/go.mod | 6 +- pkg/build/go.sum | 12 +-- pkg/promlib/go.mod | 6 +- pkg/promlib/go.sum | 12 +-- pkg/storage/unified/apistore/go.mod | 25 +++-- pkg/storage/unified/apistore/go.sum | 48 ++++----- pkg/storage/unified/resource/go.mod | 6 +- pkg/storage/unified/resource/go.sum | 48 ++++----- 21 files changed, 311 insertions(+), 166 deletions(-) diff --git a/apps/alerting/notifications/go.mod b/apps/alerting/notifications/go.mod index 2d88581dc52..c35603b00df 100644 --- a/apps/alerting/notifications/go.mod +++ b/apps/alerting/notifications/go.mod @@ -38,7 +38,7 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240821155123-6891eb1d35da // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmespath-community/go-jmespath v1.1.1 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -69,7 +69,7 @@ require ( go.opentelemetry.io/otel/metric v1.33.0 // indirect go.opentelemetry.io/otel/sdk v1.33.0 // indirect go.opentelemetry.io/otel/trace v1.33.0 // indirect - go.opentelemetry.io/proto/otlp v1.4.0 // indirect + go.opentelemetry.io/proto/otlp v1.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.32.0 // indirect @@ -80,7 +80,7 @@ require ( golang.org/x/term v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.9.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect google.golang.org/grpc v1.69.2 // indirect google.golang.org/protobuf v1.36.1 // indirect diff --git a/apps/alerting/notifications/go.sum b/apps/alerting/notifications/go.sum index 1715e2d28f8..ea3e1dc3988 100644 --- a/apps/alerting/notifications/go.sum +++ b/apps/alerting/notifications/go.sum @@ -81,8 +81,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a534 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340/go.mod h1:3bDW6wMZJB7tiONtC/1Xpicra6Wp5GgbTbQWCbI5fkc= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jmespath-community/go-jmespath v1.1.1 h1:bFikPhsi/FdmlZhVgSCd2jj1e7G/rw+zyQfyg5UF+L4= @@ -196,8 +196,8 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4Jjx go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= -go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= -go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -262,8 +262,8 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU= google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= diff --git a/apps/investigation/go.mod b/apps/investigation/go.mod index d5d5c6cc49d..222bedf653a 100644 --- a/apps/investigation/go.mod +++ b/apps/investigation/go.mod @@ -32,7 +32,7 @@ require ( github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/uuid v1.6.0 // indirect github.com/grafana/grafana-app-sdk/logging v0.29.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/invopop/yaml v0.3.1 // indirect @@ -60,7 +60,7 @@ require ( go.opentelemetry.io/otel/metric v1.33.0 // indirect go.opentelemetry.io/otel/sdk v1.33.0 // indirect go.opentelemetry.io/otel/trace v1.33.0 // indirect - go.opentelemetry.io/proto/otlp v1.4.0 // indirect + go.opentelemetry.io/proto/otlp v1.5.0 // indirect golang.org/x/net v0.34.0 // indirect golang.org/x/oauth2 v0.25.0 // indirect golang.org/x/sync v0.10.0 // indirect @@ -70,7 +70,7 @@ require ( golang.org/x/time v0.9.0 // indirect golang.org/x/tools v0.29.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect google.golang.org/grpc v1.69.2 // indirect google.golang.org/protobuf v1.36.1 // indirect diff --git a/apps/investigation/go.sum b/apps/investigation/go.sum index be0502d6005..1e29e15bfcb 100644 --- a/apps/investigation/go.sum +++ b/apps/investigation/go.sum @@ -53,8 +53,8 @@ github.com/grafana/grafana-app-sdk v0.29.0 h1:LMSm/+0LOBPd13fe1bs/4sKJmuLiixYUX9 github.com/grafana/grafana-app-sdk v0.29.0/go.mod h1:XLt308EmK6kvqPlzjUyXxbwZKEk2vur/eiypUNDay5I= github.com/grafana/grafana-app-sdk/logging v0.29.0 h1:mgbXaAf33aFwqwGVeaX30l8rkeAJH0iACgX5Rn6YkN4= github.com/grafana/grafana-app-sdk/logging v0.29.0/go.mod h1:xy6ZyVXl50Z3DBDLybvBPphbykPhuVNed/VNmen9DQM= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -140,8 +140,8 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4Jjx go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= -go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= -go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -187,8 +187,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= diff --git a/apps/playlist/go.mod b/apps/playlist/go.mod index e8174a96dcb..14bcd395cd4 100644 --- a/apps/playlist/go.mod +++ b/apps/playlist/go.mod @@ -33,7 +33,7 @@ require ( github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/uuid v1.6.0 // indirect github.com/grafana/grafana-app-sdk/logging v0.29.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/invopop/yaml v0.3.1 // indirect @@ -61,7 +61,7 @@ require ( go.opentelemetry.io/otel/metric v1.33.0 // indirect go.opentelemetry.io/otel/sdk v1.33.0 // indirect go.opentelemetry.io/otel/trace v1.33.0 // indirect - go.opentelemetry.io/proto/otlp v1.4.0 // indirect + go.opentelemetry.io/proto/otlp v1.5.0 // indirect golang.org/x/net v0.34.0 // indirect golang.org/x/oauth2 v0.25.0 // indirect golang.org/x/sync v0.10.0 // indirect @@ -71,7 +71,7 @@ require ( golang.org/x/time v0.9.0 // indirect golang.org/x/tools v0.29.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect google.golang.org/grpc v1.69.2 // indirect google.golang.org/protobuf v1.36.1 // indirect diff --git a/apps/playlist/go.sum b/apps/playlist/go.sum index be0502d6005..1e29e15bfcb 100644 --- a/apps/playlist/go.sum +++ b/apps/playlist/go.sum @@ -53,8 +53,8 @@ github.com/grafana/grafana-app-sdk v0.29.0 h1:LMSm/+0LOBPd13fe1bs/4sKJmuLiixYUX9 github.com/grafana/grafana-app-sdk v0.29.0/go.mod h1:XLt308EmK6kvqPlzjUyXxbwZKEk2vur/eiypUNDay5I= github.com/grafana/grafana-app-sdk/logging v0.29.0 h1:mgbXaAf33aFwqwGVeaX30l8rkeAJH0iACgX5Rn6YkN4= github.com/grafana/grafana-app-sdk/logging v0.29.0/go.mod h1:xy6ZyVXl50Z3DBDLybvBPphbykPhuVNed/VNmen9DQM= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -140,8 +140,8 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4Jjx go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= -go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= -go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -187,8 +187,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= diff --git a/go.mod b/go.mod index 1b2a6556e0e..2066f77d04a 100644 --- a/go.mod +++ b/go.mod @@ -92,7 +92,7 @@ require ( github.com/grafana/tempo v1.5.1-0.20241001135150-ed943d7a56b2 // @grafana/observability-traces-and-profiling github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // @grafana/plugins-platform-backend github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 // @grafana/grafana-backend-group - github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // @grafana/identity-access-team + github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // @grafana/identity-access-team github.com/hashicorp/go-hclog v1.6.3 // @grafana/plugins-platform-backend github.com/hashicorp/go-multierror v1.1.1 // @grafana/alerting-squad github.com/hashicorp/go-plugin v1.6.2 // @grafana/plugins-platform-backend @@ -123,9 +123,9 @@ require ( github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // @grafana/alerting-backend github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // @grafana/grafana-operator-experience-squad github.com/olekukonko/tablewriter v0.0.5 // @grafana/grafana-backend-group - github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66 // @grafana/identity-access-team - github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f // @grafana/identity-access-team - github.com/openfga/openfga v1.6.2 // @grafana/identity-access-team + github.com/openfga/api/proto v0.0.0-20250107154247-c22e6db5c4f5 // @grafana/identity-access-team + github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20241115164311-10e575c8e47c // @grafana/identity-access-team + github.com/openfga/openfga v1.8.4 // @grafana/identity-access-team github.com/openzipkin/zipkin-go v0.4.3 // @grafana/oss-big-tent github.com/patrickmn/go-cache v2.1.0+incompatible // @grafana/alerting-backend github.com/phpdave11/gofpdi v1.0.13 // @grafana/sharing-squad @@ -240,6 +240,7 @@ require ( github.com/Masterminds/squirrel v1.5.4 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/RoaringBitmap/roaring v1.9.3 // indirect + github.com/Yiling-J/theine-go v0.6.0 // indirect github.com/agext/levenshtein v1.2.1 // indirect github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect @@ -326,7 +327,7 @@ require ( github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/btree v1.1.3 // indirect - github.com/google/cel-go v0.22.0 // indirect + github.com/google/cel-go v0.22.1 // indirect github.com/google/flatbuffers v24.3.25+incompatible // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gofuzz v1.2.0 // indirect @@ -356,7 +357,7 @@ require ( github.com/invopop/yaml v0.3.1 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect - github.com/jackc/pgx/v5 v5.7.1 // indirect + github.com/jackc/pgx/v5 v5.7.2 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect @@ -371,7 +372,6 @@ require ( github.com/jpillora/backoff v1.0.0 // indirect github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect - github.com/karlseguin/ccache/v3 v3.0.5 // indirect github.com/klauspost/compress v1.17.11 // indirect github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/kylelemons/godebug v1.1.0 // indirect @@ -422,7 +422,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/pressly/goose/v3 v3.22.1 // indirect + github.com/pressly/goose/v3 v3.24.0 // indirect github.com/prometheus/common/sigv4 v0.1.0 // indirect github.com/prometheus/exporter-toolkit v0.13.2 // indirect github.com/prometheus/procfs v0.15.1 // indirect @@ -478,8 +478,8 @@ require ( go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 // indirect go.opentelemetry.io/otel/metric v1.33.0 // indirect - go.opentelemetry.io/proto/otlp v1.4.0 // indirect - go.uber.org/mock v0.4.0 // indirect + go.opentelemetry.io/proto/otlp v1.5.0 // indirect + go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go4.org/netipx v0.0.0-20230125063823-8449b0a6169f // indirect golang.org/x/sys v0.29.0 // indirect @@ -487,7 +487,7 @@ require ( golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect @@ -501,7 +501,7 @@ require ( modernc.org/libc v1.55.3 // indirect modernc.org/mathutil v1.6.0 // indirect modernc.org/memory v1.8.0 // indirect - modernc.org/sqlite v1.33.1 // indirect + modernc.org/sqlite v1.34.4 // indirect modernc.org/strutil v1.2.0 // indirect modernc.org/token v1.1.0 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 // indirect diff --git a/go.sum b/go.sum index e183dd02dee..84a3338d539 100644 --- a/go.sum +++ b/go.sum @@ -747,6 +747,8 @@ github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f h1:HR5nRmUQgX github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f/go.mod h1:f3HiCrHjHBdcm6E83vGaXh1KomZMA2P6aeo3hKx/wg0= github.com/Workiva/go-datastructures v1.1.5 h1:5YfhQ4ry7bZc2Mc7R0YZyYwpf5c6t1cEFvdAhd6Mkf4= github.com/Workiva/go-datastructures v1.1.5/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= +github.com/Yiling-J/theine-go v0.6.0 h1:jv7V/tcD6ijL0T4kfbJDKP81TCZBkoriNTPSqwivWuY= +github.com/Yiling-J/theine-go v0.6.0/go.mod h1:mdch1vjgGWd7s3rWKvY+MF5InRLfRv/CWVI9RVNQ8wY= github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8= github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= @@ -1369,8 +1371,8 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.22.0 h1:b3FJZxpiv1vTMo2/5RDUqAHPxkT8mmMfJIrq1llbf7g= -github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= +github.com/google/cel-go v0.22.1 h1:AfVXx3chM2qwoSbM7Da8g8hX8OVSkBFwX+rz2+PcK40= +github.com/google/cel-go v0.22.1/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI= github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= @@ -1582,8 +1584,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= @@ -1704,8 +1706,8 @@ github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5ey github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= -github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= -github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI= +github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= @@ -1769,8 +1771,6 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8 github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= -github.com/karlseguin/ccache/v3 v3.0.5 h1:hFX25+fxzNjsRlREYsoGNa2LoVEw5mPF8wkWq/UnevQ= -github.com/karlseguin/ccache/v3 v3.0.5/go.mod h1:qxC372+Qn+IBj8Pe3KvGjHPj0sWwEF7AeZVhsNPZ6uY= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= @@ -2004,12 +2004,12 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= -github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66 h1:pAYrdyIKxPsMs/nRcTEnS9za2io11g7Rt7ng7HK82hk= -github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66/go.mod h1:gil5LBD8tSdFQbUkCQdnXsoeU9kDJdJgbGdHkgJfcd0= -github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f h1:ZMZ7ntMnaHIPZxvVQv/aqC4ctzLqH+9Fqn4uw35kQpk= -github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f/go.mod h1:ll/hN6kS4EE6B/7J/PbZqac9Nuv7ZHpI+Jfh36JLrbs= -github.com/openfga/openfga v1.6.2 h1:tHBAgiCPomCZb3IH0CFqOpTDVDA/Xb8kG87oX4JCbXc= -github.com/openfga/openfga v1.6.2/go.mod h1:jzbEpheazf6MFjtanQt1rpxexSRzfa9057F7JlkMv2I= +github.com/openfga/api/proto v0.0.0-20250107154247-c22e6db5c4f5 h1:z9jaRoo+NIN1AB0ogjtrjx1316TTuq6IbqpEg3UJycA= +github.com/openfga/api/proto v0.0.0-20250107154247-c22e6db5c4f5/go.mod h1:m74TNgnAAIJ03gfHcx+xaRWnr+IbQy3y/AVNwwCFrC0= +github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20241115164311-10e575c8e47c h1:1y84C0V4NRfPtRi4MqQ7+gnFtYgeBKPIeIAPLdVJ7j4= +github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20241115164311-10e575c8e47c/go.mod h1:12RMe/HuRNyOzS33RQa53jwdcxE2znr8ycXMlVbgQN4= +github.com/openfga/openfga v1.8.4 h1:OqyRpuxMCxcS7irTFYFkhAIYzmAnczNwxUqjnuZOQyo= +github.com/openfga/openfga v1.8.4/go.mod h1:9Ax9VMMySV2JMsCT8MTePeYt4OrTnPAy1XUV1y9RyuU= github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg= github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w= @@ -2065,8 +2065,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/pressly/goose/v3 v3.22.1 h1:2zICEfr1O3yTP9BRZMGPj7qFxQ+ik6yeo+z1LMuioLc= -github.com/pressly/goose/v3 v3.22.1/go.mod h1:xtMpbstWyCpyH+0cxLTMCENWBG+0CSxvTsXhW95d5eo= +github.com/pressly/goose/v3 v3.24.0 h1:sFbNms7Bd++2VMq6HSgDHDLWa7kHz1qXzPb3ZIU72VU= +github.com/pressly/goose/v3 v3.24.0/go.mod h1:rEWreU9uVtt0DHCyLzF9gRcWiiTF/V+528DV+4DORug= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= @@ -2460,16 +2460,16 @@ go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37Cb go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= -go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -3228,8 +3228,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go. google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= @@ -3441,8 +3441,8 @@ modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= -modernc.org/sqlite v1.33.1 h1:trb6Z3YYoeM9eDL1O8do81kP+0ejv+YzgyFo+Gwy0nM= -modernc.org/sqlite v1.33.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k= +modernc.org/sqlite v1.34.4 h1:sjdARozcL5KJBvYQvLlZEmctRgW9xqIZc2ncN7PU0P8= +modernc.org/sqlite v1.34.4/go.mod h1:3QQFCG2SEMtc2nv+Wq4cQCH7Hjcg+p/RMlS1XK+zwbk= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= diff --git a/go.work.sum b/go.work.sum index 385146da3cf..997fa34fd7b 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,5 +1,6 @@ buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230802163732-1c33ebd9ecfa.1 h1:tdpHgTbmbvEIARu+bixzmleMi14+3imnpoFXz+Qzjp4= buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230802163732-1c33ebd9ecfa.1/go.mod h1:xafc+XIsTxTy76GJQ1TKgvJWsSugFBqMaN27WhUblew= +cel.dev/expr v0.16.2/go.mod h1:gXngZQMkWJoSbE8mOzehJlXQyubn/Vg0vR9/F3W7iw8= cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= @@ -8,6 +9,9 @@ cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYN cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= cloud.google.com/go v0.111.0/go.mod h1:0mibmpKP1TyOOFYQY5izo0LnT+ecvOQ0Sg3OdmMiNRU= cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= +cloud.google.com/go v0.112.2/go.mod h1:iEqjp//KquGIJV/m+Pk3xecgKNhV+ry+vVTsy4TbDms= +cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU= +cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc= cloud.google.com/go/accessapproval v1.7.1/go.mod h1:JYczztsHRMK7NTXb6Xw+dwbs/WnOJxbo/2mTI+Kgg68= cloud.google.com/go/accessapproval v1.7.2/go.mod h1:/gShiq9/kK/h8T/eEn1BTzalDvk0mZxJlhfw0p+Xuc0= cloud.google.com/go/accessapproval v1.7.3/go.mod h1:4l8+pwIxGTNqSf4T3ds8nLO94NQf0W/KnMNuQ9PbnP8= @@ -109,7 +113,13 @@ cloud.google.com/go/assuredworkloads v1.11.5/go.mod h1:FKJ3g3ZvkL2D7qtqIGnDufFkH cloud.google.com/go/assuredworkloads v1.12.1 h1:B+hWc62fYL8NdntPjx0rzJJ67qx99w6dCeIVDpHf7QE= cloud.google.com/go/assuredworkloads v1.12.1/go.mod h1:nBnkK2GZNSdtjU3ER75oC5fikub5/+QchbolKgnMI/I= cloud.google.com/go/auth v0.2.0/go.mod h1:+yb+oy3/P0geX6DLKlqiGHARGR6EX2GRtYCzWOCQSbU= +cloud.google.com/go/auth v0.3.0/go.mod h1:lBv6NKTWp8E3LPzmO1TbiiRKc4drLOfHsgmlH9ogv5w= +cloud.google.com/go/auth v0.6.1/go.mod h1:eFHG7zDzbXHKmjJddFG/rBlcGp6t25SwRUiEQSlO4x4= +cloud.google.com/go/auth v0.9.3/go.mod h1:7z6VY+7h3KUdRov5F1i8NDP5ZzWKYmEPO842BgCsmTk= +cloud.google.com/go/auth v0.9.4/go.mod h1:SHia8n6//Ya940F1rLimhJCjjx7KE17t0ctFEci3HkA= cloud.google.com/go/auth/oauth2adapt v0.2.0/go.mod h1:AfqujpDAlTfLfeCIl/HJZZlIxD8+nJoZ5e0x1IxGq5k= +cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= +cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= cloud.google.com/go/automl v1.13.1/go.mod h1:1aowgAHWYZU27MybSCFiukPO7xnyawv7pt3zK4bheQE= cloud.google.com/go/automl v1.13.2/go.mod h1:gNY/fUmDEN40sP8amAX3MaXkxcqPIn7F1UIIPZpy4Mg= cloud.google.com/go/automl v1.13.3/go.mod h1:Y8KwvyAZFOsMAPqUCfNu1AyclbC6ivCUF/MTwORymyY= @@ -226,6 +236,8 @@ cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3 cloud.google.com/go/compute v1.28.1 h1:XwPcZjgMCnU2tkwY10VleUjSAfpTj9RDn+kGrbYsi8o= cloud.google.com/go/compute v1.28.1/go.mod h1:b72iXMY4FucVry3NR3Li4kVyyTvbMDE7x5WsqvxjsYk= cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= +cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= cloud.google.com/go/contactcenterinsights v1.9.1/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= cloud.google.com/go/contactcenterinsights v1.10.0/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= cloud.google.com/go/contactcenterinsights v1.11.0/go.mod h1:hutBdImE4XNZ1NV4vbPJKSFOnQruhC5Lj9bZqWMTKiU= @@ -493,6 +505,8 @@ cloud.google.com/go/iam v1.1.3/go.mod h1:3khUlaBXfPKKe7huYgEpDn6FtgRyMEqbkvBxrQy cloud.google.com/go/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8= cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/iam v1.1.8/go.mod h1:GvE6lyMmfxXauzNq8NbgJbeVQNspG+tcdL/W8QO1+zE= +cloud.google.com/go/iam v1.2.0/go.mod h1:zITGuWgsLZxd8OwAlX+eMFgZDXzBm7icj1PVTYG766Q= cloud.google.com/go/iap v1.8.1/go.mod h1:sJCbeqg3mvWLqjZNsI6dfAtbbV1DL2Rl7e1mTyXYREQ= cloud.google.com/go/iap v1.9.0/go.mod h1:01OFxd1R+NFrg78S+hoPV5PxEzv22HXaNqUUlmNHFuY= cloud.google.com/go/iap v1.9.1/go.mod h1:SIAkY7cGMLohLSdBR25BuIxO+I4fXJiL06IBL7cy/5Q= @@ -550,6 +564,9 @@ cloud.google.com/go/longrunning v0.5.2/go.mod h1:nqo6DQbNV2pXhGDbDMoN2bWz68MjZUz cloud.google.com/go/longrunning v0.5.3/go.mod h1:y/0ga59EYu58J6SHmmQOvekvND2qODbu8ywBBW7EK7Y= cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI= cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= +cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn9GqyjaBT8/mA= +cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng= +cloud.google.com/go/longrunning v0.6.0/go.mod h1:uHzSZqW89h7/pasCWNYdUpwGz3PcVWhrWupreVPYLts= cloud.google.com/go/managedidentities v1.6.1/go.mod h1:h/irGhTN2SkZ64F43tfGPMbHnypMbu4RB3yl8YcuEak= cloud.google.com/go/managedidentities v1.6.2/go.mod h1:5c2VG66eCa0WIq6IylRk3TBW83l161zkFvCj28X7jn8= cloud.google.com/go/managedidentities v1.6.3/go.mod h1:tewiat9WLyFN0Fi7q1fDD5+0N4VUoL0SCX0OTCthZq4= @@ -839,6 +856,7 @@ cloud.google.com/go/speech v1.21.1/go.mod h1:E5GHZXYQlkqWQwY5xRSLHw2ci5NMQNG52Ff cloud.google.com/go/speech v1.25.1 h1:iGZJS3wrdkje/Vqiacx1+r+zVwUZoXVMdklYIVsvfNw= cloud.google.com/go/speech v1.25.1/go.mod h1:WgQghvghkZ1htG6BhYn98mP7Tg0mti8dBFDLMVXH/vM= cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= +cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= cloud.google.com/go/storage v1.37.0/go.mod h1:i34TiT2IhiNDmcj65PqwCjcoUX7Z5pLzS8DEmoiFq1k= cloud.google.com/go/storagetransfer v1.10.0/go.mod h1:DM4sTlSmGiNczmV6iZyceIh2dbs+7z2Ayg6YAiQlYfA= @@ -884,6 +902,7 @@ cloud.google.com/go/translate v1.9.2/go.mod h1:E3Tc6rUTsQkVrXW6avbUhKJSr7ZE3j7zN cloud.google.com/go/translate v1.9.3/go.mod h1:Kbq9RggWsbqZ9W5YpM94Q1Xv4dshw/gr/SHfsl5yCZ0= cloud.google.com/go/translate v1.10.0/go.mod h1:Kbq9RggWsbqZ9W5YpM94Q1Xv4dshw/gr/SHfsl5yCZ0= cloud.google.com/go/translate v1.10.1/go.mod h1:adGZcQNom/3ogU65N9UXHOnnSvjPwA/jKQUMnsYXOyk= +cloud.google.com/go/translate v1.10.3/go.mod h1:GW0vC1qvPtd3pgtypCv4k4U8B7EdgK9/QEF2aJEUovs= cloud.google.com/go/translate v1.12.1 h1:Vws9BGpVcaOeI6HodyWdvysUzHUBFvk7ymHu1tzFvuM= cloud.google.com/go/translate v1.12.1/go.mod h1:5f4RvC7/hh76qSl6LYuqOJaKbIzEpR1Sj+CMA6gSgIk= cloud.google.com/go/video v1.17.1/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= @@ -1016,6 +1035,8 @@ github.com/ClickHouse/ch-go v0.61.5 h1:zwR8QbYI0tsMiEcze/uIMK+Tz1D3XZXLdNrlaOpeE github.com/ClickHouse/ch-go v0.61.5/go.mod h1:s1LJW/F/LcFs5HJnuogFMta50kKDO0lf9zzfrbl0RQg= github.com/ClickHouse/clickhouse-go/v2 v2.28.3 h1:SkFzPULX6nzgfNZd1YD1XTECivjTMrCtD09ZPKcVLFQ= github.com/ClickHouse/clickhouse-go/v2 v2.28.3/go.mod h1:vzn73hp+3JwxtFU4RjPCQ7r6fP2pMKVwdi8E1/Tkua8= +github.com/ClickHouse/clickhouse-go/v2 v2.30.0 h1:AG4D/hW39qa58+JHQIFOSnxyL46H6h2lrmGGk17dhFo= +github.com/ClickHouse/clickhouse-go/v2 v2.30.0/go.mod h1:i9ZQAojcayW3RsdCb3YR+n+wC2h65eJsZCscZ1Z1wyo= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oME= @@ -1101,6 +1122,7 @@ github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEq github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 h1:goHVqTbFX3AIo0tzGr14pgfAW2ZfPChKO21Z9MGf/gk= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40 h1:q4dksr6ICHXqG5hm0ZW5IHyeEJXoIJSOZeBLmWPNeIQ= github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40/go.mod h1:Q7yQnSMnLvcXlZ8RV+jwz/6y1rQTqbX6C82SndT52Zs= github.com/apache/arrow/go/v10 v10.0.1 h1:n9dERvixoC/1JjDmBcs9FPaEryoANa2sCgVFo6ez9cI= @@ -1302,8 +1324,10 @@ github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= github.com/efficientgo/tools/core v0.0.0-20220225185207-fe763185946b h1:ZHiD4/yE4idlbqvAO6iYCOYRzOMRpxkW+FKasRA3tsQ= github.com/efficientgo/tools/core v0.0.0-20220225185207-fe763185946b/go.mod h1:OmVcnJopJL8d3X3sSXTiypGoUSgFq1aDGmlrdi9dn/M= +github.com/elastic/go-sysinfo v1.8.1/go.mod h1:JfllUnzoQV/JRYymbH3dO1yggI3mV2oTKSXsDHM+uIM= github.com/elastic/go-sysinfo v1.11.2 h1:mcm4OSYVMyws6+n2HIVMGkln5HOpo5Ie1ZmbbNn0jg4= github.com/elastic/go-sysinfo v1.11.2/go.mod h1:GKqR8bbMK/1ITnez9NIsIfXQr25aLhRJa7AfT8HpBFQ= +github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0= github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw= @@ -1432,6 +1456,7 @@ github.com/google/go-pkcs11 v0.3.0/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMc github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/pprof v0.0.0-20240416155748-26353dc0451f/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg= @@ -1443,9 +1468,13 @@ github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/enterprise-certificate-proxy v0.3.3/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/googleapis/gax-go/v2 v2.12.5/go.mod h1:BUDKcWo+RaKq5SC9vVYL0wLADa3VcfswbOMMRmB9H3E= +github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= +github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk= github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0= github.com/googleapis/go-type-adapters v1.0.0 h1:9XdMn+d/G57qq1s8dNc5IesGCXHf6V2HZ2JwRxfA2tA= github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720 h1:zC34cGQu69FG7qzJ3WiKW244WfhDC3xxYMeNOX2gtUQ= @@ -1472,6 +1501,8 @@ github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJr github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hamba/avro/v2 v2.27.0 h1:IAM4lQ0VzUIKBuo4qlAiLKfqALSrFC+zi1iseTtbBKU= @@ -1542,6 +1573,7 @@ github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInw github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= github.com/jedib0t/go-pretty/v6 v6.2.4 h1:wdaj2KHD2W+mz8JgJ/Q6L/T5dB7kyqEFI16eLq7GEmk= github.com/jedib0t/go-pretty/v6 v6.2.4/go.mod h1:+nE9fyyHGil+PuISTCrp7avEdo6bqoMwqZnuiK2r2a0= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.1-0.20181029123624-5de817a9aa20/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/gopoet v0.1.0 h1:gYjOPnzHd2nzB37xYQZxj4EIQNpBrBskRqQQ3q4ZgSg= github.com/jhump/goprotoc v0.5.0 h1:Y1UgUX+txUznfqcGdDef8ZOVlyQvnV0pKWZH08RmZuo= @@ -1583,7 +1615,9 @@ github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46 h1:veS9QfglfvqAw2e+eeNT/SbGySq8ajECXJ9e4fPoLhY= github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s= github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= @@ -1635,6 +1669,8 @@ github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04 github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM= github.com/mfridman/xflag v0.0.0-20240825232106-efb77353e578 h1:CRrqlUmLebb/QjzRDWE0E66+YyN/v95+w6WyH9ju8/Y= github.com/mfridman/xflag v0.0.0-20240825232106-efb77353e578/go.mod h1:/483ywM5ZO5SuMVjrIGquYNE5CzLrj5Ux/LxWWnjRaE= +github.com/mfridman/xflag v0.1.0 h1:TWZrZwG1QklFX5S4j1vxfF1sZbZeZSGofMwPMLAF29M= +github.com/mfridman/xflag v0.1.0/go.mod h1:/483ywM5ZO5SuMVjrIGquYNE5CzLrj5Ux/LxWWnjRaE= github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= @@ -1772,6 +1808,7 @@ github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceive github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/openfga/api/proto v0.0.0-20240905181937-3583905f61a6/go.mod h1:gil5LBD8tSdFQbUkCQdnXsoeU9kDJdJgbGdHkgJfcd0= github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= @@ -1785,11 +1822,13 @@ github.com/parquet-go/parquet-go v0.23.0 h1:dyEU5oiHCtbASyItMCD2tXtT2nPmoPbKpqf0 github.com/parquet-go/parquet-go v0.23.0/go.mod h1:MnwbUcFHU6uBYMymKAlPPAw9yh3kE1wWl6Gl1uLdkNk= github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU= github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU= +github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30 h1:BHT1/DKsYDGkUgQ2jmMaozVcdk+sVfz0+1ZJq4zkWgw= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/performancecopilot/speed/v4 v4.0.0 h1:VxEDCmdkfbQYDlcr/GC9YoN9PQ6p8ulk9xVsepYy9ZY= github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= @@ -1812,10 +1851,13 @@ github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8 github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= +github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/common/assets v0.2.0 h1:0P5OrzoHrYBOSM1OigWL3mY8ZvV2N4zIE/5AahrSrfM= +github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/prometheus v0.52.0 h1:f7kHJgr7+zShpWdTCeKqbCWR7nKTScgLYQwRux9h1V0= github.com/prometheus/prometheus v0.52.0/go.mod h1:3z74cVsmVH0iXOR5QBjB7Pa6A0KJeEAK5A6UsmAFb1g= github.com/prometheus/statsd_exporter v0.26.0 h1:SQl3M6suC6NWQYEzOvIv+EF6dAMYEqIuZy+o4H9F5Ig= @@ -1859,8 +1901,10 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad h1:fiWzISvDn0Csy5H0iwgAuJGQTUpVfEMJJd4nRFXogbc= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stoewer/parquet-cli v0.0.7 h1:rhdZODIbyMS3twr4OM3am8BPPT5pbfMcHLH93whDM5o= github.com/stoewer/parquet-cli v0.0.7/go.mod h1:bskxHdj8q3H1EmfuCqjViFoeO3NEvs5lzZAQvI8Nfjk= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -1880,6 +1924,8 @@ github.com/tdewolff/parse/v2 v2.6.8 h1:mhNZXYCx//xG7Yq2e/kVLNZw4YfYmeHbhx+Zc0OvF github.com/tdewolff/parse/v2 v2.6.8/go.mod h1:XHDhaU6IBgsryfdnpzUXBlT6leW/l25yrFBTEb4eIyM= github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94= github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= @@ -1919,7 +1965,9 @@ github.com/willf/bloom v2.0.3+incompatible h1:QDacWdqcAUI1MPOwIQZRy9kOR7yxfyEmxX github.com/willf/bloom v2.0.3+incompatible/go.mod h1:MmAltL9pDMNTrvUkxdg0k0q5I0suxmuwp3KbyrZLOZ8= github.com/xanzy/go-gitlab v0.15.0 h1:rWtwKTgEnXyNUGrOArN7yyc3THRkpYcKXIXia9abywQ= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0= @@ -1934,8 +1982,12 @@ github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow= github.com/ydb-platform/ydb-go-genproto v0.0.0-20240528144234-5d5a685e41f7 h1:nL8XwD6fSst7xFUirkaWJmE7kM0CdWRYgu6+YQer1d4= github.com/ydb-platform/ydb-go-genproto v0.0.0-20240528144234-5d5a685e41f7/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I= +github.com/ydb-platform/ydb-go-genproto v0.0.0-20241112172322-ea1f63298f77 h1:LY6cI8cP4B9rrpTleZk95+08kl2gF4rixG7+V/dwL6Q= +github.com/ydb-platform/ydb-go-genproto v0.0.0-20241112172322-ea1f63298f77/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I= github.com/ydb-platform/ydb-go-sdk/v3 v3.80.2 h1:qmZGJQCNx09/r0HDIT2cDDogiOvWikELy13ubM2CFS8= github.com/ydb-platform/ydb-go-sdk/v3 v3.80.2/go.mod h1:IHwuXyolaAmGK2Dp7+dlhsnXphG1pwCoaP/OITT3+tU= +github.com/ydb-platform/ydb-go-sdk/v3 v3.95.3 h1:pgsQPKSFfRFy3JSZMUReCF4CSEwgxA+a5GymvtyRJO0= +github.com/ydb-platform/ydb-go-sdk/v3 v3.95.3/go.mod h1:WiezFS4YCi2vHqbYGQkeu/2MDBYFLix6dIs/pd87Yck= github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA= github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0= github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= @@ -1954,6 +2006,7 @@ go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsX go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= go.etcd.io/gofail v0.1.0 h1:XItAMIhOojXFQMgrxjnd2EIIHun/d5qL0Pf7FzVTkFg= go.etcd.io/gofail v0.1.0/go.mod h1:VZBCXYGZhHAinaBiiqYvuDynvahNsAyLFwB3kEHKz1M= +go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opentelemetry.io/collector v0.102.1 h1:M/ciCcReQsSDYG9bJ2Qwqk7pQILDJ2bM/l0MdeCAvJE= go.opentelemetry.io/collector v0.102.1/go.mod h1:yF1lDRgL/Eksb4/LUnkMjvLvHHpi6wqBVlzp+dACnPM= @@ -2035,10 +2088,12 @@ go.opentelemetry.io/contrib/exporters/autoexport v0.53.0/go.mod h1:lyQF6xQ4iDnMg go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0/go.mod h1:DKdbWcT4GH1D0Y3Sqt/PFXt2naRKDWtU+eE6oLdFNA8= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= go.opentelemetry.io/contrib/propagators/b3 v1.27.0 h1:IjgxbomVrV9za6bRi8fWCNXENs0co37SZedQilP2hm0= go.opentelemetry.io/contrib/propagators/b3 v1.27.0/go.mod h1:Dv9obQz25lCisDvvs4dy28UPh974CxkahRDUPsY7y9E= go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= @@ -2046,6 +2101,9 @@ go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZV go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFufObyB0= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg= +go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= go.opentelemetry.io/otel/bridge/opencensus v1.27.0 h1:ao9aGGHd+G4YfjBpGs6vbkvt5hoC67STlJA9fCnOAcs= go.opentelemetry.io/otel/bridge/opencensus v1.27.0/go.mod h1:uRvWtAAXzyVOST0WMPX5JHGBaAvBws+2F8PcC5gMnTk= go.opentelemetry.io/otel/bridge/opentracing v1.26.0 h1:Q/dHj0DOhfLMAs5u5ucAbC7gy66x9xxsZRLpHCJ4XhI= @@ -2056,6 +2114,7 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0 h1:aLm go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0/go.mod h1:TC1pyCt6G9Sjb4bQpShH+P5R53pO6ZuGnHuuln9xMeE= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0/go.mod h1:h95q0LBGh7hlAC08X2DhSeyIG02YQ0UyioTCVAqRPmc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.25.0/go.mod h1:8GlBGcDk8KKi7n+2S4BT/CPZQYH3erLu0/k64r1MYgo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0/go.mod h1:hYwym2nDEeZfG/motx0p7L7J1N1vyzIThemQsb4g2qY= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0/go.mod h1:e7ciERRhZaOZXVjx5MiL8TK5+Xv7G5Gv5PA2ZDEJdL8= go.opentelemetry.io/otel/exporters/prometheus v0.50.0 h1:2Ewsda6hejmbhGFyUvWZjUThC98Cf8Zy6g0zkIimOng= go.opentelemetry.io/otel/exporters/prometheus v0.50.0/go.mod h1:pMm5PkUo5YwbLiuEf7t2xg4wbP0/eSJrMxIMxKosynY= @@ -2070,13 +2129,21 @@ go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xC go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= +go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw= +go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= +go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= +go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -2102,13 +2169,21 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20220328175248-053ad81199eb/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e h1:qyrTQ++p1afMkO4DPEeLGq/3oTsdlvdH4vqZUBWzUKM= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4= @@ -2124,6 +2199,9 @@ golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= @@ -2140,6 +2218,12 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= @@ -2148,8 +2232,12 @@ golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCA golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2166,6 +2254,12 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808/go.mod h1:KG1lNk5ZFNssSZLrpVb4sMXKMpGwGXOxSG3rnu2gZQQ= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= @@ -2180,9 +2274,14 @@ golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -2194,6 +2293,7 @@ golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= +golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= @@ -2201,6 +2301,10 @@ golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0 golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc= @@ -2211,6 +2315,7 @@ google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWL google.golang.org/api v0.139.0/go.mod h1:CVagp6Eekz9CjGZ718Z+sloknzkDJE7Vc1Ckj9+viBk= google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= google.golang.org/api v0.150.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg= +google.golang.org/api v0.152.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY= google.golang.org/api v0.155.0/go.mod h1:GI5qK5f40kCpHfPn6+YzGAByIKWv8ujFnmoWm7Igduk= google.golang.org/api v0.157.0/go.mod h1:+z4v4ufbZ1WEpld6yMGHyggs+PmAHiaLNj5ytP3N01g= google.golang.org/api v0.160.0/go.mod h1:0mu0TpK33qnydLvWqbImq2b1eQ5FHRSDCBzAxX9ZHyw= @@ -2218,6 +2323,11 @@ google.golang.org/api v0.162.0/go.mod h1:6SulDkfoBIg4NFmCuZ39XeeAgSHCPecfSUuDyYl google.golang.org/api v0.164.0/go.mod h1:2OatzO7ZDQsoS7IFf3rvsE17/TldiU3F/zxFHeqUB5o= google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= google.golang.org/api v0.174.0/go.mod h1:aC7tB6j0HR1Nl0ni5ghpx6iLasmAX78Zkh/wgxAAjLg= +google.golang.org/api v0.177.0/go.mod h1:srbhue4MLjkjbkux5p3dw/ocYOSZTaIEvf7bCOnFQDw= +google.golang.org/api v0.187.0/go.mod h1:KIHlTc4x7N7gKKuVsdmfBXN13yEEWXWFURWY6SBp2gk= +google.golang.org/api v0.196.0/go.mod h1:g9IL21uGkYgvQ5BZg6BAtoGJQIm8r6EgaAbpNey5wBE= +google.golang.org/api v0.197.0/go.mod h1:AuOuo20GoQ331nq7DquGHlU6d+2wN2fZ8O0ta60nRNw= +google.golang.org/api v0.211.0/go.mod h1:XOloB4MXFH4UTlQSGuNUxw0UT74qdENK8d6JNsXKLi0= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= @@ -2247,6 +2357,8 @@ google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqt google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M= google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:s7iA721uChleev562UJO2OYB0PPT9CMFjV+Ce7VJH5M= +google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:hL97c3SYopEHblzpxRL4lSs523++l8DYxGM1FQiYmb4= google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ= google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= @@ -2273,6 +2385,14 @@ google.golang.org/genproto/googleapis/api v0.0.0-20240213162025-012b6fc9bca9/go. google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be/go.mod h1:dvdCTIoAGbkWbcIKBniID56/7XHTt6WfxXNMxuziJ+w= +google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6/go.mod h1:10yRODfgim2/T8csjQsMPgZOMvtytXKTDRzH6HRGzRw= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= +google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4/go.mod h1:px9SlOOZBg1wM1zdnr8jEL4CNGUBZ+ZKYtNPApNQc4c= +google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= +google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4= +google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= +google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:E5//3O5ZIG2l71Xnt+P/CYUY8Bxs8E7WMoZ9tlcMbAY= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230807174057-1744710a1577/go.mod h1:NjCQG/D8JandXxM57PZbAJL1DCNL6EypA0vPPwfsc7c= google.golang.org/genproto/googleapis/bytestream v0.0.0-20231030173426-d783a09b4405/go.mod h1:GRUCuLdzVqZte8+Dl/D4N25yLzcGqqWaYkeVOwulFqw= google.golang.org/genproto/googleapis/bytestream v0.0.0-20231212172506-995d672761c0/go.mod h1:guYXGPwC6jwxgWKW5Y405fKWOFNwlvUlUnzyp9i0uqo= @@ -2311,9 +2431,20 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240228201840-1f18d85a4ec2/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240415141817-7cd4c1c1f9ec/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240429193739-8cf5692501f6/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= @@ -2329,8 +2460,19 @@ google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJai google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= +google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= @@ -2345,10 +2487,13 @@ gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzE gopkg.in/telebot.v3 v3.2.1 h1:3I4LohaAyJBiivGmkfB+CiVu7QFOWkuZ4+KHgO/G3rs= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.3.2 h1:ytYb4rOqyp1TSa2EPvNVwtPQJctSELKaMyLfqNP4+34= honnef.co/go/tools v0.3.2/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw= +howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80= @@ -2402,6 +2547,7 @@ modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/sqlite v1.18.2/go.mod h1:kvrTLEWgxUcHa2GfHBQtanR1H9ht3hTJNtKpzH9k1u0= modernc.org/sqlite v1.21.2/go.mod h1:cxbLkB5WS32DnQqeH4h4o1B0eMr8W/y8/RGuxQ3JsC0= +modernc.org/sqlite v1.34.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k= modernc.org/tcl v1.13.1 h1:npxzTwFTZYM8ghWicVIX1cRWzj7Nd8i6AqqX2p+IYao= modernc.org/tcl v1.13.2/go.mod h1:7CLiGIPo1M8Rv1Mitpv5akc2+8fxUd2y2UzC/MfMzy0= modernc.org/tcl v1.15.1 h1:mOQwiEK4p7HruMZcwKTZPw/aqtGM4aY00uzWhlKKYws= diff --git a/pkg/aggregator/go.mod b/pkg/aggregator/go.mod index ba4d35f73dd..2a35ffcc1d5 100644 --- a/pkg/aggregator/go.mod +++ b/pkg/aggregator/go.mod @@ -54,7 +54,7 @@ require ( github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.3 // indirect - github.com/google/cel-go v0.22.0 // indirect + github.com/google/cel-go v0.22.1 // indirect github.com/google/flatbuffers v24.3.25+incompatible // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect @@ -69,7 +69,7 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-plugin v1.6.2 // indirect github.com/hashicorp/yamux v0.1.1 // indirect @@ -128,7 +128,7 @@ require ( go.opentelemetry.io/otel/metric v1.33.0 // indirect go.opentelemetry.io/otel/sdk v1.33.0 // indirect go.opentelemetry.io/otel/trace v1.33.0 // indirect - go.opentelemetry.io/proto/otlp v1.4.0 // indirect + go.opentelemetry.io/proto/otlp v1.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.32.0 // indirect @@ -144,7 +144,7 @@ require ( golang.org/x/tools v0.29.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect google.golang.org/grpc v1.69.2 // indirect google.golang.org/protobuf v1.36.1 // indirect diff --git a/pkg/aggregator/go.sum b/pkg/aggregator/go.sum index d48c830f717..933c49616d6 100644 --- a/pkg/aggregator/go.sum +++ b/pkg/aggregator/go.sum @@ -110,8 +110,8 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.22.0 h1:b3FJZxpiv1vTMo2/5RDUqAHPxkT8mmMfJIrq1llbf7g= -github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= +github.com/google/cel-go v0.22.1 h1:AfVXx3chM2qwoSbM7Da8g8hX8OVSkBFwX+rz2+PcK40= +github.com/google/cel-go v0.22.1/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI= github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= @@ -154,8 +154,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a534 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340/go.mod h1:3bDW6wMZJB7tiONtC/1Xpicra6Wp5GgbTbQWCbI5fkc= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog= @@ -379,8 +379,8 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= -go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= -go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -481,8 +481,8 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU= google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= diff --git a/pkg/apiserver/go.mod b/pkg/apiserver/go.mod index 4ce2bf40458..a3750033c83 100644 --- a/pkg/apiserver/go.mod +++ b/pkg/apiserver/go.mod @@ -46,7 +46,7 @@ require ( github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -75,7 +75,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 // indirect go.opentelemetry.io/otel/metric v1.33.0 // indirect go.opentelemetry.io/otel/sdk v1.33.0 // indirect - go.opentelemetry.io/proto/otlp v1.4.0 // indirect + go.opentelemetry.io/proto/otlp v1.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/net v0.34.0 // indirect @@ -86,7 +86,7 @@ require ( golang.org/x/time v0.9.0 // indirect golang.org/x/tools v0.29.0 // indirect google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect google.golang.org/grpc v1.69.2 // indirect google.golang.org/protobuf v1.36.1 // indirect diff --git a/pkg/apiserver/go.sum b/pkg/apiserver/go.sum index c660f18b131..46ebe7411b0 100644 --- a/pkg/apiserver/go.sum +++ b/pkg/apiserver/go.sum @@ -89,8 +89,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a534 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340/go.mod h1:3bDW6wMZJB7tiONtC/1Xpicra6Wp5GgbTbQWCbI5fkc= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= @@ -216,8 +216,8 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4Jjx go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= -go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= -go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -298,8 +298,8 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU= google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= diff --git a/pkg/build/go.mod b/pkg/build/go.mod index 025383983bf..1a65469fd40 100644 --- a/pkg/build/go.mod +++ b/pkg/build/go.mod @@ -77,7 +77,7 @@ require ( go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect golang.org/x/sys v0.29.0 // indirect google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect; @grafana/grafana-backend-group - google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) @@ -92,7 +92,7 @@ require ( github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/distribution/reference v0.6.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/term v0.5.0 // indirect @@ -106,7 +106,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 // indirect go.opentelemetry.io/otel/log v0.4.0 // indirect go.opentelemetry.io/otel/sdk/log v0.4.0 // indirect - go.opentelemetry.io/proto/otlp v1.4.0 // indirect + go.opentelemetry.io/proto/otlp v1.5.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect gotest.tools/v3 v3.5.1 // indirect ) diff --git a/pkg/build/go.sum b/pkg/build/go.sum index 23bfbd25ef6..7b709096c0b 100644 --- a/pkg/build/go.sum +++ b/pkg/build/go.sum @@ -146,8 +146,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKG github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q= github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= @@ -259,8 +259,8 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4Jjx go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= -go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= -go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -343,8 +343,8 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU= google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= diff --git a/pkg/promlib/go.mod b/pkg/promlib/go.mod index 58416fa8992..356f85110a7 100644 --- a/pkg/promlib/go.mod +++ b/pkg/promlib/go.mod @@ -53,7 +53,7 @@ require ( github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-plugin v1.6.2 // indirect github.com/hashicorp/yamux v0.1.1 // indirect @@ -100,7 +100,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 // indirect go.opentelemetry.io/otel/metric v1.33.0 // indirect go.opentelemetry.io/otel/sdk v1.33.0 // indirect - go.opentelemetry.io/proto/otlp v1.4.0 // indirect + go.opentelemetry.io/proto/otlp v1.5.0 // indirect go.uber.org/atomic v1.11.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect golang.org/x/mod v0.22.0 // indirect @@ -112,7 +112,7 @@ require ( golang.org/x/tools v0.29.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/api v0.216.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect google.golang.org/grpc v1.69.2 // indirect google.golang.org/protobuf v1.36.1 // indirect diff --git a/pkg/promlib/go.sum b/pkg/promlib/go.sum index 68b0cb9656d..df7e1abe4a4 100644 --- a/pkg/promlib/go.sum +++ b/pkg/promlib/go.sum @@ -132,8 +132,8 @@ github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpS github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 h1:kQ0NI7W1B3HwiN5gAYtY+XFItDPbLBwYRxAqbFTyDes= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0/go.mod h1:zrT2dxOAjNFPRGjTUe2Xmb4q4YdUwVvQFV6xiCSf+z0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog= @@ -318,8 +318,8 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= -go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= -go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -386,8 +386,8 @@ gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0= gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o= google.golang.org/api v0.216.0 h1:xnEHy+xWFrtYInWPy8OdGFsyIfWJjtVnO39g7pz2BFY= google.golang.org/api v0.216.0/go.mod h1:K9wzQMvWi47Z9IU7OgdOofvZuw75Ge3PPITImZR/UyI= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= diff --git a/pkg/storage/unified/apistore/go.mod b/pkg/storage/unified/apistore/go.mod index a2350ab1a9d..83edae6fa1c 100644 --- a/pkg/storage/unified/apistore/go.mod +++ b/pkg/storage/unified/apistore/go.mod @@ -55,6 +55,7 @@ require ( github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect github.com/RoaringBitmap/roaring v1.9.3 // indirect github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // indirect + github.com/Yiling-J/theine-go v0.6.0 // indirect github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/apache/arrow-go/v18 v18.0.1-0.20241212180703-82be143d7c30 // indirect @@ -115,7 +116,6 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/distribution/reference v0.6.0 // indirect github.com/dlmiddlecote/sqlstats v1.0.2 // indirect - github.com/docker/docker v27.4.1+incompatible // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/elazarl/goproxy v1.3.0 // indirect @@ -159,7 +159,7 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.3 // indirect - github.com/google/cel-go v0.22.0 // indirect + github.com/google/cel-go v0.22.1 // indirect github.com/google/flatbuffers v24.3.25+incompatible // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect @@ -185,7 +185,7 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect @@ -203,7 +203,7 @@ require ( github.com/invopop/yaml v0.3.1 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect - github.com/jackc/pgx/v5 v5.7.1 // indirect + github.com/jackc/pgx/v5 v5.7.2 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jeremywohl/flatten v1.0.1 // indirect github.com/jessevdk/go-flags v1.5.0 // indirect @@ -215,7 +215,6 @@ require ( github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect - github.com/karlseguin/ccache/v3 v3.0.5 // indirect github.com/klauspost/compress v1.17.11 // indirect github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/kylelemons/godebug v1.1.0 // indirect @@ -256,9 +255,9 @@ require ( github.com/oklog/ulid v1.3.1 // indirect github.com/oklog/ulid/v2 v2.1.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66 // indirect - github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f // indirect - github.com/openfga/openfga v1.6.2 // indirect + github.com/openfga/api/proto v0.0.0-20250107154247-c22e6db5c4f5 // indirect + github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20241115164311-10e575c8e47c // indirect + github.com/openfga/openfga v1.8.4 // indirect github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect @@ -268,7 +267,7 @@ require ( github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/pressly/goose/v3 v3.22.1 // indirect + github.com/pressly/goose/v3 v3.24.0 // indirect github.com/prometheus/alertmanager v0.27.0 // indirect github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_model v0.6.1 // indirect @@ -324,9 +323,9 @@ require ( go.opentelemetry.io/otel/metric v1.33.0 // indirect go.opentelemetry.io/otel/sdk v1.33.0 // indirect go.opentelemetry.io/otel/trace v1.33.0 // indirect - go.opentelemetry.io/proto/otlp v1.4.0 // indirect + go.opentelemetry.io/proto/otlp v1.5.0 // indirect go.uber.org/atomic v1.11.0 // indirect - go.uber.org/mock v0.4.0 // indirect + go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.32.0 // indirect @@ -343,7 +342,7 @@ require ( gonum.org/v1/gonum v0.15.1 // indirect google.golang.org/api v0.216.0 // indirect google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect google.golang.org/protobuf v1.36.1 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect @@ -362,7 +361,7 @@ require ( modernc.org/libc v1.55.3 // indirect modernc.org/mathutil v1.6.0 // indirect modernc.org/memory v1.8.0 // indirect - modernc.org/sqlite v1.33.1 // indirect + modernc.org/sqlite v1.34.4 // indirect modernc.org/strutil v1.2.0 // indirect modernc.org/token v1.1.0 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 // indirect diff --git a/pkg/storage/unified/apistore/go.sum b/pkg/storage/unified/apistore/go.sum index 73a81896f45..42f2f860903 100644 --- a/pkg/storage/unified/apistore/go.sum +++ b/pkg/storage/unified/apistore/go.sum @@ -111,6 +111,8 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f h1:HR5nRmUQgXrwqZOwZ2DAc/aCi3Bu3xENpspW935vxu0= github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f/go.mod h1:f3HiCrHjHBdcm6E83vGaXh1KomZMA2P6aeo3hKx/wg0= +github.com/Yiling-J/theine-go v0.6.0 h1:jv7V/tcD6ijL0T4kfbJDKP81TCZBkoriNTPSqwivWuY= +github.com/Yiling-J/theine-go v0.6.0/go.mod h1:mdch1vjgGWd7s3rWKvY+MF5InRLfRv/CWVI9RVNQ8wY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -473,8 +475,8 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.22.0 h1:b3FJZxpiv1vTMo2/5RDUqAHPxkT8mmMfJIrq1llbf7g= -github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= +github.com/google/cel-go v0.22.1 h1:AfVXx3chM2qwoSbM7Da8g8hX8OVSkBFwX+rz2+PcK40= +github.com/google/cel-go v0.22.1/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI= github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= @@ -583,8 +585,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a534 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340/go.mod h1:3bDW6wMZJB7tiONtC/1Xpicra6Wp5GgbTbQWCbI5fkc= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= @@ -642,8 +644,8 @@ github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5ey github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= -github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= -github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI= +github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jeremywohl/flatten v1.0.1 h1:LrsxmB3hfwJuE+ptGOijix1PIfOoKLJ3Uee/mzbgtrs= @@ -688,8 +690,6 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= -github.com/karlseguin/ccache/v3 v3.0.5 h1:hFX25+fxzNjsRlREYsoGNa2LoVEw5mPF8wkWq/UnevQ= -github.com/karlseguin/ccache/v3 v3.0.5/go.mod h1:qxC372+Qn+IBj8Pe3KvGjHPj0sWwEF7AeZVhsNPZ6uY= github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= @@ -831,12 +831,12 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= -github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66 h1:pAYrdyIKxPsMs/nRcTEnS9za2io11g7Rt7ng7HK82hk= -github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66/go.mod h1:gil5LBD8tSdFQbUkCQdnXsoeU9kDJdJgbGdHkgJfcd0= -github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f h1:ZMZ7ntMnaHIPZxvVQv/aqC4ctzLqH+9Fqn4uw35kQpk= -github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f/go.mod h1:ll/hN6kS4EE6B/7J/PbZqac9Nuv7ZHpI+Jfh36JLrbs= -github.com/openfga/openfga v1.6.2 h1:tHBAgiCPomCZb3IH0CFqOpTDVDA/Xb8kG87oX4JCbXc= -github.com/openfga/openfga v1.6.2/go.mod h1:jzbEpheazf6MFjtanQt1rpxexSRzfa9057F7JlkMv2I= +github.com/openfga/api/proto v0.0.0-20250107154247-c22e6db5c4f5 h1:z9jaRoo+NIN1AB0ogjtrjx1316TTuq6IbqpEg3UJycA= +github.com/openfga/api/proto v0.0.0-20250107154247-c22e6db5c4f5/go.mod h1:m74TNgnAAIJ03gfHcx+xaRWnr+IbQy3y/AVNwwCFrC0= +github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20241115164311-10e575c8e47c h1:1y84C0V4NRfPtRi4MqQ7+gnFtYgeBKPIeIAPLdVJ7j4= +github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20241115164311-10e575c8e47c/go.mod h1:12RMe/HuRNyOzS33RQa53jwdcxE2znr8ycXMlVbgQN4= +github.com/openfga/openfga v1.8.4 h1:OqyRpuxMCxcS7irTFYFkhAIYzmAnczNwxUqjnuZOQyo= +github.com/openfga/openfga v1.8.4/go.mod h1:9Ax9VMMySV2JMsCT8MTePeYt4OrTnPAy1XUV1y9RyuU= github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w= github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -865,8 +865,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pressly/goose/v3 v3.22.1 h1:2zICEfr1O3yTP9BRZMGPj7qFxQ+ik6yeo+z1LMuioLc= -github.com/pressly/goose/v3 v3.22.1/go.mod h1:xtMpbstWyCpyH+0cxLTMCENWBG+0CSxvTsXhW95d5eo= +github.com/pressly/goose/v3 v3.24.0 h1:sFbNms7Bd++2VMq6HSgDHDLWa7kHz1qXzPb3ZIU72VU= +github.com/pressly/goose/v3 v3.24.0/go.mod h1:rEWreU9uVtt0DHCyLzF9gRcWiiTF/V+528DV+4DORug= github.com/prometheus/alertmanager v0.27.0 h1:V6nTa2J5V4s8TG4C4HtrBP/WNSebCCTYGGv4qecA/+I= github.com/prometheus/alertmanager v0.27.0/go.mod h1:8Ia/R3urPmbzJ8OsdvmZvIprDwvwmYCmUbwBL+jlPOE= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -1095,16 +1095,16 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= -go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= -go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -1465,8 +1465,8 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU= google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -1586,8 +1586,8 @@ modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= -modernc.org/sqlite v1.33.1 h1:trb6Z3YYoeM9eDL1O8do81kP+0ejv+YzgyFo+Gwy0nM= -modernc.org/sqlite v1.33.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k= +modernc.org/sqlite v1.34.4 h1:sjdARozcL5KJBvYQvLlZEmctRgW9xqIZc2ncN7PU0P8= +modernc.org/sqlite v1.34.4/go.mod h1:3QQFCG2SEMtc2nv+Wq4cQCH7Hjcg+p/RMlS1XK+zwbk= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/pkg/storage/unified/resource/go.mod b/pkg/storage/unified/resource/go.mod index 36be0fe79ac..c5442aa3237 100644 --- a/pkg/storage/unified/resource/go.mod +++ b/pkg/storage/unified/resource/go.mod @@ -126,7 +126,7 @@ require ( github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect github.com/grafana/sqlds/v4 v4.1.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect @@ -214,7 +214,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 // indirect go.opentelemetry.io/otel/metric v1.33.0 // indirect go.opentelemetry.io/otel/sdk v1.33.0 // indirect - go.opentelemetry.io/proto/otlp v1.4.0 // indirect + go.opentelemetry.io/proto/otlp v1.5.0 // indirect go.uber.org/atomic v1.11.0 // indirect golang.org/x/crypto v0.32.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect @@ -229,7 +229,7 @@ require ( golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/api v0.216.0 // indirect google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/pkg/storage/unified/resource/go.sum b/pkg/storage/unified/resource/go.sum index b0e3e3d8b29..4ab42a45d97 100644 --- a/pkg/storage/unified/resource/go.sum +++ b/pkg/storage/unified/resource/go.sum @@ -71,6 +71,8 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f h1:HR5nRmUQgXrwqZOwZ2DAc/aCi3Bu3xENpspW935vxu0= github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f/go.mod h1:f3HiCrHjHBdcm6E83vGaXh1KomZMA2P6aeo3hKx/wg0= +github.com/Yiling-J/theine-go v0.6.0 h1:jv7V/tcD6ijL0T4kfbJDKP81TCZBkoriNTPSqwivWuY= +github.com/Yiling-J/theine-go v0.6.0/go.mod h1:mdch1vjgGWd7s3rWKvY+MF5InRLfRv/CWVI9RVNQ8wY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -351,8 +353,8 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.22.0 h1:b3FJZxpiv1vTMo2/5RDUqAHPxkT8mmMfJIrq1llbf7g= -github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= +github.com/google/cel-go v0.22.1 h1:AfVXx3chM2qwoSbM7Da8g8hX8OVSkBFwX+rz2+PcK40= +github.com/google/cel-go v0.22.1/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8= github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI= github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= @@ -434,8 +436,8 @@ github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpS github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 h1:kQ0NI7W1B3HwiN5gAYtY+XFItDPbLBwYRxAqbFTyDes= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0/go.mod h1:zrT2dxOAjNFPRGjTUe2Xmb4q4YdUwVvQFV6xiCSf+z0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= @@ -487,8 +489,8 @@ github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7Ulw github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgx v3.2.0+incompatible h1:0Vihzu20St42/UDsvZGdNE6jak7oi/UOeMzwMPHkgFY= github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= -github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= -github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI= +github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jeremywohl/flatten v1.0.1 h1:LrsxmB3hfwJuE+ptGOijix1PIfOoKLJ3Uee/mzbgtrs= @@ -526,8 +528,6 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= -github.com/karlseguin/ccache/v3 v3.0.5 h1:hFX25+fxzNjsRlREYsoGNa2LoVEw5mPF8wkWq/UnevQ= -github.com/karlseguin/ccache/v3 v3.0.5/go.mod h1:qxC372+Qn+IBj8Pe3KvGjHPj0sWwEF7AeZVhsNPZ6uY= github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= @@ -651,12 +651,12 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66 h1:pAYrdyIKxPsMs/nRcTEnS9za2io11g7Rt7ng7HK82hk= -github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66/go.mod h1:gil5LBD8tSdFQbUkCQdnXsoeU9kDJdJgbGdHkgJfcd0= -github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f h1:ZMZ7ntMnaHIPZxvVQv/aqC4ctzLqH+9Fqn4uw35kQpk= -github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f/go.mod h1:ll/hN6kS4EE6B/7J/PbZqac9Nuv7ZHpI+Jfh36JLrbs= -github.com/openfga/openfga v1.6.2 h1:tHBAgiCPomCZb3IH0CFqOpTDVDA/Xb8kG87oX4JCbXc= -github.com/openfga/openfga v1.6.2/go.mod h1:jzbEpheazf6MFjtanQt1rpxexSRzfa9057F7JlkMv2I= +github.com/openfga/api/proto v0.0.0-20250107154247-c22e6db5c4f5 h1:z9jaRoo+NIN1AB0ogjtrjx1316TTuq6IbqpEg3UJycA= +github.com/openfga/api/proto v0.0.0-20250107154247-c22e6db5c4f5/go.mod h1:m74TNgnAAIJ03gfHcx+xaRWnr+IbQy3y/AVNwwCFrC0= +github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20241115164311-10e575c8e47c h1:1y84C0V4NRfPtRi4MqQ7+gnFtYgeBKPIeIAPLdVJ7j4= +github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20241115164311-10e575c8e47c/go.mod h1:12RMe/HuRNyOzS33RQa53jwdcxE2znr8ycXMlVbgQN4= +github.com/openfga/openfga v1.8.4 h1:OqyRpuxMCxcS7irTFYFkhAIYzmAnczNwxUqjnuZOQyo= +github.com/openfga/openfga v1.8.4/go.mod h1:9Ax9VMMySV2JMsCT8MTePeYt4OrTnPAy1XUV1y9RyuU= github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w= github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= @@ -683,8 +683,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pressly/goose/v3 v3.22.1 h1:2zICEfr1O3yTP9BRZMGPj7qFxQ+ik6yeo+z1LMuioLc= -github.com/pressly/goose/v3 v3.22.1/go.mod h1:xtMpbstWyCpyH+0cxLTMCENWBG+0CSxvTsXhW95d5eo= +github.com/pressly/goose/v3 v3.24.0 h1:sFbNms7Bd++2VMq6HSgDHDLWa7kHz1qXzPb3ZIU72VU= +github.com/pressly/goose/v3 v3.24.0/go.mod h1:rEWreU9uVtt0DHCyLzF9gRcWiiTF/V+528DV+4DORug= github.com/prometheus/alertmanager v0.27.0 h1:V6nTa2J5V4s8TG4C4HtrBP/WNSebCCTYGGv4qecA/+I= github.com/prometheus/alertmanager v0.27.0/go.mod h1:8Ia/R3urPmbzJ8OsdvmZvIprDwvwmYCmUbwBL+jlPOE= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -863,14 +863,14 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= -go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= -go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= @@ -1059,8 +1059,8 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU= google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o= -google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA= +google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw= google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -1142,8 +1142,8 @@ modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= -modernc.org/sqlite v1.33.1 h1:trb6Z3YYoeM9eDL1O8do81kP+0ejv+YzgyFo+Gwy0nM= -modernc.org/sqlite v1.33.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k= +modernc.org/sqlite v1.34.4 h1:sjdARozcL5KJBvYQvLlZEmctRgW9xqIZc2ncN7PU0P8= +modernc.org/sqlite v1.34.4/go.mod h1:3QQFCG2SEMtc2nv+Wq4cQCH7Hjcg+p/RMlS1XK+zwbk= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= From f9a61e2eb27f1c6dc0d6b2bce6df3ea7863cfeaf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2025 09:49:39 +0100 Subject: [PATCH 29/30] Update React Aria (#99129) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 8 +- packages/grafana-ui/package.json | 8 +- yarn.lock | 264 ++++++++++++++++--------------- 3 files changed, 143 insertions(+), 137 deletions(-) diff --git a/package.json b/package.json index a904ada7489..4bcc5e3ba64 100644 --- a/package.json +++ b/package.json @@ -291,10 +291,10 @@ "@opentelemetry/exporter-collector": "0.25.0", "@opentelemetry/semantic-conventions": "1.28.0", "@popperjs/core": "2.11.8", - "@react-aria/dialog": "3.5.20", - "@react-aria/focus": "3.19.0", - "@react-aria/overlays": "3.24.0", - "@react-aria/utils": "3.26.0", + "@react-aria/dialog": "3.5.21", + "@react-aria/focus": "3.19.1", + "@react-aria/overlays": "3.25.0", + "@react-aria/utils": "3.27.0", "@react-awesome-query-builder/ui": "6.6.4", "@reduxjs/toolkit": "2.5.0", "@visx/event": "3.12.0", diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 1e8f79787fd..097e3879733 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -58,10 +58,10 @@ "@leeoniya/ufuzzy": "1.0.18", "@monaco-editor/react": "4.6.0", "@popperjs/core": "2.11.8", - "@react-aria/dialog": "3.5.20", - "@react-aria/focus": "3.19.0", - "@react-aria/overlays": "3.24.0", - "@react-aria/utils": "3.26.0", + "@react-aria/dialog": "3.5.21", + "@react-aria/focus": "3.19.1", + "@react-aria/overlays": "3.25.0", + "@react-aria/utils": "3.27.0", "@tanstack/react-virtual": "^3.5.1", "@types/jquery": "3.5.32", "@types/lodash": "4.17.14", diff --git a/yarn.lock b/yarn.lock index f44165df0ff..760fac248e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3817,10 +3817,10 @@ __metadata: "@leeoniya/ufuzzy": "npm:1.0.18" "@monaco-editor/react": "npm:4.6.0" "@popperjs/core": "npm:2.11.8" - "@react-aria/dialog": "npm:3.5.20" - "@react-aria/focus": "npm:3.19.0" - "@react-aria/overlays": "npm:3.24.0" - "@react-aria/utils": "npm:3.26.0" + "@react-aria/dialog": "npm:3.5.21" + "@react-aria/focus": "npm:3.19.1" + "@react-aria/overlays": "npm:3.25.0" + "@react-aria/utils": "npm:3.27.0" "@rollup/plugin-node-resolve": "npm:16.0.0" "@storybook/addon-a11y": "npm:^8.4.2" "@storybook/addon-actions": "npm:^8.4.2" @@ -4079,12 +4079,12 @@ __metadata: languageName: node linkType: hard -"@internationalized/date@npm:^3.6.0": - version: 3.6.0 - resolution: "@internationalized/date@npm:3.6.0" +"@internationalized/date@npm:^3.7.0": + version: 3.7.0 + resolution: "@internationalized/date@npm:3.7.0" dependencies: "@swc/helpers": "npm:^0.5.0" - checksum: 10/862a34376ff1e36da0afa4a667b62183d7a480eb7c5b919b0a6e1450f4162bc8a6c8941e073a4fb0c6fce6d9420894051235f9e604ee1162fae7b59972a64d88 + checksum: 10/59adffb57f1391e17bfe9b2e9b1a71c0957a1835b0176a86ad5a99fd2f2919f094d3f553fb39be157d84c315a88917e0eda779c9101026e3bfac217ace18a559 languageName: node linkType: hard @@ -6199,89 +6199,92 @@ __metadata: languageName: node linkType: hard -"@react-aria/dialog@npm:3.5.20": - version: 3.5.20 - resolution: "@react-aria/dialog@npm:3.5.20" +"@react-aria/dialog@npm:3.5.21": + version: 3.5.21 + resolution: "@react-aria/dialog@npm:3.5.21" dependencies: - "@react-aria/focus": "npm:^3.19.0" - "@react-aria/overlays": "npm:^3.24.0" - "@react-aria/utils": "npm:^3.26.0" - "@react-types/dialog": "npm:^3.5.14" - "@react-types/shared": "npm:^3.26.0" + "@react-aria/focus": "npm:^3.19.1" + "@react-aria/overlays": "npm:^3.25.0" + "@react-aria/utils": "npm:^3.27.0" + "@react-types/dialog": "npm:^3.5.15" + "@react-types/shared": "npm:^3.27.0" "@swc/helpers": "npm:^0.5.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/a3e18df7495fc659d46c0ae61ae6addcd55fc6e512f0562c3e31d9e43cb5a95f7f49f6e840894b594839533681701606af804e70ff4c4b22ac4c7f0224f3c817 + checksum: 10/8531bef34f17c929ebf50caf44e11f69f34475b08893df8ac59eeb18e82e9da8f9eada7379563668aa655c895b86c5f0cd0bb322292a196f2b9638b67228ed52 languageName: node linkType: hard -"@react-aria/focus@npm:3.19.0, @react-aria/focus@npm:^3.19.0": - version: 3.19.0 - resolution: "@react-aria/focus@npm:3.19.0" +"@react-aria/focus@npm:3.19.1, @react-aria/focus@npm:^3.19.1": + version: 3.19.1 + resolution: "@react-aria/focus@npm:3.19.1" dependencies: - "@react-aria/interactions": "npm:^3.22.5" - "@react-aria/utils": "npm:^3.26.0" - "@react-types/shared": "npm:^3.26.0" + "@react-aria/interactions": "npm:^3.23.0" + "@react-aria/utils": "npm:^3.27.0" + "@react-types/shared": "npm:^3.27.0" "@swc/helpers": "npm:^0.5.0" clsx: "npm:^2.0.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/4b507c382ce83b698637464094257af23abdfa1a096486cdf898d0e8db120dcd87035b59dab8855180cc1671e89d410b8812936100a1502ead01f80b52dfa4e9 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/2fe5e880c4d7f3fb612ba8f5ec46e3a6ef761dc8066ad51c043ec0c90b9f5985f49b9ef8e902f75f2bc37e75e54271aa1997afd03a0fd12c5df386190688a761 languageName: node linkType: hard -"@react-aria/i18n@npm:^3.12.4": - version: 3.12.4 - resolution: "@react-aria/i18n@npm:3.12.4" +"@react-aria/i18n@npm:^3.12.5": + version: 3.12.5 + resolution: "@react-aria/i18n@npm:3.12.5" dependencies: - "@internationalized/date": "npm:^3.6.0" + "@internationalized/date": "npm:^3.7.0" "@internationalized/message": "npm:^3.1.6" "@internationalized/number": "npm:^3.6.0" "@internationalized/string": "npm:^3.2.5" "@react-aria/ssr": "npm:^3.9.7" - "@react-aria/utils": "npm:^3.26.0" - "@react-types/shared": "npm:^3.26.0" - "@swc/helpers": "npm:^0.5.0" - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/3a62d641ed23b96378d82f252cecf17071ca842a2d964e35c9764a7ad1f7f4815472e8f9bf54fe094d15e81f3fb4b982b2b2949298f79ef1a7e2e6b538e1a12a - languageName: node - linkType: hard - -"@react-aria/interactions@npm:^3.22.5": - version: 3.22.5 - resolution: "@react-aria/interactions@npm:3.22.5" - dependencies: - "@react-aria/ssr": "npm:^3.9.7" - "@react-aria/utils": "npm:^3.26.0" - "@react-types/shared": "npm:^3.26.0" - "@swc/helpers": "npm:^0.5.0" - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/058fbbfd295471bde94cbe6501d5ebb64d1371c455e43c8c55daf6edd02983f73eb1eb716dd03b96c275aed26fa16a355a35f3daffefc54904576d5d26b4458e - languageName: node - linkType: hard - -"@react-aria/overlays@npm:3.24.0, @react-aria/overlays@npm:^3.24.0": - version: 3.24.0 - resolution: "@react-aria/overlays@npm:3.24.0" - dependencies: - "@react-aria/focus": "npm:^3.19.0" - "@react-aria/i18n": "npm:^3.12.4" - "@react-aria/interactions": "npm:^3.22.5" - "@react-aria/ssr": "npm:^3.9.7" - "@react-aria/utils": "npm:^3.26.0" - "@react-aria/visually-hidden": "npm:^3.8.18" - "@react-stately/overlays": "npm:^3.6.12" - "@react-types/button": "npm:^3.10.1" - "@react-types/overlays": "npm:^3.8.11" - "@react-types/shared": "npm:^3.26.0" + "@react-aria/utils": "npm:^3.27.0" + "@react-types/shared": "npm:^3.27.0" "@swc/helpers": "npm:^0.5.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/32bb00a435af82dfb57561737082fb0ac2361954fe217be25c84011bdaf23e683201b0142ba3d1137c90be713894b94c68ae8db4dc269cb09f449673ffa7dcb6 + checksum: 10/bfbc3a63fd8a6aeda219b60fa447db17e27d05c7a6b24ee030171721cfe3da812880f5fd257552e174b6aea0a209f71807491704bb71ad45db8949718e3aeac0 + languageName: node + linkType: hard + +"@react-aria/interactions@npm:^3.23.0": + version: 3.23.0 + resolution: "@react-aria/interactions@npm:3.23.0" + dependencies: + "@react-aria/ssr": "npm:^3.9.7" + "@react-aria/utils": "npm:^3.27.0" + "@react-types/shared": "npm:^3.27.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/915f408708045b38fb25398b2de03610c246f571cb9414c46c00e3e51d3b2abafe778357c1720ff15dc8255fcc023b7eeff7205ddeb60ae3d1b5521f36220e24 + languageName: node + linkType: hard + +"@react-aria/overlays@npm:3.25.0, @react-aria/overlays@npm:^3.25.0": + version: 3.25.0 + resolution: "@react-aria/overlays@npm:3.25.0" + dependencies: + "@react-aria/focus": "npm:^3.19.1" + "@react-aria/i18n": "npm:^3.12.5" + "@react-aria/interactions": "npm:^3.23.0" + "@react-aria/ssr": "npm:^3.9.7" + "@react-aria/utils": "npm:^3.27.0" + "@react-aria/visually-hidden": "npm:^3.8.19" + "@react-stately/overlays": "npm:^3.6.13" + "@react-types/button": "npm:^3.10.2" + "@react-types/overlays": "npm:^3.8.12" + "@react-types/shared": "npm:^3.27.0" + "@swc/helpers": "npm:^0.5.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/8d868cde9c02c39faa9219ce7eb0441889f8fbde78c73a0db911957ef3355b0d5448c0b47b9a3d491c31e9f3e7939c763f99a5689747be6f97ddb060794b3b7f languageName: node linkType: hard @@ -6296,32 +6299,34 @@ __metadata: languageName: node linkType: hard -"@react-aria/utils@npm:3.26.0, @react-aria/utils@npm:^3.26.0": - version: 3.26.0 - resolution: "@react-aria/utils@npm:3.26.0" +"@react-aria/utils@npm:3.27.0, @react-aria/utils@npm:^3.27.0": + version: 3.27.0 + resolution: "@react-aria/utils@npm:3.27.0" dependencies: "@react-aria/ssr": "npm:^3.9.7" "@react-stately/utils": "npm:^3.10.5" - "@react-types/shared": "npm:^3.26.0" + "@react-types/shared": "npm:^3.27.0" "@swc/helpers": "npm:^0.5.0" clsx: "npm:^2.0.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/484cfbc553b3313d291a78bbfd3fcc435ce36b7fc5408935be027f22f41e73b69306d67aa0bcf5e010f0059d4a6776217110f95012001699fc9d37da54963c7b + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/cacf892a6ae80bef854cd7278320cfc0fdc2582e27bcc57ad9fb5be1174dfc5370132592933921fbe633f4d7a6e0a0293ae607a973b23748d01ea1cae0d49205 languageName: node linkType: hard -"@react-aria/visually-hidden@npm:^3.8.18": - version: 3.8.18 - resolution: "@react-aria/visually-hidden@npm:3.8.18" +"@react-aria/visually-hidden@npm:^3.8.19": + version: 3.8.19 + resolution: "@react-aria/visually-hidden@npm:3.8.19" dependencies: - "@react-aria/interactions": "npm:^3.22.5" - "@react-aria/utils": "npm:^3.26.0" - "@react-types/shared": "npm:^3.26.0" + "@react-aria/interactions": "npm:^3.23.0" + "@react-aria/utils": "npm:^3.27.0" + "@react-types/shared": "npm:^3.27.0" "@swc/helpers": "npm:^0.5.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/4f068dbeeaf3751c526bf7d1467d9eeca43a6e665d5e9245b3556e9c5a43f28eb3c14ff56fffeb0eecbf6282eae0cc17824249bfba9199d97d23374ee733e82e + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/1f4a8a54e87d7a44421e8e033fdffa63a15e5f239d22de76f2bba970189495aed1fd1d42c67635a120ce7a53c715714336f0bebfeaac9f94d2121cd42f776d3e languageName: node linkType: hard @@ -6359,16 +6364,16 @@ __metadata: languageName: node linkType: hard -"@react-stately/overlays@npm:^3.6.12": - version: 3.6.12 - resolution: "@react-stately/overlays@npm:3.6.12" +"@react-stately/overlays@npm:^3.6.13": + version: 3.6.13 + resolution: "@react-stately/overlays@npm:3.6.13" dependencies: "@react-stately/utils": "npm:^3.10.5" - "@react-types/overlays": "npm:^3.8.11" + "@react-types/overlays": "npm:^3.8.12" "@swc/helpers": "npm:^0.5.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/78c448964fea85d148a6d45c723d26df765ca049445077b85a318b1a10f1b888d543318a251ff80f28e9109da2c722160be4657eae5dae0c2865f24039fecb11 + checksum: 10/68972dd8617583ee6ecceb6154c97640048c844f8ea4296d64c867e5d95cd6d96c3feee5207efb063d9ee50b08728cc18ae42510eb36c8351a4d7e3452855aec languageName: node linkType: hard @@ -6383,7 +6388,7 @@ __metadata: languageName: node linkType: hard -"@react-types/button@npm:3.10.1, @react-types/button@npm:^3.10.1": +"@react-types/button@npm:3.10.1": version: 3.10.1 resolution: "@react-types/button@npm:3.10.1" dependencies: @@ -6394,15 +6399,26 @@ __metadata: languageName: node linkType: hard -"@react-types/dialog@npm:^3.5.14": - version: 3.5.14 - resolution: "@react-types/dialog@npm:3.5.14" +"@react-types/button@npm:^3.10.2": + version: 3.10.2 + resolution: "@react-types/button@npm:3.10.2" dependencies: - "@react-types/overlays": "npm:^3.8.11" - "@react-types/shared": "npm:^3.26.0" + "@react-types/shared": "npm:^3.27.0" peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - checksum: 10/4339a86c862832860eeb9be102a77cd1119d1ef968bb51603d8d789ee26404a28fde047203c4b579ee0ba2975cf36a8991cfc750449222c0fa150eed84464499 + checksum: 10/fbc3ac3c11d6ba0f509fa8b26f7de96d77d3ef769fd474d56f1a7f430f727698dd4eb29f0f1dd75de4eb3a3cf9a805a2966e5509c60d1e5ed530f37d1a3ceb58 + languageName: node + linkType: hard + +"@react-types/dialog@npm:^3.5.15": + version: 3.5.15 + resolution: "@react-types/dialog@npm:3.5.15" + dependencies: + "@react-types/overlays": "npm:^3.8.12" + "@react-types/shared": "npm:^3.27.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/fce2f15e9fb9be2e9f13405f7129c5225bd9356c4d049d21c5481de150dfff613ae58705d1bfb20155649100ec48a6139549dacb7936ae7e176e9dde28f3eb36 languageName: node linkType: hard @@ -6418,7 +6434,7 @@ __metadata: languageName: node linkType: hard -"@react-types/overlays@npm:3.8.11, @react-types/overlays@npm:^3.8.11": +"@react-types/overlays@npm:3.8.11": version: 3.8.11 resolution: "@react-types/overlays@npm:3.8.11" dependencies: @@ -6429,7 +6445,18 @@ __metadata: languageName: node linkType: hard -"@react-types/shared@npm:3.26.0, @react-types/shared@npm:^3.26.0": +"@react-types/overlays@npm:^3.8.11, @react-types/overlays@npm:^3.8.12": + version: 3.8.12 + resolution: "@react-types/overlays@npm:3.8.12" + dependencies: + "@react-types/shared": "npm:^3.27.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/3510add3f70c99a56b3dc160a51f5f71e60e958fd3753f2379eb904ff5442fe30d17841dee79ae77ae3b872a003757995074f45d701453186518dd357d204901 + languageName: node + linkType: hard + +"@react-types/shared@npm:3.26.0": version: 3.26.0 resolution: "@react-types/shared@npm:3.26.0" peerDependencies: @@ -6438,6 +6465,15 @@ __metadata: languageName: node linkType: hard +"@react-types/shared@npm:^3.26.0, @react-types/shared@npm:^3.27.0": + version: 3.27.0 + resolution: "@react-types/shared@npm:3.27.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + checksum: 10/359be934dda6404824479d0dfdf9e694414252da4946b4e486f3cc546a080844a7d4f20507041d3f8f6f5a316c05b28785ca3f4377a7f4ea397ed1f21c2646af + languageName: node + linkType: hard + "@reduxjs/toolkit@npm:2.5.0": version: 2.5.0 resolution: "@reduxjs/toolkit@npm:2.5.0" @@ -17402,10 +17438,10 @@ __metadata: "@playwright/test": "npm:1.49.1" "@pmmmwh/react-refresh-webpack-plugin": "npm:0.5.15" "@popperjs/core": "npm:2.11.8" - "@react-aria/dialog": "npm:3.5.20" - "@react-aria/focus": "npm:3.19.0" - "@react-aria/overlays": "npm:3.24.0" - "@react-aria/utils": "npm:3.26.0" + "@react-aria/dialog": "npm:3.5.21" + "@react-aria/focus": "npm:3.19.1" + "@react-aria/overlays": "npm:3.25.0" + "@react-aria/utils": "npm:3.27.0" "@react-awesome-query-builder/ui": "npm:6.6.4" "@react-types/button": "npm:3.10.1" "@react-types/menu": "npm:3.9.13" @@ -24847,22 +24883,7 @@ __metadata: languageName: node linkType: hard -"rc-overflow@npm:^1.3.1": - version: 1.3.2 - resolution: "rc-overflow@npm:1.3.2" - dependencies: - "@babel/runtime": "npm:^7.11.1" - classnames: "npm:^2.2.1" - rc-resize-observer: "npm:^1.0.0" - rc-util: "npm:^5.37.0" - peerDependencies: - react: ">=16.9.0" - react-dom: ">=16.9.0" - checksum: 10/a35d6f035de9e5b71f5762ddaf9757770fadab7d5f5e6bf0451346cffb06027e9de75a8104ca782c71e381f55552588a350905a61083cd23d2fb6f24e2807007 - languageName: node - linkType: hard - -"rc-overflow@npm:^1.3.2": +"rc-overflow@npm:^1.3.1, rc-overflow@npm:^1.3.2": version: 1.4.1 resolution: "rc-overflow@npm:1.4.1" dependencies: @@ -24907,22 +24928,7 @@ __metadata: languageName: node linkType: hard -"rc-resize-observer@npm:^1.0.0, rc-resize-observer@npm:^1.3.1": - version: 1.3.1 - resolution: "rc-resize-observer@npm:1.3.1" - dependencies: - "@babel/runtime": "npm:^7.20.7" - classnames: "npm:^2.2.1" - rc-util: "npm:^5.27.0" - resize-observer-polyfill: "npm:^1.5.1" - peerDependencies: - react: ">=16.9.0" - react-dom: ">=16.9.0" - checksum: 10/71add2ac032464b8ef62a044559396728249fc01cffcd5084c4d9e3b69b22f4ad85308f90e2dea6fce8e23d6a72325f8ba9a2c96697e82d31d6c16453fb2642c - languageName: node - linkType: hard - -"rc-resize-observer@npm:^1.4.0": +"rc-resize-observer@npm:^1.0.0, rc-resize-observer@npm:^1.3.1, rc-resize-observer@npm:^1.4.0": version: 1.4.3 resolution: "rc-resize-observer@npm:1.4.3" dependencies: @@ -25027,7 +25033,7 @@ __metadata: languageName: node linkType: hard -"rc-util@npm:^5.0.1, rc-util@npm:^5.0.6, rc-util@npm:^5.15.0, rc-util@npm:^5.16.1, rc-util@npm:^5.21.0, rc-util@npm:^5.24.4, rc-util@npm:^5.26.0, rc-util@npm:^5.27.0, rc-util@npm:^5.36.0, rc-util@npm:^5.37.0, rc-util@npm:^5.38.0, rc-util@npm:^5.38.1, rc-util@npm:^5.43.0, rc-util@npm:^5.44.1, rc-util@npm:^5.44.3": +"rc-util@npm:^5.0.1, rc-util@npm:^5.0.6, rc-util@npm:^5.15.0, rc-util@npm:^5.16.1, rc-util@npm:^5.21.0, rc-util@npm:^5.24.4, rc-util@npm:^5.26.0, rc-util@npm:^5.36.0, rc-util@npm:^5.37.0, rc-util@npm:^5.38.0, rc-util@npm:^5.38.1, rc-util@npm:^5.43.0, rc-util@npm:^5.44.1, rc-util@npm:^5.44.3": version: 5.44.3 resolution: "rc-util@npm:5.44.3" dependencies: From 5e23b2c07fa5c440daa0de53ffc98fda4a60e323 Mon Sep 17 00:00:00 2001 From: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com> Date: Fri, 17 Jan 2025 10:04:33 +0100 Subject: [PATCH 30/30] Zipkin: Improve error source (#99099) * Zipkin: Improve error source * Revert file name change --- pkg/tsdb/zipkin/client.go | 14 +++++++++++++- pkg/tsdb/zipkin/client_test.go | 11 +++++++++++ pkg/tsdb/zipkin/handler_querydata.go | 2 +- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/pkg/tsdb/zipkin/client.go b/pkg/tsdb/zipkin/client.go index 4002d89ee91..02c5b311629 100644 --- a/pkg/tsdb/zipkin/client.go +++ b/pkg/tsdb/zipkin/client.go @@ -118,7 +118,7 @@ func (z *ZipkinClient) Traces(serviceName string, spanName string) ([][]model.Sp func (z *ZipkinClient) Trace(traceId string) ([]model.SpanModel, error) { trace := []model.SpanModel{} if traceId == "" { - return trace, errors.New("invalid/empty traceId") + return trace, backend.DownstreamError(errors.New("invalid/empty traceId")) } traceUrl, err := url.JoinPath(z.url, "/api/v2/trace", url.QueryEscape(traceId)) @@ -128,6 +128,9 @@ func (z *ZipkinClient) Trace(traceId string) ([]model.SpanModel, error) { res, err := z.httpClient.Get(traceUrl) if err != nil { + if backend.IsDownstreamHTTPError(err) { + return trace, backend.DownstreamError(err) + } return trace, err } @@ -138,6 +141,15 @@ func (z *ZipkinClient) Trace(traceId string) ([]model.SpanModel, error) { } } }() + + if res != nil && res.StatusCode/100 != 2 { + err := backend.DownstreamError(fmt.Errorf("request failed: %s", res.Status)) + if backend.ErrorSourceFromHTTPStatus(res.StatusCode) == backend.ErrorSourceDownstream { + return trace, backend.DownstreamError(err) + } + return trace, err + } + if err := json.NewDecoder(res.Body).Decode(&trace); err != nil { return trace, err } diff --git a/pkg/tsdb/zipkin/client_test.go b/pkg/tsdb/zipkin/client_test.go index c62d10b8d97..6ef7e0ce1c4 100644 --- a/pkg/tsdb/zipkin/client_test.go +++ b/pkg/tsdb/zipkin/client_test.go @@ -2,11 +2,14 @@ package zipkin import ( "encoding/json" + "errors" + "fmt" "net/http" "net/http/httptest" "net/url" "testing" + "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/log" "github.com/openzipkin/zipkin-go/model" "github.com/stretchr/testify/assert" @@ -17,29 +20,37 @@ func TestZipkinClient_Services(t *testing.T) { name string mockResponse string mockStatusCode int + mockStatus string expectedResult []string expectError bool + expectedError error }{ { name: "Successful response", mockResponse: `["service1", "service2"]`, mockStatusCode: http.StatusOK, + mockStatus: "OK", expectedResult: []string{"service1", "service2"}, expectError: false, + expectedError: nil, }, { name: "Non-200 response", mockResponse: "", mockStatusCode: http.StatusInternalServerError, + mockStatus: "Internal Server Error", expectedResult: []string{}, expectError: true, + expectedError: backend.DownstreamError(fmt.Errorf("request failed: Internal Server Error")), }, { name: "Invalid JSON response", mockResponse: `{invalid json`, mockStatusCode: http.StatusOK, + mockStatus: "OK", expectedResult: []string{}, expectError: true, + expectedError: errors.New("invalid character 'i' looking for beginning of value"), }, } diff --git a/pkg/tsdb/zipkin/handler_querydata.go b/pkg/tsdb/zipkin/handler_querydata.go index 3e08ad9e585..b871758cd17 100644 --- a/pkg/tsdb/zipkin/handler_querydata.go +++ b/pkg/tsdb/zipkin/handler_querydata.go @@ -39,7 +39,7 @@ func queryData(ctx context.Context, dsInfo *datasourceInfo, req *backend.QueryDa traces, err := dsInfo.ZipkinClient.Trace(query.Query) if err != nil { es := backend.ErrorSourcePlugin - if backend.IsDownstreamHTTPError(err) { + if backend.IsDownstreamError(err) { es = backend.ErrorSourceDownstream } response.Responses[q.RefID] = backend.DataResponse{