User: Add tracing (#87028)
* Inject tracer in tests * Annotate with traces Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>
This commit is contained in:
co-authored by
Gabriel MABILLE
parent
7f1b2ef205
commit
a2cba3d0b5
@@ -7,8 +7,12 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/localcache"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/quota"
|
||||
@@ -27,6 +31,7 @@ type Service struct {
|
||||
teamService team.Service
|
||||
cacheService *localcache.CacheService
|
||||
cfg *setting.Cfg
|
||||
tracer tracing.Tracer
|
||||
}
|
||||
|
||||
func ProvideService(
|
||||
@@ -34,9 +39,8 @@ func ProvideService(
|
||||
orgService org.Service,
|
||||
cfg *setting.Cfg,
|
||||
teamService team.Service,
|
||||
cacheService *localcache.CacheService,
|
||||
quotaService quota.Service,
|
||||
bundleRegistry supportbundles.Service,
|
||||
cacheService *localcache.CacheService, tracer tracing.Tracer,
|
||||
quotaService quota.Service, bundleRegistry supportbundles.Service,
|
||||
) (user.Service, error) {
|
||||
store := ProvideStore(db, cfg)
|
||||
s := &Service{
|
||||
@@ -45,6 +49,7 @@ func ProvideService(
|
||||
cfg: cfg,
|
||||
teamService: teamService,
|
||||
cacheService: cacheService,
|
||||
tracer: tracer,
|
||||
}
|
||||
|
||||
defaultLimits, err := readQuotaConfig(cfg)
|
||||
@@ -55,7 +60,7 @@ func ProvideService(
|
||||
if err := quotaService.RegisterQuotaReporter("a.NewUsageReporter{
|
||||
TargetSrv: quota.TargetSrv(user.QuotaTargetSrv),
|
||||
DefaultLimits: defaultLimits,
|
||||
Reporter: s.Usage,
|
||||
Reporter: s.usage,
|
||||
}); err != nil {
|
||||
return s, err
|
||||
}
|
||||
@@ -87,21 +92,10 @@ func (s *Service) GetUsageStats(ctx context.Context) map[string]any {
|
||||
return stats
|
||||
}
|
||||
|
||||
func (s *Service) Usage(ctx context.Context, _ *quota.ScopeParameters) (*quota.Map, error) {
|
||||
u := "a.Map{}
|
||||
if used, err := s.store.Count(ctx); err != nil {
|
||||
return u, err
|
||||
} else {
|
||||
tag, err := quota.NewTag(quota.TargetSrv(user.QuotaTargetSrv), quota.Target(user.QuotaTarget), quota.GlobalScope)
|
||||
if err != nil {
|
||||
return u, err
|
||||
}
|
||||
u.Set(tag, used)
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*user.User, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "user.Create")
|
||||
defer span.End()
|
||||
|
||||
if len(cmd.Login) == 0 {
|
||||
cmd.Login = cmd.Email
|
||||
}
|
||||
@@ -126,8 +120,7 @@ func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*use
|
||||
cmd.Email = cmd.Login
|
||||
}
|
||||
|
||||
err = s.store.LoginConflict(ctx, cmd.Login, cmd.Email)
|
||||
if err != nil {
|
||||
if err := s.store.LoginConflict(ctx, cmd.Login, cmd.Email); err != nil {
|
||||
return nil, user.ErrUserAlreadyExists
|
||||
}
|
||||
|
||||
@@ -202,27 +195,48 @@ func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*use
|
||||
}
|
||||
|
||||
func (s *Service) Delete(ctx context.Context, cmd *user.DeleteUserCommand) error {
|
||||
ctx, span := s.tracer.Start(ctx, "user.Delete", trace.WithAttributes(
|
||||
attribute.Int64("userID", cmd.UserID),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
_, err := s.store.GetByID(ctx, cmd.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// delete from all the stores
|
||||
|
||||
return s.store.Delete(ctx, cmd.UserID)
|
||||
}
|
||||
|
||||
func (s *Service) GetByID(ctx context.Context, query *user.GetUserByIDQuery) (*user.User, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "user.GetByID", trace.WithAttributes(
|
||||
attribute.Int64("userID", query.ID),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
return s.store.GetByID(ctx, query.ID)
|
||||
}
|
||||
|
||||
func (s *Service) GetByLogin(ctx context.Context, query *user.GetUserByLoginQuery) (*user.User, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "user.GetByLogin")
|
||||
defer span.End()
|
||||
|
||||
return s.store.GetByLogin(ctx, query)
|
||||
}
|
||||
|
||||
func (s *Service) GetByEmail(ctx context.Context, query *user.GetUserByEmailQuery) (*user.User, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "user.GetByEmail")
|
||||
defer span.End()
|
||||
|
||||
return s.store.GetByEmail(ctx, query)
|
||||
}
|
||||
|
||||
func (s *Service) Update(ctx context.Context, cmd *user.UpdateUserCommand) error {
|
||||
ctx, span := s.tracer.Start(ctx, "user.Update", trace.WithAttributes(
|
||||
attribute.Int64("userID", cmd.UserID),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
usr, err := s.store.GetByID(ctx, cmd.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -273,6 +287,11 @@ func (s *Service) Update(ctx context.Context, cmd *user.UpdateUserCommand) error
|
||||
}
|
||||
|
||||
func (s *Service) UpdateLastSeenAt(ctx context.Context, cmd *user.UpdateUserLastSeenAtCommand) error {
|
||||
ctx, span := s.tracer.Start(ctx, "user.UpdateLastSeen", trace.WithAttributes(
|
||||
attribute.Int64("userID", cmd.UserID),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
u, err := s.GetSignedInUserWithCacheCtx(ctx, &user.GetSignedInUserQuery{
|
||||
UserID: cmd.UserID,
|
||||
OrgID: cmd.OrgID,
|
||||
@@ -294,6 +313,12 @@ func shouldUpdateLastSeen(t time.Time) bool {
|
||||
}
|
||||
|
||||
func (s *Service) GetSignedInUserWithCacheCtx(ctx context.Context, query *user.GetSignedInUserQuery) (*user.SignedInUser, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "user.GetSignedInUserWithCacheCtx", trace.WithAttributes(
|
||||
attribute.Int64("userID", query.UserID),
|
||||
attribute.Int64("orgID", query.OrgID),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
var signedInUser *user.SignedInUser
|
||||
|
||||
// only check cache if we have a user ID and an org ID in query
|
||||
@@ -321,54 +346,62 @@ func newSignedInUserCacheKey(orgID, userID int64) string {
|
||||
}
|
||||
|
||||
func (s *Service) GetSignedInUser(ctx context.Context, query *user.GetSignedInUserQuery) (*user.SignedInUser, error) {
|
||||
signedInUser, err := s.store.GetSignedInUser(ctx, query)
|
||||
ctx, span := s.tracer.Start(ctx, "user.GetSignedInUser", trace.WithAttributes(
|
||||
attribute.Int64("userID", query.UserID),
|
||||
attribute.Int64("orgID", query.OrgID),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
usr, err := s.store.GetSignedInUser(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
getTeamsByUserQuery := &team.GetTeamIDsByUserQuery{
|
||||
OrgID: signedInUser.OrgID,
|
||||
UserID: signedInUser.UserID,
|
||||
}
|
||||
signedInUser.Teams, err = s.teamService.GetTeamIDsByUser(ctx, getTeamsByUserQuery)
|
||||
usr.Teams, err = s.teamService.GetTeamIDsByUser(ctx, &team.GetTeamIDsByUserQuery{
|
||||
OrgID: usr.OrgID,
|
||||
UserID: usr.UserID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return signedInUser, err
|
||||
return usr, err
|
||||
}
|
||||
|
||||
func (s *Service) Search(ctx context.Context, query *user.SearchUsersQuery) (*user.SearchUserQueryResult, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "user.Search", trace.WithAttributes(
|
||||
attribute.Int64("orgID", query.OrgID),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
return s.store.Search(ctx, query)
|
||||
}
|
||||
|
||||
func (s *Service) BatchDisableUsers(ctx context.Context, cmd *user.BatchDisableUsersCommand) error {
|
||||
ctx, span := s.tracer.Start(ctx, "user.BatchDisableUsers", trace.WithAttributes(
|
||||
attribute.Int64Slice("userIDs", cmd.UserIDs),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
return s.store.BatchDisableUsers(ctx, cmd)
|
||||
}
|
||||
|
||||
func (s *Service) GetProfile(ctx context.Context, query *user.GetUserProfileQuery) (*user.UserProfileDTO, error) {
|
||||
result, err := s.store.GetProfile(ctx, query)
|
||||
return result, err
|
||||
}
|
||||
ctx, span := s.tracer.Start(ctx, "user.GetProfile", trace.WithAttributes(
|
||||
attribute.Int64("userID", query.UserID),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) {
|
||||
limits := "a.Map{}
|
||||
|
||||
if cfg == nil {
|
||||
return limits, nil
|
||||
}
|
||||
|
||||
globalQuotaTag, err := quota.NewTag(quota.TargetSrv(user.QuotaTargetSrv), quota.Target(user.QuotaTarget), quota.GlobalScope)
|
||||
if err != nil {
|
||||
return limits, err
|
||||
}
|
||||
|
||||
limits.Set(globalQuotaTag, cfg.Quota.Global.User)
|
||||
return limits, nil
|
||||
return s.store.GetProfile(ctx, query)
|
||||
}
|
||||
|
||||
// CreateServiceAccount creates a service account in the user table and adds service account to an organisation in the org_user table
|
||||
func (s *Service) CreateServiceAccount(ctx context.Context, cmd *user.CreateUserCommand) (*user.User, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "user.CreateServiceAccount", trace.WithAttributes(
|
||||
attribute.Int64("orgID", cmd.OrgID),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
cmd.Email = cmd.Login
|
||||
err := s.store.LoginConflict(ctx, cmd.Login, cmd.Email)
|
||||
if err != nil {
|
||||
@@ -462,6 +495,36 @@ func (s *Service) supportBundleCollector() supportbundles.Collector {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) usage(ctx context.Context, _ *quota.ScopeParameters) (*quota.Map, error) {
|
||||
u := "a.Map{}
|
||||
if used, err := s.store.Count(ctx); err != nil {
|
||||
return u, err
|
||||
} else {
|
||||
tag, err := quota.NewTag(quota.TargetSrv(user.QuotaTargetSrv), quota.Target(user.QuotaTarget), quota.GlobalScope)
|
||||
if err != nil {
|
||||
return u, err
|
||||
}
|
||||
u.Set(tag, used)
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) {
|
||||
limits := "a.Map{}
|
||||
|
||||
if cfg == nil {
|
||||
return limits, nil
|
||||
}
|
||||
|
||||
globalQuotaTag, err := quota.NewTag(quota.TargetSrv(user.QuotaTargetSrv), quota.Target(user.QuotaTarget), quota.GlobalScope)
|
||||
if err != nil {
|
||||
return limits, err
|
||||
}
|
||||
|
||||
limits.Set(globalQuotaTag, cfg.Quota.Global.User)
|
||||
return limits, nil
|
||||
}
|
||||
|
||||
// This is just to ensure that all users have a valid uid.
|
||||
// To protect against upgrade / downgrade we need to run this for a couple of releases.
|
||||
// FIXME: Remove this migration and make uid field required https://github.com/grafana/identity-access-team/issues/552
|
||||
|
||||
Reference in New Issue
Block a user