From aa913b5f392ecd7ae7f8138fa08a4498af5c95a1 Mon Sep 17 00:00:00 2001 From: Kristin Laemmert Date: Wed, 21 Aug 2024 13:24:45 -0400 Subject: [PATCH] chore: add tracing to quote API and service methods with contexts (#92211) * chore: add tracing to quote API and service methods with contexts I also fixed a typo (overriden -> overridden) and removed a method that looked like it wasn't useful anymore. (It seemed to exist to return an error, but never returned an error, and so just added many lines of unnecessary error checking). --- pkg/api/quota.go | 16 ++++++--- pkg/services/quota/quotaimpl/quota.go | 49 ++++++++++++++------------- 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/pkg/api/quota.go b/pkg/api/quota.go index 42be8ac2a54..58ff3b11ca6 100644 --- a/pkg/api/quota.go +++ b/pkg/api/quota.go @@ -47,7 +47,9 @@ func (hs *HTTPServer) GetOrgQuotas(c *contextmodel.ReqContext) response.Response } func (hs *HTTPServer) getOrgQuotasHelper(c *contextmodel.ReqContext, orgID int64) response.Response { - q, err := hs.QuotaService.GetQuotasByScope(c.Req.Context(), quota.OrgScope, orgID) + ctx, span := hs.tracer.Start(c.Req.Context(), "api.getOrgQuotasHelper") + defer span.End() + q, err := hs.QuotaService.GetQuotasByScope(ctx, quota.OrgScope, orgID) if err != nil { return response.ErrOrFallback(http.StatusInternalServerError, "failed to get quota", err) } @@ -70,6 +72,8 @@ func (hs *HTTPServer) getOrgQuotasHelper(c *contextmodel.ReqContext, orgID int64 // 404: notFoundError // 500: internalServerError func (hs *HTTPServer) UpdateOrgQuota(c *contextmodel.ReqContext) response.Response { + ctx, span := hs.tracer.Start(c.Req.Context(), "api.UpdateOrgQuota") + defer span.End() cmd := quota.UpdateQuotaCmd{} var err error if err := web.Bind(c.Req, &cmd); err != nil { @@ -81,7 +85,7 @@ func (hs *HTTPServer) UpdateOrgQuota(c *contextmodel.ReqContext) response.Respon } cmd.Target = web.Params(c.Req)[":target"] - if err := hs.QuotaService.Update(c.Req.Context(), &cmd); err != nil { + if err := hs.QuotaService.Update(ctx, &cmd); err != nil { return response.ErrOrFallback(http.StatusInternalServerError, "Failed to update org quotas", err) } return response.Success("Organization quota updated") @@ -114,12 +118,14 @@ func (hs *HTTPServer) UpdateOrgQuota(c *contextmodel.ReqContext) response.Respon // 404: notFoundError // 500: internalServerError func (hs *HTTPServer) GetUserQuotas(c *contextmodel.ReqContext) response.Response { + ctx, span := hs.tracer.Start(c.Req.Context(), "api.GetUserQuotas") + defer span.End() id, err := strconv.ParseInt(web.Params(c.Req)[":id"], 10, 64) if err != nil { return response.Err(quota.ErrBadRequest.Errorf("id is invalid: %w", err)) } - q, err := hs.QuotaService.GetQuotasByScope(c.Req.Context(), quota.UserScope, id) + q, err := hs.QuotaService.GetQuotasByScope(ctx, quota.UserScope, id) if err != nil { return response.ErrOrFallback(http.StatusInternalServerError, "Failed to get org quotas", err) } @@ -143,6 +149,8 @@ func (hs *HTTPServer) GetUserQuotas(c *contextmodel.ReqContext) response.Respons // 404: notFoundError // 500: internalServerError func (hs *HTTPServer) UpdateUserQuota(c *contextmodel.ReqContext) response.Response { + ctx, span := hs.tracer.Start(c.Req.Context(), "api.UpdateUserQuota") + defer span.End() cmd := quota.UpdateQuotaCmd{} var err error if err := web.Bind(c.Req, &cmd); err != nil { @@ -154,7 +162,7 @@ func (hs *HTTPServer) UpdateUserQuota(c *contextmodel.ReqContext) response.Respo } cmd.Target = web.Params(c.Req)[":target"] - if err := hs.QuotaService.Update(c.Req.Context(), &cmd); err != nil { + if err := hs.QuotaService.Update(ctx, &cmd); err != nil { return response.ErrOrFallback(http.StatusInternalServerError, "Failed to update org quotas", err) } return response.Success("Organization quota updated") diff --git a/pkg/services/quota/quotaimpl/quota.go b/pkg/services/quota/quotaimpl/quota.go index 16a4f16a949..e8867ad38e8 100644 --- a/pkg/services/quota/quotaimpl/quota.go +++ b/pkg/services/quota/quotaimpl/quota.go @@ -4,6 +4,7 @@ import ( "context" "sync" + "go.opentelemetry.io/otel" "golang.org/x/sync/errgroup" "github.com/grafana/grafana/pkg/infra/db" @@ -13,6 +14,10 @@ import ( "github.com/grafana/grafana/pkg/setting" ) +// tracer is the global tracer for the quota service. Tracer pulls the globally +// initialized tracer from the opentelemetry package. +var tracer = otel.Tracer("github.com/grafana/grafana/pkg/services/quota/quotaimpl/service") + type serviceDisabled struct { } @@ -81,16 +86,20 @@ func (s *service) QuotaReached(c *contextmodel.ReqContext, targetSrv quota.Targe if c == nil { return false, nil } + ctx, span := tracer.Start(c.Req.Context(), "quota-service.QuotaReached") + defer span.End() params := "a.ScopeParameters{} if c.IsSignedIn { params.OrgID = c.SignedInUser.GetOrgID() params.UserID = c.UserID } - return s.CheckQuotaReached(c.Req.Context(), targetSrv, params) + return s.CheckQuotaReached(ctx, targetSrv, params) } func (s *service) GetQuotasByScope(ctx context.Context, scope quota.Scope, id int64) ([]quota.QuotaDTO, error) { + ctx, span := tracer.Start(ctx, "quota-service.GetQuotasByScope") + defer span.End() if err := scope.Validate(); err != nil { return nil, err } @@ -104,10 +113,7 @@ func (s *service) GetQuotasByScope(ctx context.Context, scope quota.Scope, id in scopeParams.UserID = id } - c, err := s.getContext(ctx) - if err != nil { - return nil, err - } + c := quota.FromContext(ctx, s.targetToSrv) customLimits, err := s.store.Get(c, &scopeParams) if err != nil { return nil, err @@ -160,6 +166,8 @@ func (s *service) GetQuotasByScope(ctx context.Context, scope quota.Scope, id in } func (s *service) Update(ctx context.Context, cmd *quota.UpdateQuotaCmd) error { + ctx, span := tracer.Start(ctx, "quota-service.Update") + defer span.End() targetFound := false knownTargets, err := s.defaultLimits.Targets() if err != nil { @@ -175,16 +183,15 @@ func (s *service) Update(ctx context.Context, cmd *quota.UpdateQuotaCmd) error { return quota.ErrInvalidTarget.Errorf("unknown quota target: %s", cmd.Target) } - c, err := s.getContext(ctx) - if err != nil { - return err - } + c := quota.FromContext(ctx, s.targetToSrv) return s.store.Update(c, cmd) } // CheckQuotaReached check that quota is reached for a target. If ScopeParameters are not defined, only global scope is checked func (s *service) CheckQuotaReached(ctx context.Context, targetSrv quota.TargetSrv, scopeParams *quota.ScopeParameters) (bool, error) { - targetSrvLimits, err := s.getOverridenLimits(ctx, targetSrv, scopeParams) + ctx, span := tracer.Start(ctx, "quota-service.CheckQuotaReached") + defer span.End() + targetSrvLimits, err := s.getOverriddenLimits(ctx, targetSrv, scopeParams) if err != nil { return false, err } @@ -233,10 +240,9 @@ func (s *service) CheckQuotaReached(ctx context.Context, targetSrv quota.TargetS } func (s *service) DeleteQuotaForUser(ctx context.Context, userID int64) error { - c, err := s.getContext(ctx) - if err != nil { - return err - } + ctx, span := tracer.Start(ctx, "quota-service.DeleteQuotaForUser") + defer span.End() + c := quota.FromContext(ctx, s.targetToSrv) return s.store.DeleteByUser(c, userID) } @@ -296,13 +302,12 @@ func (s *service) getReporters() <-chan reporter { return ch } -func (s *service) getOverridenLimits(ctx context.Context, targetSrv quota.TargetSrv, scopeParams *quota.ScopeParameters) (map[quota.Tag]int64, error) { +func (s *service) getOverriddenLimits(ctx context.Context, targetSrv quota.TargetSrv, scopeParams *quota.ScopeParameters) (map[quota.Tag]int64, error) { + ctx, span := tracer.Start(ctx, "quota-service.getOverriddenLimits") + defer span.End() targetSrvLimits := make(map[quota.Tag]int64) - c, err := s.getContext(ctx) - if err != nil { - return nil, err - } + c := quota.FromContext(ctx, s.targetToSrv) customLimits, err := s.store.Get(c, scopeParams) if err != nil { return targetSrvLimits, err @@ -331,6 +336,8 @@ func (s *service) getOverridenLimits(ctx context.Context, targetSrv quota.Target } func (s *service) getUsage(ctx context.Context, scopeParams *quota.ScopeParameters) (*quota.Map, error) { + ctx, span := tracer.Start(ctx, "quota-service.getUsage") + defer span.End() usage := "a.Map{} g, ctx := errgroup.WithContext(ctx) @@ -352,7 +359,3 @@ func (s *service) getUsage(ctx context.Context, scopeParams *quota.ScopeParamete return usage, nil } - -func (s *service) getContext(ctx context.Context) (quota.Context, error) { - return quota.FromContext(ctx, s.targetToSrv), nil -}