From 372d0acec8b0ea7cc5530b3518ce7ff39f3b40f1 Mon Sep 17 00:00:00 2001 From: Jeff Levin Date: Thu, 29 Aug 2024 22:26:15 -0800 Subject: [PATCH] Instrument tracing across dashboards (#91937) Add tracing across dashboards and accesscontrol --- pkg/api/api.go | 3 + pkg/api/dashboard.go | 68 ++++++++++++++++- pkg/api/dashboard_permission.go | 14 ++++ pkg/services/accesscontrol/api/api.go | 6 +- .../resourcepermissions/service.go | 20 ++--- pkg/services/dashboards/accesscontrol.go | 23 ++++++ pkg/services/dashboards/database/database.go | 75 +++++++++++++++++++ .../dashboards/service/dashboard_service.go | 56 ++++++++++++++ 8 files changed, 249 insertions(+), 16 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index 76026f68d42..eaf4c8c3a0c 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -46,8 +46,11 @@ import ( publicdashboardsapi "github.com/grafana/grafana/pkg/services/publicdashboards/api" "github.com/grafana/grafana/pkg/services/serviceaccounts" "github.com/grafana/grafana/pkg/services/user" + "go.opentelemetry.io/otel" ) +var tracer = otel.Tracer("github.com/grafana/grafana/pkg/api") + // registerRoutes registers all API HTTP routes. func (hs *HTTPServer) registerRoutes() { reqNoAuth := middleware.NoAuth() diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go index 6f1b9820784..82af44e30a4 100644 --- a/pkg/api/dashboard.go +++ b/pkg/api/dashboard.go @@ -40,6 +40,10 @@ const ( ) func (hs *HTTPServer) isDashboardStarredByUser(c *contextmodel.ReqContext, dashID int64) (bool, error) { + ctx, span := tracer.Start(c.Req.Context(), "api.isDashboardStarredByUser") + defer span.End() + c.Req = c.Req.WithContext(ctx) + if !c.IsSignedIn { return false, nil } @@ -81,8 +85,9 @@ func dashboardGuardianResponse(err error) response.Response { // 404: notFoundError // 500: internalServerError func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response { - ctx, span := hs.tracer.Start(c.Req.Context(), "api.GetDashboard") + ctx, span := tracer.Start(c.Req.Context(), "api.GetDashboard") defer span.End() + c.Req = c.Req.WithContext(ctx) uid := web.Params(c.Req)[":uid"] dash, rsp := hs.getDashboardHelper(ctx, c.SignedInUser.GetOrgID(), 0, uid) @@ -230,6 +235,10 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response } func (hs *HTTPServer) getAnnotationPermissionsByScope(c *contextmodel.ReqContext, actions *dashboardsV0.AnnotationActions, scope string) { + ctx, span := tracer.Start(c.Req.Context(), "api.getAnnotationPermissionsByScope") + defer span.End() + c.Req = c.Req.WithContext(ctx) + var err error evaluate := accesscontrol.EvalPermission(accesscontrol.ActionAnnotationsCreate, scope) @@ -252,6 +261,9 @@ func (hs *HTTPServer) getAnnotationPermissionsByScope(c *contextmodel.ReqContext } func (hs *HTTPServer) getUserLogin(ctx context.Context, userID int64) string { + ctx, span := tracer.Start(ctx, "api.getUserLogin") + defer span.End() + query := user.GetUserByIDQuery{ID: userID} user, err := hs.userService.GetByID(ctx, &query) if err != nil { @@ -292,6 +304,10 @@ func (hs *HTTPServer) getDashboardHelper(ctx context.Context, orgID int64, id in // 404: notFoundError // 500: internalServerError func (hs *HTTPServer) RestoreDeletedDashboard(c *contextmodel.ReqContext) response.Response { + ctx, span := tracer.Start(c.Req.Context(), "api.RestoreDeletedDashboard") + defer span.End() + c.Req = c.Req.WithContext(ctx) + uid := web.Params(c.Req)[":uid"] cmd := dashboards.RestoreDeletedDashboardCommand{} @@ -342,6 +358,10 @@ func (hs *HTTPServer) RestoreDeletedDashboard(c *contextmodel.ReqContext) respon // 404: notFoundError // 500: internalServerError func (hs *HTTPServer) SoftDeleteDashboard(c *contextmodel.ReqContext) response.Response { + ctx, span := tracer.Start(c.Req.Context(), "api.SoftDeleteDashboard") + defer span.End() + c.Req = c.Req.WithContext(ctx) + uid := web.Params(c.Req)[":uid"] dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), 0, uid) if rsp != nil { @@ -408,6 +428,10 @@ func (hs *HTTPServer) HardDeleteDashboardByUID(c *contextmodel.ReqContext) respo } func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Response { + ctx, span := tracer.Start(c.Req.Context(), "api.deleteDashboard") + defer span.End() + c.Req = c.Req.WithContext(ctx) + uid := web.Params(c.Req)[":uid"] var dash *dashboards.Dashboard @@ -496,6 +520,10 @@ func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Respo // 422: unprocessableEntityError // 500: internalServerError func (hs *HTTPServer) PostDashboard(c *contextmodel.ReqContext) response.Response { + ctx, span := tracer.Start(c.Req.Context(), "api.PostDashboard") + defer span.End() + c.Req = c.Req.WithContext(ctx) + cmd := dashboards.SaveDashboardCommand{} if err := web.Bind(c.Req, &cmd); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) @@ -504,11 +532,15 @@ func (hs *HTTPServer) PostDashboard(c *contextmodel.ReqContext) response.Respons } func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.SaveDashboardCommand) response.Response { + ctx, span := tracer.Start(c.Req.Context(), "api.postDashboard") + defer span.End() + c.Req = c.Req.WithContext(ctx) + if cmd.IsFolder { return response.Error(http.StatusBadRequest, "Use folders endpoint for saving folders.", nil) } - ctx := c.Req.Context() + ctx = c.Req.Context() var err error var userID int64 @@ -622,6 +654,10 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S // 401: unauthorisedError // 500: internalServerError func (hs *HTTPServer) GetHomeDashboard(c *contextmodel.ReqContext) response.Response { + ctx, span := tracer.Start(c.Req.Context(), "api.GetHomeDashboard") + defer span.End() + c.Req = c.Req.WithContext(ctx) + var userID int64 if id, err := identity.UserIdentifier(c.SignedInUser.GetID()); err == nil { userID = id @@ -685,6 +721,10 @@ func (hs *HTTPServer) GetHomeDashboard(c *contextmodel.ReqContext) response.Resp } func (hs *HTTPServer) addGettingStartedPanelToHomeDashboard(c *contextmodel.ReqContext, dash *simplejson.Json) { + ctx, span := tracer.Start(c.Req.Context(), "api.addGettingStartedPanelToHomeDashboard") + defer span.End() + c.Req = c.Req.WithContext(ctx) + // We only add this getting started panel for Admins who have not dismissed it, // and if a custom default home dashboard hasn't been configured if !c.HasUserRole(org.RoleAdmin) || @@ -736,6 +776,10 @@ func (hs *HTTPServer) addGettingStartedPanelToHomeDashboard(c *contextmodel.ReqC // 404: notFoundError // 500: internalServerError func (hs *HTTPServer) GetDashboardVersions(c *contextmodel.ReqContext) response.Response { + ctx, span := tracer.Start(c.Req.Context(), "api.GetDashboardVersions") + defer span.End() + c.Req = c.Req.WithContext(ctx) + var dashID int64 var err error @@ -846,6 +890,10 @@ func (hs *HTTPServer) GetDashboardVersions(c *contextmodel.ReqContext) response. // 404: notFoundError // 500: internalServerError func (hs *HTTPServer) GetDashboardVersion(c *contextmodel.ReqContext) response.Response { + ctx, span := tracer.Start(c.Req.Context(), "api.GetDashboardVersion") + defer span.End() + c.Req = c.Req.WithContext(ctx) + var dashID int64 var err error @@ -921,6 +969,10 @@ func (hs *HTTPServer) GetDashboardVersion(c *contextmodel.ReqContext) response.R // 403: forbiddenError // 500: internalServerError func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) response.Response { + ctx, span := tracer.Start(c.Req.Context(), "api.CalculateDashboardDiff") + defer span.End() + c.Req = c.Req.WithContext(ctx) + apiOptions := dtos.CalculateDiffOptions{} if err := web.Bind(c.Req, &apiOptions); err != nil { return response.Error(http.StatusBadRequest, "bad request data", err) @@ -1032,6 +1084,10 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons // 404: notFoundError // 500: internalServerError func (hs *HTTPServer) RestoreDashboardVersion(c *contextmodel.ReqContext) response.Response { + ctx, span := tracer.Start(c.Req.Context(), "api.RestoreDashboardVersion") + defer span.End() + c.Req = c.Req.WithContext(ctx) + var dashID int64 var err error @@ -1098,6 +1154,10 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *contextmodel.ReqContext) respon // 401: unauthorisedError // 500: internalServerError func (hs *HTTPServer) GetDashboardTags(c *contextmodel.ReqContext) { + ctx, span := tracer.Start(c.Req.Context(), "api.GetDashboardTags") + defer span.End() + c.Req = c.Req.WithContext(ctx) + query := dashboards.GetDashboardTagsQuery{OrgID: c.SignedInUser.GetOrgID()} queryResult, err := hs.DashboardService.GetDashboardTags(c.Req.Context(), &query) if err != nil { @@ -1110,6 +1170,10 @@ func (hs *HTTPServer) GetDashboardTags(c *contextmodel.ReqContext) { // GetDashboardUIDs converts internal ids to UIDs func (hs *HTTPServer) GetDashboardUIDs(c *contextmodel.ReqContext) { + ctx, span := tracer.Start(c.Req.Context(), "api.GetDashboardUIDs") + defer span.End() + c.Req = c.Req.WithContext(ctx) + ids := strings.Split(web.Params(c.Req)[":ids"], ",") uids := make([]string, 0, len(ids)) diff --git a/pkg/api/dashboard_permission.go b/pkg/api/dashboard_permission.go index 061a343330e..16da432b2b0 100644 --- a/pkg/api/dashboard_permission.go +++ b/pkg/api/dashboard_permission.go @@ -44,6 +44,10 @@ import ( // 404: notFoundError // 500: internalServerError func (hs *HTTPServer) GetDashboardPermissionList(c *contextmodel.ReqContext) response.Response { + ctx, span := tracer.Start(c.Req.Context(), "api.GetDashboardPermissionList") + defer span.End() + c.Req = c.Req.WithContext(ctx) + var dashID int64 var err error dashUID := web.Params(c.Req)[":uid"] @@ -117,6 +121,10 @@ func (hs *HTTPServer) GetDashboardPermissionList(c *contextmodel.ReqContext) res // 404: notFoundError // 500: internalServerError func (hs *HTTPServer) UpdateDashboardPermissions(c *contextmodel.ReqContext) response.Response { + ctx, span := tracer.Start(c.Req.Context(), "api.UpdateDashboardPermissions") + defer span.End() + c.Req = c.Req.WithContext(ctx) + var dashID int64 var err error apiCmd := dtos.UpdateDashboardACLCommand{} @@ -175,6 +183,9 @@ var dashboardPermissionMap = map[string]dashboardaccess.PermissionType{ } func (hs *HTTPServer) getDashboardACL(ctx context.Context, user identity.Requester, dashboard *dashboards.Dashboard) ([]*dashboards.DashboardACLInfoDTO, error) { + ctx, span := tracer.Start(ctx, "api.getDashboardACL") + defer span.End() + permissions, err := hs.dashboardPermissionsService.GetPermissions(ctx, user, dashboard.UID) if err != nil { return nil, err @@ -253,6 +264,9 @@ func (hs *HTTPServer) filterHiddenACL(user identity.Requester, acl []*dashboards // updateDashboardAccessControl is used for api backward compatibility func (hs *HTTPServer) updateDashboardAccessControl(ctx context.Context, orgID int64, uid string, isFolder bool, items []*dashboards.DashboardACL, old []*dashboards.DashboardACLInfoDTO) error { + ctx, span := tracer.Start(ctx, "api.updateDashboardAccessControl") + defer span.End() + commands := []accesscontrol.SetResourcePermissionCommand{} for _, item := range items { permissions := item.Permission.String() diff --git a/pkg/services/accesscontrol/api/api.go b/pkg/services/accesscontrol/api/api.go index a35a3d88b81..5148eb70206 100644 --- a/pkg/services/accesscontrol/api/api.go +++ b/pkg/services/accesscontrol/api/api.go @@ -50,8 +50,7 @@ func (api *AccessControlAPI) getUserActions(c *contextmodel.ReqContext) response defer span.End() reloadCache := c.QueryBool("reloadcache") - permissions, err := api.Service.GetUserPermissions(ctx, - c.SignedInUser, ac.Options{ReloadCache: reloadCache}) + permissions, err := api.Service.GetUserPermissions(ctx, c.SignedInUser, ac.Options{ReloadCache: reloadCache}) if err != nil { return response.JSON(http.StatusInternalServerError, err) } @@ -65,8 +64,7 @@ func (api *AccessControlAPI) getUserPermissions(c *contextmodel.ReqContext) resp defer span.End() reloadCache := c.QueryBool("reloadcache") - permissions, err := api.Service.GetUserPermissions(ctx, - c.SignedInUser, ac.Options{ReloadCache: reloadCache}) + permissions, err := api.Service.GetUserPermissions(ctx, c.SignedInUser, ac.Options{ReloadCache: reloadCache}) if err != nil { return response.JSON(http.StatusInternalServerError, err) } diff --git a/pkg/services/accesscontrol/resourcepermissions/service.go b/pkg/services/accesscontrol/resourcepermissions/service.go index a80046877b5..2a6f89a2106 100644 --- a/pkg/services/accesscontrol/resourcepermissions/service.go +++ b/pkg/services/accesscontrol/resourcepermissions/service.go @@ -138,7 +138,7 @@ type Service struct { } func (s *Service) GetPermissions(ctx context.Context, user identity.Requester, resourceID string) ([]accesscontrol.ResourcePermission, error) { - ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.GetPermissions") + ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.GetPermissions") defer span.End() var inheritedScopes []string @@ -209,7 +209,7 @@ func (s *Service) GetPermissions(ctx context.Context, user identity.Requester, r } func (s *Service) SetUserPermission(ctx context.Context, orgID int64, user accesscontrol.User, resourceID, permission string) (*accesscontrol.ResourcePermission, error) { - ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.SetUserPermission") + ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.SetUserPermission") defer span.End() actions, err := s.mapPermission(permission) @@ -235,7 +235,7 @@ func (s *Service) SetUserPermission(ctx context.Context, orgID int64, user acces } func (s *Service) SetTeamPermission(ctx context.Context, orgID, teamID int64, resourceID, permission string) (*accesscontrol.ResourcePermission, error) { - ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.SetTeamPermission") + ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.SetTeamPermission") defer span.End() actions, err := s.mapPermission(permission) @@ -261,7 +261,7 @@ func (s *Service) SetTeamPermission(ctx context.Context, orgID, teamID int64, re } func (s *Service) SetBuiltInRolePermission(ctx context.Context, orgID int64, builtInRole, resourceID, permission string) (*accesscontrol.ResourcePermission, error) { - ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.SetBuiltInRolePermission") + ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.SetBuiltInRolePermission") defer span.End() actions, err := s.mapPermission(permission) @@ -290,7 +290,7 @@ func (s *Service) SetPermissions( ctx context.Context, orgID int64, resourceID string, commands ...accesscontrol.SetResourcePermissionCommand, ) ([]accesscontrol.ResourcePermission, error) { - ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.SetPermissions") + ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.SetPermissions") defer span.End() if err := s.validateResource(ctx, orgID, resourceID); err != nil { @@ -370,7 +370,7 @@ func (s *Service) mapPermission(permission string) ([]string, error) { } func (s *Service) validateResource(ctx context.Context, orgID int64, resourceID string) error { - ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.validateResource") + ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.validateResource") defer span.End() if s.options.ResourceValidator != nil { @@ -380,7 +380,7 @@ func (s *Service) validateResource(ctx context.Context, orgID int64, resourceID } func (s *Service) validateUser(ctx context.Context, orgID, userID int64) error { - ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.validateUser") + ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.validateUser") defer span.End() if !s.options.Assignments.Users { @@ -397,7 +397,7 @@ func (s *Service) validateUser(ctx context.Context, orgID, userID int64) error { } func (s *Service) validateTeam(ctx context.Context, orgID, teamID int64) error { - ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.validateTeam") + ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.validateTeam") defer span.End() if !s.options.Assignments.Teams { @@ -416,7 +416,7 @@ func (s *Service) validateTeam(ctx context.Context, orgID, teamID int64) error { } func (s *Service) validateBuiltinRole(ctx context.Context, builtinRole string) error { - _, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.validateBuiltinRole") + _, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.validateBuiltinRole") defer span.End() if !s.options.Assignments.BuiltInRoles { @@ -580,7 +580,7 @@ func (a *ActionSetSvc) ExpandActionSetsWithFilter(permissions []accesscontrol.Pe // RegisterActionSets allow the caller to expand the existing action sets with additional permissions // This is intended to be used by plugins, and currently supports extending folder and dashboard action sets func (a *ActionSetSvc) RegisterActionSets(ctx context.Context, pluginID string, registrations []plugins.ActionSet) error { - ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.RegisterActionSets") + ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.RegisterActionSets") defer span.End() if !a.features.IsEnabled(ctx, featuremgmt.FlagAccessActionSets) || !a.features.IsEnabled(ctx, featuremgmt.FlagAccessControlOnCall) { diff --git a/pkg/services/dashboards/accesscontrol.go b/pkg/services/dashboards/accesscontrol.go index e8ec7661b35..c4b53df4c87 100644 --- a/pkg/services/dashboards/accesscontrol.go +++ b/pkg/services/dashboards/accesscontrol.go @@ -8,6 +8,7 @@ import ( "github.com/grafana/grafana/pkg/infra/metrics" ac "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/folder" + "go.opentelemetry.io/otel" ) const ( @@ -38,12 +39,16 @@ var ( ScopeFoldersAll = ScopeFoldersProvider.GetResourceAllScope() ScopeDashboardsProvider = ac.NewScopeProvider(ScopeDashboardsRoot) ScopeDashboardsAll = ScopeDashboardsProvider.GetResourceAllScope() + tracer = otel.Tracer("github.com/grafana/grafana/pkg/services/dashboards") ) // NewFolderNameScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:name:" into an uid based scope. func NewFolderNameScopeResolver(folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { prefix := ScopeFoldersProvider.GetResourceScopeName("") return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { + ctx, span := tracer.Start(ctx, "dashboards.NewFolderNameScopeResolver") + span.End() + if !strings.HasPrefix(scope, prefix) { return nil, ac.ErrInvalidScope } @@ -72,6 +77,9 @@ func NewFolderNameScopeResolver(folderDB folder.FolderStore, folderSvc folder.Se func NewFolderIDScopeResolver(folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { prefix := ScopeFoldersProvider.GetResourceScope("") return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { + ctx, span := tracer.Start(ctx, "dashboards.NewFolderIDScopeResolver") + span.End() + if !strings.HasPrefix(scope, prefix) { return nil, ac.ErrInvalidScope } @@ -105,6 +113,9 @@ func NewFolderIDScopeResolver(folderDB folder.FolderStore, folderSvc folder.Serv func NewFolderUIDScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { prefix := ScopeFoldersProvider.GetResourceScopeUID("") return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { + ctx, span := tracer.Start(ctx, "dashboards.NewFolderUIDScopeResolver") + span.End() + if !strings.HasPrefix(scope, prefix) { return nil, ac.ErrInvalidScope } @@ -127,6 +138,9 @@ func NewFolderUIDScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttrib func NewDashboardIDScopeResolver(folderDB folder.FolderStore, ds DashboardService, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { prefix := ScopeDashboardsProvider.GetResourceScope("") return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { + ctx, span := tracer.Start(ctx, "dashboards.NewDashboardIDScopeResolver") + span.End() + if !strings.HasPrefix(scope, prefix) { return nil, ac.ErrInvalidScope } @@ -150,6 +164,9 @@ func NewDashboardIDScopeResolver(folderDB folder.FolderStore, ds DashboardServic func NewDashboardUIDScopeResolver(folderDB folder.FolderStore, ds DashboardService, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { prefix := ScopeDashboardsProvider.GetResourceScopeUID("") return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { + ctx, span := tracer.Start(ctx, "dashboards.NewDashboardUIDScopeResolver") + span.End() + if !strings.HasPrefix(scope, prefix) { return nil, ac.ErrInvalidScope } @@ -169,6 +186,9 @@ func NewDashboardUIDScopeResolver(folderDB folder.FolderStore, ds DashboardServi } func resolveDashboardScope(ctx context.Context, folderDB folder.FolderStore, orgID int64, dashboard *Dashboard, folderSvc folder.Service) ([]string, error) { + ctx, span := tracer.Start(ctx, "dashboards.resolveDashboardScope") + span.End() + var folderUID string metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Dashboard).Inc() // nolint:staticcheck @@ -204,6 +224,9 @@ func resolveDashboardScope(ctx context.Context, folderDB folder.FolderStore, org } func GetInheritedScopes(ctx context.Context, orgID int64, folderUID string, folderSvc folder.Service) ([]string, error) { + ctx, span := tracer.Start(ctx, "dashboards.GetInheritedScopes") + span.End() + if folderUID == ac.GeneralFolderUID { return nil, nil } diff --git a/pkg/services/dashboards/database/database.go b/pkg/services/dashboards/database/database.go index 8e91674cb35..b68ca7357fc 100644 --- a/pkg/services/dashboards/database/database.go +++ b/pkg/services/dashboards/database/database.go @@ -25,8 +25,11 @@ import ( "github.com/grafana/grafana/pkg/services/tag" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" + "go.opentelemetry.io/otel" ) +var tracer = otel.Tracer("github.com/grafana/grafana/pkg/services/dashboard/database") + type dashboardStore struct { store db.ReplDB cfg *setting.Cfg @@ -69,6 +72,9 @@ func (d *dashboardStore) emitEntityEvent() bool { } func (d *dashboardStore) ValidateDashboardBeforeSave(ctx context.Context, dashboard *dashboards.Dashboard, overwrite bool) (bool, error) { + ctx, span := tracer.Start(ctx, "dashboards.database.ValidateDashboardBeforesave") + defer span.End() + isParentFolderChanged := false err := d.store.DB().WithTransactionalDbSession(ctx, func(sess *db.Session) error { var err error @@ -93,6 +99,9 @@ func (d *dashboardStore) ValidateDashboardBeforeSave(ctx context.Context, dashbo } func (d *dashboardStore) GetProvisionedDataByDashboardID(ctx context.Context, dashboardID int64) (*dashboards.DashboardProvisioning, error) { + ctx, span := tracer.Start(ctx, "dashboards.database.GetProvisionedDataByDashboardID") + defer span.End() + var data dashboards.DashboardProvisioning err := d.store.DB().WithDbSession(ctx, func(sess *db.Session) error { _, err := sess.Where("dashboard_id = ?", dashboardID).Get(&data) @@ -106,6 +115,9 @@ func (d *dashboardStore) GetProvisionedDataByDashboardID(ctx context.Context, da } func (d *dashboardStore) GetProvisionedDataByDashboardUID(ctx context.Context, orgID int64, dashboardUID string) (*dashboards.DashboardProvisioning, error) { + ctx, span := tracer.Start(ctx, "dashboards.database.GetProvisionedDataByDashboardUID") + defer span.End() + var provisionedDashboard dashboards.DashboardProvisioning err := d.store.DB().WithDbSession(ctx, func(sess *db.Session) error { var dashboard dashboards.Dashboard @@ -129,6 +141,9 @@ func (d *dashboardStore) GetProvisionedDataByDashboardUID(ctx context.Context, o } func (d *dashboardStore) GetProvisionedDashboardData(ctx context.Context, name string) ([]*dashboards.DashboardProvisioning, error) { + ctx, span := tracer.Start(ctx, "dashboards.database.GetProvisionedDashboardData") + defer span.End() + var result []*dashboards.DashboardProvisioning err := d.store.DB().WithDbSession(ctx, func(sess *db.Session) error { return sess.Where("name = ?", name).Find(&result) @@ -137,6 +152,9 @@ func (d *dashboardStore) GetProvisionedDashboardData(ctx context.Context, name s } func (d *dashboardStore) SaveProvisionedDashboard(ctx context.Context, cmd dashboards.SaveDashboardCommand, provisioning *dashboards.DashboardProvisioning) (*dashboards.Dashboard, error) { + ctx, span := tracer.Start(ctx, "dashboards.database.SaveProvisionedDashboard") + defer span.End() + var result *dashboards.Dashboard var err error err = d.store.DB().WithTransactionalDbSession(ctx, func(sess *db.Session) error { @@ -155,6 +173,9 @@ func (d *dashboardStore) SaveProvisionedDashboard(ctx context.Context, cmd dashb } func (d *dashboardStore) SaveDashboard(ctx context.Context, cmd dashboards.SaveDashboardCommand) (*dashboards.Dashboard, error) { + ctx, span := tracer.Start(ctx, "dashboards.database.SaveDashboard") + defer span.End() + var result *dashboards.Dashboard var err error err = d.store.DB().WithTransactionalDbSession(ctx, func(sess *db.Session) error { @@ -173,6 +194,9 @@ func (d *dashboardStore) SaveDashboard(ctx context.Context, cmd dashboards.SaveD // UnprovisionDashboard removes row in dashboard_provisioning for the dashboard making it seem as if manually created. // The dashboard will still have `created_by = -1` to see it was not created by any particular user. func (d *dashboardStore) UnprovisionDashboard(ctx context.Context, id int64) error { + ctx, span := tracer.Start(ctx, "dashboards.database.UnprovisionDashboard") + defer span.End() + return d.store.DB().WithTransactionalDbSession(ctx, func(sess *db.Session) error { _, err := sess.Where("dashboard_id = ?", id).Delete(&dashboards.DashboardProvisioning{}) return err @@ -180,6 +204,9 @@ func (d *dashboardStore) UnprovisionDashboard(ctx context.Context, id int64) err } func (d *dashboardStore) DeleteOrphanedProvisionedDashboards(ctx context.Context, cmd *dashboards.DeleteOrphanedProvisionedDashboardsCommand) error { + ctx, span := tracer.Start(ctx, "dashboards.database.DeleteOrphanedProvisionedDashboards") + defer span.End() + return d.store.DB().WithDbSession(ctx, func(sess *db.Session) error { var result []*dashboards.DashboardProvisioning @@ -205,6 +232,9 @@ func (d *dashboardStore) DeleteOrphanedProvisionedDashboards(ctx context.Context } func (d *dashboardStore) Count(ctx context.Context, scopeParams *quota.ScopeParameters) (*quota.Map, error) { + ctx, span := tracer.Start(ctx, "dashboards.database.Count") + defer span.End() + u := "a.Map{} type result struct { Count int64 @@ -500,6 +530,9 @@ func saveProvisionedData(sess *db.Session, provisioning *dashboards.DashboardPro } func (d *dashboardStore) GetDashboardsByPluginID(ctx context.Context, query *dashboards.GetDashboardsByPluginIDQuery) ([]*dashboards.Dashboard, error) { + ctx, span := tracer.Start(ctx, "dashboards.database.GetDashboardsByPluginID") + defer span.End() + var dashboards = make([]*dashboards.Dashboard, 0) err := d.store.DB().WithDbSession(ctx, func(dbSession *db.Session) error { whereExpr := "org_id=? AND plugin_id=? AND is_folder=" + d.store.DB().GetDialect().BooleanStr(false) @@ -514,6 +547,9 @@ func (d *dashboardStore) GetDashboardsByPluginID(ctx context.Context, query *das } func (d *dashboardStore) GetSoftDeletedDashboard(ctx context.Context, orgID int64, uid string) (*dashboards.Dashboard, error) { + ctx, span := tracer.Start(ctx, "dashboards.database.GetSoftDeletedDashboard") + defer span.End() + if orgID == 0 || uid == "" { return nil, dashboards.ErrDashboardIdentifierNotSet } @@ -537,6 +573,9 @@ func (d *dashboardStore) GetSoftDeletedDashboard(ctx context.Context, orgID int6 } func (d *dashboardStore) RestoreDashboard(ctx context.Context, orgID int64, dashboardUID string, folder *folder.Folder) error { + ctx, span := tracer.Start(ctx, "dashboards.database.RestoreDashboard") + defer span.End() + return d.store.DB().WithTransactionalDbSession(ctx, func(sess *db.Session) error { if folder == nil || folder.UID == "" { _, err := sess.Exec("UPDATE dashboard SET deleted=NULL, folder_id=0, folder_uid=NULL WHERE org_id=? AND uid=?", orgID, dashboardUID) @@ -549,6 +588,9 @@ func (d *dashboardStore) RestoreDashboard(ctx context.Context, orgID int64, dash } func (d *dashboardStore) SoftDeleteDashboard(ctx context.Context, orgID int64, dashboardUID string) error { + ctx, span := tracer.Start(ctx, "dashboards.database.SoftDeleteDashboard") + defer span.End() + return d.store.DB().WithTransactionalDbSession(ctx, func(sess *db.Session) error { _, err := sess.Exec("UPDATE dashboard SET deleted=? WHERE org_id=? AND uid=?", time.Now(), orgID, dashboardUID) return err @@ -556,6 +598,9 @@ func (d *dashboardStore) SoftDeleteDashboard(ctx context.Context, orgID int64, d } func (d *dashboardStore) SoftDeleteDashboardsInFolders(ctx context.Context, orgID int64, folderUids []string) error { + ctx, span := tracer.Start(ctx, "dashboards.database.SoftDeleteDashboardsInFolders") + defer span.End() + if len(folderUids) == 0 { return nil } @@ -580,6 +625,9 @@ func (d *dashboardStore) SoftDeleteDashboardsInFolders(ctx context.Context, orgI } func (d *dashboardStore) DeleteDashboard(ctx context.Context, cmd *dashboards.DeleteDashboardCommand) error { + ctx, span := tracer.Start(ctx, "dashboards.database.DeleteDashboard") + defer span.End() + return d.store.DB().WithTransactionalDbSession(ctx, func(sess *db.Session) error { return d.deleteDashboard(cmd, sess, d.emitEntityEvent()) }) @@ -736,6 +784,9 @@ func createEntityEvent(dashboard *dashboards.Dashboard, eventType store.EntityEv } func (d *dashboardStore) GetDashboard(ctx context.Context, query *dashboards.GetDashboardQuery) (*dashboards.Dashboard, error) { + ctx, span := tracer.Start(ctx, "dashboards.database.GetDashboard") + defer span.End() + var queryResult *dashboards.Dashboard err := d.store.ReadReplica().WithDbSession(ctx, func(sess *db.Session) error { metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Dashboard).Inc() @@ -778,6 +829,9 @@ func (d *dashboardStore) GetDashboard(ctx context.Context, query *dashboards.Get } func (d *dashboardStore) GetDashboardUIDByID(ctx context.Context, query *dashboards.GetDashboardRefByIDQuery) (*dashboards.DashboardRef, error) { + ctx, span := tracer.Start(ctx, "dashboards.database.GetDashboardUIDByID") + defer span.End() + us := &dashboards.DashboardRef{} err := d.store.DB().WithDbSession(ctx, func(sess *db.Session) error { var rawSQL = `SELECT uid, slug from dashboard WHERE Id=?` @@ -796,6 +850,9 @@ func (d *dashboardStore) GetDashboardUIDByID(ctx context.Context, query *dashboa } func (d *dashboardStore) GetDashboards(ctx context.Context, query *dashboards.GetDashboardsQuery) ([]*dashboards.Dashboard, error) { + ctx, span := tracer.Start(ctx, "dashboards.database.GetDashboards") + defer span.End() + var dashboards = make([]*dashboards.Dashboard, 0) err := d.store.ReadReplica().WithDbSession(ctx, func(sess *db.Session) error { if len(query.DashboardIDs) == 0 && len(query.DashboardUIDs) == 0 { @@ -824,6 +881,9 @@ func (d *dashboardStore) GetDashboards(ctx context.Context, query *dashboards.Ge } func (d *dashboardStore) FindDashboards(ctx context.Context, query *dashboards.FindPersistedDashboardsQuery) ([]dashboards.DashboardSearchProjection, error) { + ctx, span := tracer.Start(ctx, "dashboards.database.FindDashboards") + defer span.End() + recursiveQueriesAreSupported, err := d.store.ReadReplica().RecursiveQueriesAreSupported() if err != nil { return nil, err @@ -914,6 +974,9 @@ func (d *dashboardStore) FindDashboards(ctx context.Context, query *dashboards.F } func (d *dashboardStore) GetDashboardTags(ctx context.Context, query *dashboards.GetDashboardTagsQuery) ([]*dashboards.DashboardTagCloudItem, error) { + ctx, span := tracer.Start(ctx, "dashboards.database.GetDashboardTags") + defer span.End() + queryResult := make([]*dashboards.DashboardTagCloudItem, 0) err := d.store.DB().WithDbSession(ctx, func(dbSession *db.Session) error { sql := `SELECT @@ -939,6 +1002,9 @@ func (d *dashboardStore) GetDashboardTags(ctx context.Context, query *dashboards // given parent folder ID. func (d *dashboardStore) CountDashboardsInFolders( ctx context.Context, req *dashboards.CountDashboardsInFolderRequest) (int64, error) { + ctx, span := tracer.Start(ctx, "dashboards.database.CountDashboardsInFolders") + defer span.End() + if len(req.FolderUIDs) == 0 { return 0, nil } @@ -967,6 +1033,9 @@ func (d *dashboardStore) CountDashboardsInFolders( func (d *dashboardStore) DeleteDashboardsInFolders( ctx context.Context, req *dashboards.DeleteDashboardsInFolderRequest) error { + ctx, span := tracer.Start(ctx, "dashboards.database.DeleteDashboardsInFolders") + defer span.End() + return d.store.DB().WithTransactionalDbSession(ctx, func(sess *db.Session) error { // TODO delete all dashboards in the folder in a bulk query for _, folderUID := range req.FolderUIDs { @@ -993,6 +1062,9 @@ func (d *dashboardStore) DeleteDashboardsInFolders( } func (d *dashboardStore) GetAllDashboards(ctx context.Context) ([]*dashboards.Dashboard, error) { + ctx, span := tracer.Start(ctx, "dashboards.database.GetAllDashboards") + defer span.End() + var dashboards = make([]*dashboards.Dashboard, 0) err := d.store.ReadReplica().WithDbSession(ctx, func(session *db.Session) error { err := session.Find(&dashboards) @@ -1005,6 +1077,9 @@ func (d *dashboardStore) GetAllDashboards(ctx context.Context) ([]*dashboards.Da } func (d *dashboardStore) GetSoftDeletedExpiredDashboards(ctx context.Context, duration time.Duration) ([]*dashboards.Dashboard, error) { + ctx, span := tracer.Start(ctx, "dashboards.database.GetSoftDeletedExpiredDashboards") + defer span.End() + var dashboards = make([]*dashboards.Dashboard, 0) err := d.store.DB().WithDbSession(ctx, func(sess *db.Session) error { err := sess.Where("deleted IS NOT NULL AND deleted < ?", time.Now().Add(-duration)).Find(&dashboards) diff --git a/pkg/services/dashboards/service/dashboard_service.go b/pkg/services/dashboards/service/dashboard_service.go index f1e40b2f98a..99f68aa917b 100644 --- a/pkg/services/dashboards/service/dashboard_service.go +++ b/pkg/services/dashboards/service/dashboard_service.go @@ -10,6 +10,7 @@ import ( "github.com/grafana/authlib/claims" "github.com/grafana/grafana-plugin-sdk-go/backend/gtime" "github.com/prometheus/client_golang/prometheus" + "go.opentelemetry.io/otel" "golang.org/x/exp/slices" "github.com/grafana/grafana/pkg/apimachinery/identity" @@ -43,6 +44,7 @@ var ( _ dashboards.PluginService = (*DashboardServiceImpl)(nil) daysInTrash = 24 * 30 * time.Hour + tracer = otel.Tracer("github.com/grafana/grafana/pkg/services/dashboards/service") ) type DashboardServiceImpl struct { @@ -103,6 +105,9 @@ func (dr *DashboardServiceImpl) GetProvisionedDashboardDataByDashboardUID(ctx co //nolint:gocyclo func (dr *DashboardServiceImpl) BuildSaveDashboardCommand(ctx context.Context, dto *dashboards.SaveDashboardDTO, validateProvisionedDashboard bool) (*dashboards.SaveDashboardCommand, error) { + ctx, span := tracer.Start(ctx, "dashboards.service.BuildSaveDashboardcommand") + defer span.End() + dash := dto.Dashboard dash.OrgID = dto.OrgID @@ -242,6 +247,9 @@ func (dr *DashboardServiceImpl) DeleteOrphanedProvisionedDashboards(ctx context. // getGuardianForSavePermissionCheck returns the guardian to be used for checking permission of dashboard // It replaces deleted Dashboard.GetDashboardIdForSavePermissionCheck() func getGuardianForSavePermissionCheck(ctx context.Context, d *dashboards.Dashboard, user identity.Requester) (guardian.DashboardGuardian, error) { + ctx, span := tracer.Start(ctx, "dashboards.service.getGuardianForSavePermissionCheck") + defer span.End() + newDashboard := d.ID == 0 if newDashboard { @@ -290,6 +298,9 @@ func validateDashboardRefreshInterval(minRefreshInterval string, dash *dashboard func (dr *DashboardServiceImpl) SaveProvisionedDashboard(ctx context.Context, dto *dashboards.SaveDashboardDTO, provisioning *dashboards.DashboardProvisioning) (*dashboards.Dashboard, error) { + ctx, span := tracer.Start(ctx, "dashboards.service.SaveProvisionedDashboard") + defer span.End() + if err := validateDashboardRefreshInterval(dr.cfg.MinRefreshInterval, dto.Dashboard); err != nil { dr.log.Warn("Changing refresh interval for provisioned dashboard to minimum refresh interval", "dashboardUid", dto.Dashboard.UID, "dashboardTitle", dto.Dashboard.Title, "minRefreshInterval", dr.cfg.MinRefreshInterval) @@ -317,6 +328,9 @@ func (dr *DashboardServiceImpl) SaveProvisionedDashboard(ctx context.Context, dt } func (dr *DashboardServiceImpl) SaveFolderForProvisionedDashboards(ctx context.Context, dto *folder.CreateFolderCommand) (*folder.Folder, error) { + ctx, span := tracer.Start(ctx, "dashboards.service.SaveFolderForProvisionedDashboards") + defer span.End() + dto.SignedInUser = accesscontrol.BackgroundUser("dashboard_provisioning", dto.OrgID, org.RoleAdmin, provisionerPermissions) f, err := dr.folderService.Create(ctx, dto) if err != nil { @@ -330,6 +344,9 @@ func (dr *DashboardServiceImpl) SaveFolderForProvisionedDashboards(ctx context.C func (dr *DashboardServiceImpl) SaveDashboard(ctx context.Context, dto *dashboards.SaveDashboardDTO, allowUiUpdate bool) (*dashboards.Dashboard, error) { + ctx, span := tracer.Start(ctx, "dashboards.service.SaveDashboard") + defer span.End() + if err := validateDashboardRefreshInterval(dr.cfg.MinRefreshInterval, dto.Dashboard); err != nil { dr.log.Warn("Changing refresh interval for imported dashboard to minimum refresh interval", "dashboardUid", dto.Dashboard.UID, "dashboardTitle", dto.Dashboard.Title, "minRefreshInterval", @@ -359,6 +376,9 @@ func (dr *DashboardServiceImpl) GetSoftDeletedDashboard(ctx context.Context, org } func (dr *DashboardServiceImpl) RestoreDashboard(ctx context.Context, dashboard *dashboards.Dashboard, user identity.Requester, optionalFolderUID string) error { + ctx, span := tracer.Start(ctx, "dashboards.service.RestoreDashboard") + defer span.End() + if !dr.features.IsEnabledGlobally(featuremgmt.FlagDashboardRestore) { return fmt.Errorf("feature flag %s is not enabled", featuremgmt.FlagDashboardRestore) } @@ -398,6 +418,9 @@ func (dr *DashboardServiceImpl) RestoreDashboard(ctx context.Context, dashboard } func (dr *DashboardServiceImpl) SoftDeleteDashboard(ctx context.Context, orgID int64, dashboardUID string) error { + ctx, span := tracer.Start(ctx, "dashboards.service.SoftDeleteDashboard") + defer span.End() + if !dr.features.IsEnabledGlobally(featuremgmt.FlagDashboardRestore) { return fmt.Errorf("feature flag %s is not enabled", featuremgmt.FlagDashboardRestore) } @@ -426,6 +449,9 @@ func (dr *DashboardServiceImpl) DeleteProvisionedDashboard(ctx context.Context, } func (dr *DashboardServiceImpl) deleteDashboard(ctx context.Context, dashboardId int64, orgId int64, validateProvisionedDashboard bool) error { + ctx, span := tracer.Start(ctx, "dashboards.service.deleteDashboard") + defer span.End() + if validateProvisionedDashboard { provisionedData, err := dr.GetProvisionedDashboardDataByDashboardID(ctx, dashboardId) if err != nil { @@ -442,6 +468,9 @@ func (dr *DashboardServiceImpl) deleteDashboard(ctx context.Context, dashboardId func (dr *DashboardServiceImpl) ImportDashboard(ctx context.Context, dto *dashboards.SaveDashboardDTO) ( *dashboards.Dashboard, error) { + ctx, span := tracer.Start(ctx, "dashboards.service.ImportDashboard") + defer span.End() + if err := validateDashboardRefreshInterval(dr.cfg.MinRefreshInterval, dto.Dashboard); err != nil { dr.log.Warn("Changing refresh interval for imported dashboard to minimum refresh interval", "dashboardUid", dto.Dashboard.UID, "dashboardTitle", dto.Dashboard.Title, @@ -475,6 +504,9 @@ func (dr *DashboardServiceImpl) GetDashboardsByPluginID(ctx context.Context, que } func (dr *DashboardServiceImpl) setDefaultPermissions(ctx context.Context, dto *dashboards.SaveDashboardDTO, dash *dashboards.Dashboard, provisioned bool) { + ctx, span := tracer.Start(ctx, "dashboards.service.setDefaultPermissions") + defer span.End() + resource := "dashboard" if dash.IsFolder { resource = "folder" @@ -518,6 +550,9 @@ func (dr *DashboardServiceImpl) setDefaultPermissions(ctx context.Context, dto * } func (dr *DashboardServiceImpl) setDefaultFolderPermissions(ctx context.Context, cmd *folder.CreateFolderCommand, f *folder.Folder, provisioned bool) { + ctx, span := tracer.Start(ctx, "dashboards.service.setDefaultFolderPermissions") + defer span.End() + if !dr.cfg.RBAC.PermissionsOnCreation("folder") { return } @@ -565,6 +600,9 @@ func (dr *DashboardServiceImpl) GetDashboardsSharedWithUser(ctx context.Context, } func (dr *DashboardServiceImpl) getDashboardsSharedWithUser(ctx context.Context, user identity.Requester) ([]*dashboards.Dashboard, error) { + ctx, span := tracer.Start(ctx, "dashboards.service.getDashboardsSharedWithUser") + defer span.End() + permissions := user.GetPermissions() dashboardPermissions := permissions[dashboards.ActionDashboardsRead] sharedDashboards := make([]*dashboards.Dashboard, 0) @@ -594,6 +632,9 @@ func (dr *DashboardServiceImpl) getDashboardsSharedWithUser(ctx context.Context, // filterUserSharedDashboards filter dashboards directly assigned to user, but not located in folders with view permissions func (dr *DashboardServiceImpl) filterUserSharedDashboards(ctx context.Context, user identity.Requester, userDashboards []*dashboards.Dashboard) ([]*dashboards.Dashboard, error) { + ctx, span := tracer.Start(ctx, "dashboards.service.filterUserSharedDashboards") + defer span.End() + filteredDashboards := make([]*dashboards.Dashboard, 0) folderUIDs := make([]string, 0) @@ -632,6 +673,9 @@ func (dr *DashboardServiceImpl) filterUserSharedDashboards(ctx context.Context, } func (dr *DashboardServiceImpl) getUserSharedDashboardUIDs(ctx context.Context, user identity.Requester) ([]string, error) { + ctx, span := tracer.Start(ctx, "dashboards.service.getUserSharedDashboardsUIDs") + defer span.End() + userDashboards, err := dr.getDashboardsSharedWithUser(ctx, user) if err != nil { return nil, err @@ -644,6 +688,9 @@ func (dr *DashboardServiceImpl) getUserSharedDashboardUIDs(ctx context.Context, } func (dr *DashboardServiceImpl) FindDashboards(ctx context.Context, query *dashboards.FindPersistedDashboardsQuery) ([]dashboards.DashboardSearchProjection, error) { + ctx, span := tracer.Start(ctx, "dashboards.service.FindDashboards") + defer span.End() + if dr.features.IsEnabled(ctx, featuremgmt.FlagNestedFolders) && len(query.FolderUIDs) > 0 && slices.Contains(query.FolderUIDs, folder.SharedWithMeFolderUID) { start := time.Now() userDashboardUIDs, err := dr.getUserSharedDashboardUIDs(ctx, query.SignedInUser) @@ -665,6 +712,9 @@ func (dr *DashboardServiceImpl) FindDashboards(ctx context.Context, query *dashb } func (dr *DashboardServiceImpl) SearchDashboards(ctx context.Context, query *dashboards.FindPersistedDashboardsQuery) (model.HitList, error) { + ctx, span := tracer.Start(ctx, "dashboards.service.SearchDashboards") + defer span.End() + res, err := dr.FindDashboards(ctx, query) if err != nil { return nil, err @@ -745,6 +795,9 @@ func (dr DashboardServiceImpl) CountInFolders(ctx context.Context, orgID int64, } func (dr *DashboardServiceImpl) DeleteInFolders(ctx context.Context, orgID int64, folderUIDs []string, u identity.Requester) error { + ctx, span := tracer.Start(ctx, "dashboards.service.DeleteInFolders") + defer span.End() + if dr.features.IsEnabledGlobally(featuremgmt.FlagDashboardRestore) { return dr.dashboardStore.SoftDeleteDashboardsInFolders(ctx, orgID, folderUIDs) } @@ -755,6 +808,9 @@ func (dr *DashboardServiceImpl) DeleteInFolders(ctx context.Context, orgID int64 func (dr *DashboardServiceImpl) Kind() string { return entity.StandardKindDashboard } func (dr *DashboardServiceImpl) CleanUpDeletedDashboards(ctx context.Context) (int64, error) { + ctx, span := tracer.Start(ctx, "dashboards.service.CleanUpDeletedDashboards") + defer span.End() + var deletedDashboardsCount int64 deletedDashboards, err := dr.dashboardStore.GetSoftDeletedExpiredDashboards(ctx, daysInTrash) if err != nil {