From 6d0db9512e569763ac6c049669098b5ad12d3366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enver=20Bi=C5=A1evac?= Date: Sun, 18 Aug 2024 22:04:34 +0000 Subject: [PATCH] feat: instrumentation, intitial work (#2475) * requested changes * requested changes * feat: instrumentation, intitial work --- .../pullreq/comment_apply_suggestions.go | 18 +++ app/api/controller/pullreq/comment_create.go | 17 +++ app/api/controller/pullreq/controller.go | 4 + app/api/controller/pullreq/merge.go | 15 +++ app/api/controller/pullreq/pr_create.go | 15 +++ app/api/controller/pullreq/review_submit.go | 16 +++ app/api/controller/pullreq/wire.go | 31 +++-- app/api/controller/repo/controller.go | 4 + app/api/controller/repo/create.go | 15 ++- app/api/controller/repo/create_branch.go | 16 +++ app/api/controller/repo/create_commit_tag.go | 15 +++ app/api/controller/repo/import.go | 14 +++ app/api/controller/repo/rule_create.go | 15 +++ app/api/controller/repo/wire.go | 4 +- app/api/controller/space/controller.go | 4 + app/api/controller/space/import.go | 14 +++ .../controller/space/import_repositories.go | 16 +++ app/api/controller/space/wire.go | 6 +- app/services/instrument/git_consumer.go | 99 ++++++++++++++++ app/services/instrument/instrument.go | 82 ++++++++++++++ app/services/instrument/noop.go | 31 +++++ app/services/instrument/tasks.go | 106 ++++++++++++++++++ app/services/instrument/wire.go | 73 ++++++++++++ app/services/pullreq/service.go | 3 + app/services/pullreq/wire.go | 22 +++- app/services/wire.go | 54 +++++---- app/store/database.go | 2 + app/store/database/repo.go | 52 +++++++++ cli/operations/server/server.go | 6 + cmd/gitness/wire.go | 2 + cmd/gitness/wire_gen.go | 20 +++- types/config.go | 5 + types/repo.go | 6 + 33 files changed, 762 insertions(+), 40 deletions(-) create mode 100644 app/services/instrument/git_consumer.go create mode 100644 app/services/instrument/instrument.go create mode 100644 app/services/instrument/noop.go create mode 100644 app/services/instrument/tasks.go create mode 100644 app/services/instrument/wire.go diff --git a/app/api/controller/pullreq/comment_apply_suggestions.go b/app/api/controller/pullreq/comment_apply_suggestions.go index 37593f6922..e358f0af4c 100644 --- a/app/api/controller/pullreq/comment_apply_suggestions.go +++ b/app/api/controller/pullreq/comment_apply_suggestions.go @@ -25,6 +25,7 @@ import ( "github.com/harness/gitness/app/api/usererror" "github.com/harness/gitness/app/auth" "github.com/harness/gitness/app/bootstrap" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/app/services/protection" "github.com/harness/gitness/contextutil" "github.com/harness/gitness/git" @@ -367,6 +368,23 @@ func (c *Controller) CommentApplySuggestions( log.Ctx(ctx).Warn().Err(err).Msg("failed to publish PR changed event") } + err = c.instrumentation.Track(ctx, instrument.Event{ + Type: instrument.EventTypePRSuggestionApplied, + Principal: session.Principal.ToPrincipalInfo(), + Path: repo.Path, + Properties: map[instrument.Property]any{ + instrument.PropertyRepositoryID: repo.ID, + instrument.PropertyRepositoryName: repo.Identifier, + instrument.PropertyPullRequestID: pr.Number, + }, + }) + if err != nil { + log.Ctx(ctx).Warn().Msgf( + "failed to insert instrumentation record for pull request suggestion applied operation: %s", + err, + ) + } + return CommentApplySuggestionsOutput{ CommitID: commitOut.CommitID.String(), RuleViolations: violations, diff --git a/app/api/controller/pullreq/comment_create.go b/app/api/controller/pullreq/comment_create.go index 4f5d5b4078..47712d386b 100644 --- a/app/api/controller/pullreq/comment_create.go +++ b/app/api/controller/pullreq/comment_create.go @@ -24,6 +24,7 @@ import ( "github.com/harness/gitness/app/api/usererror" "github.com/harness/gitness/app/auth" events "github.com/harness/gitness/app/events/pullreq" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/errors" "github.com/harness/gitness/git" "github.com/harness/gitness/store" @@ -224,6 +225,22 @@ func (c *Controller) CommentCreate( c.reportCommentCreated(ctx, pr, session.Principal.ID, act.ID, act.IsReply()) } + err = c.instrumentation.Track(ctx, instrument.Event{ + Type: instrument.EventTypeCreatePRComment, + Principal: session.Principal.ToPrincipalInfo(), + Path: repo.Path, + Properties: map[instrument.Property]any{ + instrument.PropertyRepositoryID: repo.ID, + instrument.PropertyRepositoryName: repo.Identifier, + instrument.PropertyPullRequestID: pr.Number, + instrument.PropertyCommentIsReplied: in.IsReply(), + instrument.PropertyCommentContainsSuggestion: len(parseSuggestions(in.Text)) > 0, + }, + }) + if err != nil { + log.Ctx(ctx).Warn().Msgf("failed to insert instrumentation record for create pull request comment operation: %s", err) + } + return act, nil } diff --git a/app/api/controller/pullreq/controller.go b/app/api/controller/pullreq/controller.go index 4ddb603962..cfd63e0a1c 100644 --- a/app/api/controller/pullreq/controller.go +++ b/app/api/controller/pullreq/controller.go @@ -26,6 +26,7 @@ import ( pullreqevents "github.com/harness/gitness/app/events/pullreq" "github.com/harness/gitness/app/services/codecomments" "github.com/harness/gitness/app/services/codeowners" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/app/services/label" locker "github.com/harness/gitness/app/services/locker" "github.com/harness/gitness/app/services/migrate" @@ -68,6 +69,7 @@ type Controller struct { locker *locker.Locker importer *migrate.PullReq labelSvc *label.Service + instrumentation instrument.Service } func NewController( @@ -95,6 +97,7 @@ func NewController( locker *locker.Locker, importer *migrate.PullReq, labelSvc *label.Service, + instrumentation instrument.Service, ) *Controller { return &Controller{ tx: tx, @@ -121,6 +124,7 @@ func NewController( locker: locker, importer: importer, labelSvc: labelSvc, + instrumentation: instrumentation, } } diff --git a/app/api/controller/pullreq/merge.go b/app/api/controller/pullreq/merge.go index 1bc5c23904..0df983c4d4 100644 --- a/app/api/controller/pullreq/merge.go +++ b/app/api/controller/pullreq/merge.go @@ -27,6 +27,7 @@ import ( "github.com/harness/gitness/app/bootstrap" pullreqevents "github.com/harness/gitness/app/events/pullreq" "github.com/harness/gitness/app/services/codeowners" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/app/services/protection" "github.com/harness/gitness/contextutil" "github.com/harness/gitness/errors" @@ -498,6 +499,20 @@ func (c *Controller) Merge( log.Ctx(ctx).Warn().Err(err).Msg("failed to publish PR changed event") } + err = c.instrumentation.Track(ctx, instrument.Event{ + Type: instrument.EventTypeMergePullRequest, + Principal: session.Principal.ToPrincipalInfo(), + Path: sourceRepo.Path, + Properties: map[instrument.Property]any{ + instrument.PropertyRepositoryID: sourceRepo.ID, + instrument.PropertyRepositoryName: sourceRepo.Identifier, + instrument.PropertyPullRequestID: pr.Number, + instrument.PropertyMergeStrategy: in.Method, + }, + }) + if err != nil { + log.Ctx(ctx).Warn().Msgf("failed to insert instrumentation record for merge pr operation: %s", err) + } return &types.MergeResponse{ SHA: mergeOutput.MergeSHA.String(), BranchDeleted: branchDeleted, diff --git a/app/api/controller/pullreq/pr_create.go b/app/api/controller/pullreq/pr_create.go index b277ad52e3..53de04e8cd 100644 --- a/app/api/controller/pullreq/pr_create.go +++ b/app/api/controller/pullreq/pr_create.go @@ -23,6 +23,7 @@ import ( "github.com/harness/gitness/app/api/usererror" "github.com/harness/gitness/app/auth" pullreqevents "github.com/harness/gitness/app/events/pullreq" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/git" "github.com/harness/gitness/git/sha" "github.com/harness/gitness/types" @@ -154,6 +155,20 @@ func (c *Controller) Create( log.Ctx(ctx).Warn().Err(err).Msg("failed to publish PR changed event") } + err = c.instrumentation.Track(ctx, instrument.Event{ + Type: instrument.EventTypeCreatePullRequest, + Principal: session.Principal.ToPrincipalInfo(), + Path: sourceRepo.Path, + Properties: map[instrument.Property]any{ + instrument.PropertyRepositoryID: sourceRepo.ID, + instrument.PropertyRepositoryName: sourceRepo.Identifier, + instrument.PropertyPullRequestID: pr.Number, + }, + }) + if err != nil { + log.Ctx(ctx).Warn().Msgf("failed to insert instrumentation record for create pull request operation: %s", err) + } + return pr, nil } diff --git a/app/api/controller/pullreq/review_submit.go b/app/api/controller/pullreq/review_submit.go index a3738201d1..8ccb5880ba 100644 --- a/app/api/controller/pullreq/review_submit.go +++ b/app/api/controller/pullreq/review_submit.go @@ -23,6 +23,7 @@ import ( "github.com/harness/gitness/app/api/usererror" "github.com/harness/gitness/app/auth" events "github.com/harness/gitness/app/events/pullreq" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/git" "github.com/harness/gitness/store" "github.com/harness/gitness/types" @@ -142,6 +143,21 @@ func (c *Controller) ReviewSubmit( log.Ctx(ctx).Err(err).Msgf("failed to write pull request activity after review submit") } + err = c.instrumentation.Track(ctx, instrument.Event{ + Type: instrument.EventTypeReviewPullRequest, + Principal: session.Principal.ToPrincipalInfo(), + Path: repo.Path, + Properties: map[instrument.Property]any{ + instrument.PropertyRepositoryID: repo.ID, + instrument.PropertyRepositoryName: repo.Identifier, + instrument.PropertyPullRequestID: pr.Number, + instrument.PropertyDecision: in.Decision, + }, + }) + if err != nil { + log.Ctx(ctx).Warn().Msgf("failed to insert instrumentation record for review pull request operation: %s", err) + } + return review, nil } diff --git a/app/api/controller/pullreq/wire.go b/app/api/controller/pullreq/wire.go index 38a76bfb7f..c5ca5e85ed 100644 --- a/app/api/controller/pullreq/wire.go +++ b/app/api/controller/pullreq/wire.go @@ -19,6 +19,7 @@ import ( pullreqevents "github.com/harness/gitness/app/events/pullreq" "github.com/harness/gitness/app/services/codecomments" "github.com/harness/gitness/app/services/codeowners" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/app/services/label" "github.com/harness/gitness/app/services/locker" "github.com/harness/gitness/app/services/migrate" @@ -50,16 +51,32 @@ func ProvideController(tx dbtx.Transactor, urlProvider url.Provider, authorizer pullreqService *pullreq.Service, ruleManager *protection.Manager, sseStreamer sse.Streamer, codeOwners *codeowners.Service, locker *locker.Locker, importer *migrate.PullReq, labelSvc *label.Service, + instrumentation instrument.Service, ) *Controller { - return NewController(tx, urlProvider, authorizer, - pullReqStore, pullReqActivityStore, + return NewController(tx, + urlProvider, + authorizer, + pullReqStore, + pullReqActivityStore, codeCommentsView, - pullReqReviewStore, pullReqReviewerStore, + pullReqReviewStore, + pullReqReviewerStore, repoStore, - principalStore, principalInfoCache, - fileViewStore, membershipStore, + principalStore, + principalInfoCache, + fileViewStore, + membershipStore, checkStore, - rpcClient, eventReporter, + rpcClient, + eventReporter, codeCommentMigrator, - pullreqService, ruleManager, sseStreamer, codeOwners, locker, importer, labelSvc) + pullreqService, + ruleManager, + sseStreamer, + codeOwners, + locker, + importer, + labelSvc, + instrumentation, + ) } diff --git a/app/api/controller/repo/controller.go b/app/api/controller/repo/controller.go index d4b94d8c19..1fb2bf094a 100644 --- a/app/api/controller/repo/controller.go +++ b/app/api/controller/repo/controller.go @@ -29,6 +29,7 @@ import ( repoevents "github.com/harness/gitness/app/events/repo" "github.com/harness/gitness/app/services/codeowners" "github.com/harness/gitness/app/services/importer" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/app/services/keywordsearch" "github.com/harness/gitness/app/services/label" "github.com/harness/gitness/app/services/locker" @@ -94,6 +95,7 @@ type Controller struct { repoCheck Check publicAccess publicaccess.Service labelSvc *label.Service + instrumentation instrument.Service } func NewController( @@ -122,6 +124,7 @@ func NewController( repoCheck Check, publicAccess publicaccess.Service, labelSvc *label.Service, + instrumentation instrument.Service, ) *Controller { return &Controller{ defaultBranch: config.Git.DefaultBranch, @@ -149,6 +152,7 @@ func NewController( repoCheck: repoCheck, publicAccess: publicAccess, labelSvc: labelSvc, + instrumentation: instrumentation, } } diff --git a/app/api/controller/repo/create.go b/app/api/controller/repo/create.go index 7e3f1e53e8..475d2b665e 100644 --- a/app/api/controller/repo/create.go +++ b/app/api/controller/repo/create.go @@ -29,6 +29,7 @@ import ( "github.com/harness/gitness/app/bootstrap" "github.com/harness/gitness/app/githook" "github.com/harness/gitness/app/paths" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/audit" "github.com/harness/gitness/git" "github.com/harness/gitness/resources" @@ -164,7 +165,19 @@ func (c *Controller) Create(ctx context.Context, session *auth.Session, in *Crea if err != nil { log.Ctx(ctx).Warn().Msgf("failed to insert audit log for create repository operation: %s", err) } - + err = c.instrumentation.Track(ctx, instrument.Event{ + Type: instrument.EventTypeRepositoryCreate, + Principal: session.Principal.ToPrincipalInfo(), + Path: repo.Path, + Properties: map[instrument.Property]any{ + instrument.PropertyRepositoryID: repo.ID, + instrument.PropertyRepositoryName: repo.Identifier, + instrument.PropertyRepositoryCreationType: instrument.CreationTypeCreate, + }, + }) + if err != nil { + log.Ctx(ctx).Warn().Msgf("failed to insert instrumentation record for create repository operation: %s", err) + } // index repository if files are created if !repo.IsEmpty { err = c.indexer.Index(ctx, repo) diff --git a/app/api/controller/repo/create_branch.go b/app/api/controller/repo/create_branch.go index d1581de45c..428ed25efd 100644 --- a/app/api/controller/repo/create_branch.go +++ b/app/api/controller/repo/create_branch.go @@ -20,10 +20,13 @@ import ( "github.com/harness/gitness/app/api/controller" "github.com/harness/gitness/app/auth" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/app/services/protection" "github.com/harness/gitness/git" "github.com/harness/gitness/types" "github.com/harness/gitness/types/enum" + + "github.com/rs/zerolog/log" ) // CreateBranchInput used for branch creation apis. @@ -93,5 +96,18 @@ func (c *Controller) CreateBranch(ctx context.Context, return nil, nil, fmt.Errorf("failed to map branch: %w", err) } + err = c.instrumentation.Track(ctx, instrument.Event{ + Type: instrument.EventTypeCreateBranch, + Principal: session.Principal.ToPrincipalInfo(), + Path: repo.Path, + Properties: map[instrument.Property]any{ + instrument.PropertyRepositoryID: repo.ID, + instrument.PropertyRepositoryName: repo.Identifier, + }, + }) + if err != nil { + log.Ctx(ctx).Warn().Msgf("failed to insert instrumentation record for create branch operation: %s", err) + } + return &branch, nil, nil } diff --git a/app/api/controller/repo/create_commit_tag.go b/app/api/controller/repo/create_commit_tag.go index c0584e59c8..76f20219ca 100644 --- a/app/api/controller/repo/create_commit_tag.go +++ b/app/api/controller/repo/create_commit_tag.go @@ -21,10 +21,13 @@ import ( "github.com/harness/gitness/app/api/controller" "github.com/harness/gitness/app/auth" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/app/services/protection" "github.com/harness/gitness/git" "github.com/harness/gitness/types" "github.com/harness/gitness/types/enum" + + "github.com/rs/zerolog/log" ) // CreateCommitTagInput used for tag creation apis. @@ -101,5 +104,17 @@ func (c *Controller) CreateCommitTag(ctx context.Context, return nil, nil, fmt.Errorf("failed to map tag received from service output: %w", err) } + err = c.instrumentation.Track(ctx, instrument.Event{ + Type: instrument.EventTypeCreateTag, + Principal: session.Principal.ToPrincipalInfo(), + Path: repo.Path, + Properties: map[instrument.Property]any{ + instrument.PropertyRepositoryID: repo.ID, + instrument.PropertyRepositoryName: repo.Identifier, + }, + }) + if err != nil { + log.Ctx(ctx).Warn().Msgf("failed to insert instrumentation record for create tag operation: %s", err) + } return &commitTag, nil, nil } diff --git a/app/api/controller/repo/import.go b/app/api/controller/repo/import.go index b59af47550..4fe459025a 100644 --- a/app/api/controller/repo/import.go +++ b/app/api/controller/repo/import.go @@ -22,6 +22,7 @@ import ( "github.com/harness/gitness/app/auth" "github.com/harness/gitness/app/paths" "github.com/harness/gitness/app/services/importer" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/audit" "github.com/rs/zerolog/log" @@ -114,6 +115,19 @@ func (c *Controller) Import(ctx context.Context, session *auth.Session, in *Impo log.Warn().Msgf("failed to insert audit log for import repository operation: %s", err) } + err = c.instrumentation.Track(ctx, instrument.Event{ + Type: instrument.EventTypeRepositoryCreate, + Principal: session.Principal.ToPrincipalInfo(), + Path: repo.Path, + Properties: map[instrument.Property]any{ + instrument.PropertyRepositoryID: repo.ID, + instrument.PropertyRepositoryName: repo.Identifier, + instrument.PropertyRepositoryCreationType: instrument.CreationTypeImport, + }, + }) + if err != nil { + log.Ctx(ctx).Warn().Msgf("failed to insert instrumentation record for import repository operation: %s", err) + } return GetRepoOutputWithAccess(ctx, false, repo), nil } diff --git a/app/api/controller/repo/rule_create.go b/app/api/controller/repo/rule_create.go index af92a9243c..8d93152874 100644 --- a/app/api/controller/repo/rule_create.go +++ b/app/api/controller/repo/rule_create.go @@ -23,6 +23,7 @@ import ( "github.com/harness/gitness/app/api/usererror" "github.com/harness/gitness/app/auth" "github.com/harness/gitness/app/paths" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/app/services/protection" "github.com/harness/gitness/audit" "github.com/harness/gitness/types" @@ -127,6 +128,20 @@ func (c *Controller) RuleCreate(ctx context.Context, log.Ctx(ctx).Warn().Msgf("failed to insert audit log for create branch rule operation: %s", err) } + err = c.instrumentation.Track(ctx, instrument.Event{ + Type: instrument.EventTypeCreateBranchRule, + Principal: session.Principal.ToPrincipalInfo(), + Path: repo.Path, + Properties: map[instrument.Property]any{ + instrument.PropertyRepositoryID: repo.ID, + instrument.PropertyRepositoryName: repo.Identifier, + instrument.PropertyRuleID: r.ID, + }, + }) + if err != nil { + log.Ctx(ctx).Warn().Msgf("failed to insert instrumentation record for create branch rule operation: %s", err) + } + r.Users, err = c.getRuleUsers(ctx, r) if err != nil { return nil, err diff --git a/app/api/controller/repo/wire.go b/app/api/controller/repo/wire.go index b6fe7e3bcb..8ef541df32 100644 --- a/app/api/controller/repo/wire.go +++ b/app/api/controller/repo/wire.go @@ -20,6 +20,7 @@ import ( repoevents "github.com/harness/gitness/app/events/repo" "github.com/harness/gitness/app/services/codeowners" "github.com/harness/gitness/app/services/importer" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/app/services/keywordsearch" "github.com/harness/gitness/app/services/label" "github.com/harness/gitness/app/services/locker" @@ -69,13 +70,14 @@ func ProvideController( repoChecks Check, publicAccess publicaccess.Service, labelSvc *label.Service, + instrumentation instrument.Service, ) *Controller { return NewController(config, tx, urlProvider, authorizer, repoStore, spaceStore, pipelineStore, principalStore, ruleStore, settings, principalInfoCache, protectionManager, rpcClient, importer, codeOwners, reporeporter, indexer, limiter, locker, auditService, mtxManager, identifierCheck, - repoChecks, publicAccess, labelSvc) + repoChecks, publicAccess, labelSvc, instrumentation) } func ProvideRepoCheck() Check { diff --git a/app/api/controller/space/controller.go b/app/api/controller/space/controller.go index 45a020783e..9582d9d87c 100644 --- a/app/api/controller/space/controller.go +++ b/app/api/controller/space/controller.go @@ -24,6 +24,7 @@ import ( "github.com/harness/gitness/app/services/exporter" "github.com/harness/gitness/app/services/gitspace" "github.com/harness/gitness/app/services/importer" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/app/services/label" "github.com/harness/gitness/app/services/publicaccess" "github.com/harness/gitness/app/sse" @@ -85,6 +86,7 @@ type Controller struct { auditService audit.Service gitspaceSvc *gitspace.Service labelSvc *label.Service + instrumentation instrument.Service } func NewController(config *types.Config, tx dbtx.Transactor, urlProvider url.Provider, @@ -95,6 +97,7 @@ func NewController(config *types.Config, tx dbtx.Transactor, urlProvider url.Pro membershipStore store.MembershipStore, importer *importer.Repository, exporter *exporter.Repository, limiter limiter.ResourceLimiter, publicAccess publicaccess.Service, auditService audit.Service, gitspaceSvc *gitspace.Service, labelSvc *label.Service, + instrumentation instrument.Service, ) *Controller { return &Controller{ nestedSpacesEnabled: config.NestedSpacesEnabled, @@ -120,5 +123,6 @@ func NewController(config *types.Config, tx dbtx.Transactor, urlProvider url.Pro auditService: auditService, gitspaceSvc: gitspaceSvc, labelSvc: labelSvc, + instrumentation: instrumentation, } } diff --git a/app/api/controller/space/import.go b/app/api/controller/space/import.go index 9e08d03dad..e9b12922d9 100644 --- a/app/api/controller/space/import.go +++ b/app/api/controller/space/import.go @@ -23,6 +23,7 @@ import ( "github.com/harness/gitness/app/auth" "github.com/harness/gitness/app/paths" "github.com/harness/gitness/app/services/importer" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/audit" "github.com/harness/gitness/types" @@ -137,6 +138,19 @@ func (c *Controller) Import(ctx context.Context, session *auth.Session, in *Impo if err != nil { log.Warn().Msgf("failed to insert audit log for import repository operation: %s", err) } + err = c.instrumentation.Track(ctx, instrument.Event{ + Type: instrument.EventTypeRepositoryCreate, + Principal: session.Principal.ToPrincipalInfo(), + Path: space.Path, + Properties: map[instrument.Property]any{ + instrument.PropertyRepositoryID: repo.ID, + instrument.PropertyRepositoryName: repo.Identifier, + instrument.PropertyRepositoryCreationType: instrument.CreationTypeImport, + }, + }) + if err != nil { + log.Ctx(ctx).Warn().Msgf("failed to insert instrumentation record for import repository operation: %s", err) + } } return GetSpaceOutput(ctx, c.publicAccess, space) diff --git a/app/api/controller/space/import_repositories.go b/app/api/controller/space/import_repositories.go index 127386afca..54b6d1da5f 100644 --- a/app/api/controller/space/import_repositories.go +++ b/app/api/controller/space/import_repositories.go @@ -18,6 +18,7 @@ import ( "context" "errors" "fmt" + "time" apiauth "github.com/harness/gitness/app/api/auth" "github.com/harness/gitness/app/api/controller/limiter" @@ -26,6 +27,7 @@ import ( "github.com/harness/gitness/app/auth" "github.com/harness/gitness/app/paths" "github.com/harness/gitness/app/services/importer" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/audit" "github.com/harness/gitness/store" "github.com/harness/gitness/types" @@ -182,6 +184,20 @@ func (c *Controller) ImportRepositories( if err != nil { log.Warn().Msgf("failed to insert audit log for import repository operation: %s", err) } + err = c.instrumentation.Track(ctx, instrument.Event{ + Type: instrument.EventTypeRepositoryCreate, + Principal: session.Principal.ToPrincipalInfo(), + Timestamp: time.Now(), + Path: space.Path, + Properties: map[instrument.Property]any{ + instrument.PropertyRepositoryID: repo.ID, + instrument.PropertyRepositoryName: repo.Identifier, + instrument.PropertyRepositoryCreationType: instrument.CreationTypeImport, + }, + }) + if err != nil { + log.Ctx(ctx).Warn().Msgf("failed to insert instrumentation record for import repository operation: %s", err) + } } duplicateReposOut := make([]*repoctrl.RepositoryOutput, len(duplicateRepos)) diff --git a/app/api/controller/space/wire.go b/app/api/controller/space/wire.go index 8b694af7be..812b69638f 100644 --- a/app/api/controller/space/wire.go +++ b/app/api/controller/space/wire.go @@ -21,6 +21,7 @@ import ( "github.com/harness/gitness/app/services/exporter" "github.com/harness/gitness/app/services/gitspace" "github.com/harness/gitness/app/services/importer" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/app/services/label" "github.com/harness/gitness/app/services/publicaccess" "github.com/harness/gitness/app/sse" @@ -48,6 +49,7 @@ func ProvideController(config *types.Config, tx dbtx.Transactor, urlProvider url exporter *exporter.Repository, limiter limiter.ResourceLimiter, publicAccess publicaccess.Service, auditService audit.Service, gitspaceService *gitspace.Service, labelSvc *label.Service, + instrumentation instrument.Service, ) *Controller { return NewController(config, tx, urlProvider, sseStreamer, identifierCheck, authorizer, spacePathStore, pipelineStore, secretStore, @@ -56,5 +58,7 @@ func ProvideController(config *types.Config, tx dbtx.Transactor, urlProvider url repoCtrl, membershipStore, importer, exporter, limiter, publicAccess, auditService, gitspaceService, - labelSvc) + labelSvc, + instrumentation, + ) } diff --git a/app/services/instrument/git_consumer.go b/app/services/instrument/git_consumer.go new file mode 100644 index 0000000000..1f7d7a7915 --- /dev/null +++ b/app/services/instrument/git_consumer.go @@ -0,0 +1,99 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package instrument + +import ( + "context" + "fmt" + "time" + + gitevents "github.com/harness/gitness/app/events/git" + "github.com/harness/gitness/app/store" + "github.com/harness/gitness/events" + "github.com/harness/gitness/stream" + "github.com/harness/gitness/types" + + "github.com/rs/zerolog/log" +) + +type Consumer struct { + repoStore store.RepoStore + principalInfoCache store.PrincipalInfoCache + instrumentation Service +} + +func NewConsumer(ctx context.Context, + config *types.Config, + gitReaderFactory *events.ReaderFactory[*gitevents.Reader], + repoStore store.RepoStore, + principalInfoCache store.PrincipalInfoCache, + instrumentation Service, +) (Consumer, error) { + c := Consumer{ + repoStore: repoStore, + principalInfoCache: principalInfoCache, + instrumentation: instrumentation, + } + + const groupCommitInstrument = "gitness:git:instrumentation" + _, err := gitReaderFactory.Launch(ctx, groupCommitInstrument, config.InstanceID, + func(r *gitevents.Reader) error { + const idleTimeout = 10 * time.Second + r.Configure( + stream.WithConcurrency(3), + stream.WithHandlerOptions( + stream.WithIdleTimeout(idleTimeout), + stream.WithMaxRetries(2), + )) + + _ = r.RegisterBranchUpdated(c.instrumentTrackOnBranchUpdate) + + return nil + }) + if err != nil { + return Consumer{}, fmt.Errorf("failed to launch git consumer: %w", err) + } + return c, nil +} + +func (c Consumer) instrumentTrackOnBranchUpdate( + ctx context.Context, + event *events.Event[*gitevents.BranchUpdatedPayload], +) error { + repo, err := c.repoStore.Find(ctx, event.Payload.RepoID) + if err != nil { + return fmt.Errorf("failed to get repo git info: %w", err) + } + + principal, err := c.principalInfoCache.Get(ctx, event.Payload.PrincipalID) + if err != nil { + return fmt.Errorf("failed to get principal info: %w", err) + } + + err = c.instrumentation.Track(ctx, Event{ + Type: EventTypeCreateCommit, + Principal: principal, + Path: repo.Path, + Properties: map[Property]any{ + PropertyRepositoryID: repo.ID, + PropertyRepositoryName: repo.Identifier, + PropertyIsDefaultBranch: event.Payload.Ref == repo.DefaultBranch, + }, + }) + if err != nil { + log.Ctx(ctx).Warn().Msgf("failed to insert instrumentation record for create commit operation: %s", err) + } + return nil +} diff --git a/app/services/instrument/instrument.go b/app/services/instrument/instrument.go new file mode 100644 index 0000000000..0cba0ab243 --- /dev/null +++ b/app/services/instrument/instrument.go @@ -0,0 +1,82 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package instrument + +import ( + "context" + "time" + + "github.com/harness/gitness/types" +) + +type CreationType string + +const ( + CreationTypeCreate CreationType = "CREATE" + CreationTypeImport CreationType = "IMPORT" +) + +type Property string + +const ( + PropertyRepositoryID Property = "repository_id" + PropertyRepositoryName Property = "repository_name" + PropertyRepositoryCreationType Property = "creation_type" + PropertyPullRequestID Property = "pull_request_id" + PropertyCommentIsReplied Property = "comment_is_replied" + PropertyCommentContainsSuggestion Property = "contains_suggestion" + PropertyMergeStrategy Property = "merge_strategy" + PropertyRuleID Property = "rule_id" + PropertyIsDefaultBranch Property = "is_default_branch" + PropertyDecision Property = "decision" + PropertyRepositories Property = "repositories" +) + +type EventType string + +const ( + EventTypeRepositoryCreate EventType = "Repository create" + EventTypeRepositoryCount EventType = "Repository count" + EventTypeCommitCount EventType = "Commit count" + EventTypeCreateCommit EventType = "Create commit" + EventTypeCreateBranch EventType = "Create branch" + EventTypeCreateTag EventType = "Create tag" + EventTypeCreatePullRequest EventType = "Create pull request" + EventTypeMergePullRequest EventType = "Merge pull request" + EventTypeReviewPullRequest EventType = "Review pull request" + EventTypeCreatePRComment EventType = "Create PR comment" + EventTypeCreateBranchRule EventType = "Create branch rule" + EventTypePRSuggestionApplied EventType = "Pull request suggestion applied" +) + +func (e EventType) String() string { + return string(e) +} + +type Event struct { + Type EventType `json:"event"` + Category string `json:"category"` + Principal *types.PrincipalInfo `json:"user_id,omitempty"` + GroupID string `json:"group_id,omitempty"` + Timestamp time.Time `json:"timestamp,omitempty"` + Path string `json:"path"` + RemoteAddr string `json:"remote_addr"` + Properties map[Property]any `json:"properties,omitempty"` +} + +type Service interface { + Track(ctx context.Context, event Event) error + Close(ctx context.Context) error +} diff --git a/app/services/instrument/noop.go b/app/services/instrument/noop.go new file mode 100644 index 0000000000..09572582fc --- /dev/null +++ b/app/services/instrument/noop.go @@ -0,0 +1,31 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package instrument + +import "context" + +type Noop struct { +} + +func (n Noop) Track( + context.Context, + Event, +) error { + return nil +} + +func (n Noop) Close(context.Context) error { + return nil +} diff --git a/app/services/instrument/tasks.go b/app/services/instrument/tasks.go new file mode 100644 index 0000000000..7292d81ef2 --- /dev/null +++ b/app/services/instrument/tasks.go @@ -0,0 +1,106 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package instrument + +import ( + "context" + "fmt" + "time" + + "github.com/harness/gitness/app/bootstrap" + "github.com/harness/gitness/app/store" + "github.com/harness/gitness/errors" + "github.com/harness/gitness/job" + "github.com/harness/gitness/types" + + "github.com/rs/zerolog/log" +) + +const ( + jobType = "instrumentation-total-repositories" +) + +type RepositoryCount struct { + enabled bool + svc Service + repoStore store.RepoStore +} + +func NewRepositoryCount( + ctx context.Context, + config *types.Config, + svc Service, + repoStore store.RepoStore, + scheduler *job.Scheduler, + executor *job.Executor, +) (*RepositoryCount, error) { + r := &RepositoryCount{ + enabled: config.Instrumentation.Enable, + svc: svc, + repoStore: repoStore, + } + + err := executor.Register(jobType, r) + if err != nil { + return nil, fmt.Errorf("failed to register instrumentation job: %w", err) + } + + if scheduler == nil { + return nil, errors.New("job scheduler is nil") + } + err = scheduler.AddRecurring(ctx, jobType, jobType, config.Instrumentation.Cron, time.Minute) + if err != nil { + return nil, fmt.Errorf("failed to register recurring job for instrumentation: %w", err) + } + + return r, nil +} + +func (c *RepositoryCount) Handle(ctx context.Context, _ string, _ job.ProgressReporter) (string, error) { + if !c.enabled { + return "", errors.New("instrumentation service is disabled") + } + + if c.repoStore == nil { + return "", errors.New("repository store not initialized") + } + // total repos in the system + totalRepos, err := c.repoStore.CountByRootSpaces(ctx) + if err != nil { + return "", fmt.Errorf("failed to get repositories total count: %w", err) + } + + if c.svc == nil { + return "", errors.New("service not initialized") + } + + systemPrincipal := bootstrap.NewSystemServiceSession().Principal + + for _, item := range totalRepos { + err = c.svc.Track(ctx, Event{ + Type: EventTypeRepositoryCount, + Principal: systemPrincipal.ToPrincipalInfo(), + GroupID: item.SpaceUID, + Properties: map[Property]any{ + PropertyRepositories: item.Total, + }, + }) + if err != nil { + log.Ctx(ctx).Warn().Msgf("failed to insert instrumentation record for repository count operation: %s", err) + } + } + + return "", nil +} diff --git a/app/services/instrument/wire.go b/app/services/instrument/wire.go new file mode 100644 index 0000000000..ead6fef10f --- /dev/null +++ b/app/services/instrument/wire.go @@ -0,0 +1,73 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package instrument + +import ( + "context" + + gitevents "github.com/harness/gitness/app/events/git" + "github.com/harness/gitness/app/store" + "github.com/harness/gitness/events" + "github.com/harness/gitness/job" + "github.com/harness/gitness/types" + + "github.com/google/wire" +) + +var WireSet = wire.NewSet( + ProvideService, + ProvideRepositoryCount, + ProvideGitConsumer, +) + +func ProvideGitConsumer( + ctx context.Context, + config *types.Config, + gitReaderFactory *events.ReaderFactory[*gitevents.Reader], + repoStore store.RepoStore, + principalInfoCache store.PrincipalInfoCache, + instrumentation Service, +) (Consumer, error) { + return NewConsumer( + ctx, + config, + gitReaderFactory, + repoStore, + principalInfoCache, + instrumentation, + ) +} + +func ProvideRepositoryCount( + ctx context.Context, + config *types.Config, + svc Service, + repoStore store.RepoStore, + scheduler *job.Scheduler, + executor *job.Executor, +) (*RepositoryCount, error) { + return NewRepositoryCount( + ctx, + config, + svc, + repoStore, + scheduler, + executor, + ) +} + +func ProvideService() Service { + return Noop{} +} diff --git a/app/services/pullreq/service.go b/app/services/pullreq/service.go index b87c08a3e7..24a71b2c60 100644 --- a/app/services/pullreq/service.go +++ b/app/services/pullreq/service.go @@ -43,6 +43,7 @@ type Service struct { pullreqStore store.PullReqStore activityStore store.PullReqActivityStore codeCommentView store.CodeCommentView + principalInfoCache store.PrincipalInfoCache codeCommentMigrator *codecomments.Migrator fileViewStore store.PullReqFileViewStore sseStreamer sse.Streamer @@ -68,6 +69,7 @@ func New(ctx context.Context, codeCommentView store.CodeCommentView, codeCommentMigrator *codecomments.Migrator, fileViewStore store.PullReqFileViewStore, + principalInfoCache store.PrincipalInfoCache, bus pubsub.PubSub, urlProvider url.Provider, sseStreamer sse.Streamer, @@ -79,6 +81,7 @@ func New(ctx context.Context, repoStore: repoStore, pullreqStore: pullreqStore, activityStore: activityStore, + principalInfoCache: principalInfoCache, codeCommentView: codeCommentView, urlProvider: urlProvider, codeCommentMigrator: codeCommentMigrator, diff --git a/app/services/pullreq/wire.go b/app/services/pullreq/wire.go index 52123f80f1..b594043418 100644 --- a/app/services/pullreq/wire.go +++ b/app/services/pullreq/wire.go @@ -45,6 +45,7 @@ func ProvideService(ctx context.Context, repoStore store.RepoStore, pullreqStore store.PullReqStore, activityStore store.PullReqActivityStore, + principalInfoCache store.PrincipalInfoCache, codeCommentView store.CodeCommentView, codeCommentMigrator *codecomments.Migrator, fileViewStore store.PullReqFileViewStore, @@ -52,7 +53,22 @@ func ProvideService(ctx context.Context, urlProvider url.Provider, sseStreamer sse.Streamer, ) (*Service, error) { - return New(ctx, config, gitReaderFactory, pullReqEvFactory, pullReqEvReporter, git, - repoGitInfoCache, repoStore, pullreqStore, activityStore, - codeCommentView, codeCommentMigrator, fileViewStore, pubsub, urlProvider, sseStreamer) + return New(ctx, + config, + gitReaderFactory, + pullReqEvFactory, + pullReqEvReporter, + git, + repoGitInfoCache, + repoStore, + pullreqStore, + activityStore, + codeCommentView, + codeCommentMigrator, + fileViewStore, + principalInfoCache, + pubsub, + urlProvider, + sseStreamer, + ) } diff --git a/app/services/wire.go b/app/services/wire.go index 464de8596b..500e37845b 100644 --- a/app/services/wire.go +++ b/app/services/wire.go @@ -20,6 +20,7 @@ import ( "github.com/harness/gitness/app/services/gitspaceevent" "github.com/harness/gitness/app/services/gitspaceinfraevent" "github.com/harness/gitness/app/services/infraprovider" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/app/services/keywordsearch" "github.com/harness/gitness/app/services/metric" "github.com/harness/gitness/app/services/notification" @@ -37,17 +38,20 @@ var WireSet = wire.NewSet( ) type Services struct { - Webhook *webhook.Service - PullReq *pullreq.Service - Trigger *trigger.Service - JobScheduler *job.Scheduler - MetricCollector *metric.Collector - RepoSizeCalculator *repo.SizeCalculator - Repo *repo.Service - Cleanup *cleanup.Service - Notification *notification.Service - Keywordsearch *keywordsearch.Service - GitspaceService *GitspaceServices + Webhook *webhook.Service + PullReq *pullreq.Service + Trigger *trigger.Service + JobScheduler *job.Scheduler + MetricCollector *metric.Collector + RepoSizeCalculator *repo.SizeCalculator + Repo *repo.Service + Cleanup *cleanup.Service + Notification *notification.Service + Keywordsearch *keywordsearch.Service + GitspaceService *GitspaceServices + Instrumentation instrument.Service + instrumentConsumer instrument.Consumer + instrumentRepoCounter *instrument.RepositoryCount } type GitspaceServices struct { @@ -83,18 +87,24 @@ func ProvideServices( notificationSvc *notification.Service, keywordsearchSvc *keywordsearch.Service, gitspaceSvc *GitspaceServices, + instrumentation instrument.Service, + instrumentConsumer instrument.Consumer, + instrumentRepoCounter *instrument.RepositoryCount, ) Services { return Services{ - Webhook: webhooksSvc, - PullReq: pullReqSvc, - Trigger: triggerSvc, - JobScheduler: jobScheduler, - MetricCollector: metricCollector, - RepoSizeCalculator: repoSizeCalculator, - Repo: repo, - Cleanup: cleanupSvc, - Notification: notificationSvc, - Keywordsearch: keywordsearchSvc, - GitspaceService: gitspaceSvc, + Webhook: webhooksSvc, + PullReq: pullReqSvc, + Trigger: triggerSvc, + JobScheduler: jobScheduler, + MetricCollector: metricCollector, + RepoSizeCalculator: repoSizeCalculator, + Repo: repo, + Cleanup: cleanupSvc, + Notification: notificationSvc, + Keywordsearch: keywordsearchSvc, + GitspaceService: gitspaceSvc, + Instrumentation: instrumentation, + instrumentConsumer: instrumentConsumer, + instrumentRepoCounter: instrumentRepoCounter, } } diff --git a/app/store/database.go b/app/store/database.go index b78d32f15c..eca9bc661c 100644 --- a/app/store/database.go +++ b/app/store/database.go @@ -248,6 +248,8 @@ type ( // Count of active repos in a space. With "DeletedBeforeOrAt" filter, counts deleted repos. Count(ctx context.Context, parentID int64, opts *types.RepoFilter) (int64, error) + CountByRootSpaces(ctx context.Context) ([]types.RepositoryCount, error) + // List returns a list of repos in a space. With "DeletedBeforeOrAt" filter, lists deleted repos. List(ctx context.Context, parentID int64, opts *types.RepoFilter) ([]*types.Repository, error) diff --git a/app/store/database/repo.go b/app/store/database/repo.go index bb84f0b1e6..5c8267cdb5 100644 --- a/app/store/database/repo.go +++ b/app/store/database/repo.go @@ -593,6 +593,58 @@ func (s *RepoStore) countAll( return numRepos, nil } +// CountByRootSpaces counts total number of repositories grouped by root spaces. +func (s *RepoStore) CountByRootSpaces( + ctx context.Context, +) ([]types.RepositoryCount, error) { + query := ` +WITH RECURSIVE + SpaceHierarchy(root_id, space_id, space_parent_id, space_uid) AS ( + SELECT space_id, space_id, space_parent_id, space_uid + FROM spaces + WHERE space_parent_id is null + + UNION + + SELECT h.root_id, s.space_id, s.space_parent_id, h.space_uid + FROM spaces s + JOIN SpaceHierarchy h ON s.space_parent_id = h.space_id + ) +SELECT + COUNT(r.repo_id) AS total, + s.root_id AS root_space_id, + s.space_uid +FROM repositories r +JOIN SpaceHierarchy s ON s.space_id = r.repo_parent_id +GROUP BY root_space_id, s.space_uid +` + + db := dbtx.GetAccessor(ctx, s.db) + + rows, err := db.QueryxContext(ctx, query) + if err != nil { + return nil, database.ProcessSQLErrorf(ctx, err, "failed to count repositories") + } + + defer rows.Close() + + var result []types.RepositoryCount + for rows.Next() { + var count types.RepositoryCount + if err = rows.Scan(&count.Total, &count.SpaceID, &count.SpaceUID); err != nil { + return nil, database.ProcessSQLErrorf(ctx, err, "failed to scan row for count repositories query") + } + + result = append(result, count) + } + + if err = rows.Err(); err != nil { + return nil, err + } + + return result, nil +} + // List returns a list of active repos in a space. // With "DeletedBeforeOrAt" filter, lists deleted repos by opts.DeletedBeforeOrAt. func (s *RepoStore) List( diff --git a/cli/operations/server/server.go b/cli/operations/server/server.go index b3714f7ccc..bb334c6192 100644 --- a/cli/operations/server/server.go +++ b/cli/operations/server/server.go @@ -166,6 +166,12 @@ func (c *command) run(*kingpin.ParseContext) error { } } + // shutdown instrumentation + err = system.services.Instrumentation.Close(shutdownCtx) + if err != nil { + log.Err(err).Msg("failed to close instrumentation gracefully") + } + // shutdown job scheduler system.services.JobScheduler.WaitJobsDone(shutdownCtx) log.Info().Msg("wait for subroutines to complete") diff --git a/cmd/gitness/wire.go b/cmd/gitness/wire.go index 7abaaadd2b..23bfc1e825 100644 --- a/cmd/gitness/wire.go +++ b/cmd/gitness/wire.go @@ -71,6 +71,7 @@ import ( "github.com/harness/gitness/app/services/gitspaceevent" "github.com/harness/gitness/app/services/gitspaceservice" "github.com/harness/gitness/app/services/importer" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/app/services/keywordsearch" svclabel "github.com/harness/gitness/app/services/label" locker "github.com/harness/gitness/app/services/locker" @@ -238,6 +239,7 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e gitspaceservice.WireSet, cliserver.ProvideGitspaceInfraProvisionerConfig, cliserver.ProvideIDEVSCodeConfig, + instrument.WireSet, ) return &cliserver.System{}, nil } diff --git a/cmd/gitness/wire_gen.go b/cmd/gitness/wire_gen.go index ed95f70ecd..1c9c9a0721 100644 --- a/cmd/gitness/wire_gen.go +++ b/cmd/gitness/wire_gen.go @@ -72,6 +72,7 @@ import ( "github.com/harness/gitness/app/services/gitspaceinfraevent" "github.com/harness/gitness/app/services/importer" infraprovider2 "github.com/harness/gitness/app/services/infraprovider" + "github.com/harness/gitness/app/services/instrument" "github.com/harness/gitness/app/services/keywordsearch" "github.com/harness/gitness/app/services/label" "github.com/harness/gitness/app/services/locker" @@ -226,7 +227,8 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro labelValueStore := database.ProvideLabelValueStore(db) pullReqLabelAssignmentStore := database.ProvidePullReqLabelStore(db) labelService := label.ProvideLabel(transactor, spaceStore, labelStore, labelValueStore, pullReqLabelAssignmentStore) - repoController := repo.ProvideController(config, transactor, provider, authorizer, repoStore, spaceStore, pipelineStore, principalStore, ruleStore, settingsService, principalInfoCache, protectionManager, gitInterface, repository, codeownersService, reporter, indexer, resourceLimiter, lockerLocker, auditService, mutexManager, repoIdentifier, repoCheck, publicaccessService, labelService) + instrumentService := instrument.ProvideService() + repoController := repo.ProvideController(config, transactor, provider, authorizer, repoStore, spaceStore, pipelineStore, principalStore, ruleStore, settingsService, principalInfoCache, protectionManager, gitInterface, repository, codeownersService, reporter, indexer, resourceLimiter, lockerLocker, auditService, mutexManager, repoIdentifier, repoCheck, publicaccessService, labelService, instrumentService) reposettingsController := reposettings.ProvideController(authorizer, repoStore, settingsService, auditService) executionStore := database.ProvideExecutionStore(db) checkStore := database.ProvideCheckStore(db, principalInfoCache) @@ -272,7 +274,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro factory := infraprovider.ProvideFactory(dockerProvider) infraproviderService := infraprovider2.ProvideInfraProvider(transactor, infraProviderResourceStore, infraProviderConfigStore, infraProviderTemplateStore, factory, spaceStore) gitspaceService := gitspace.ProvideGitspace(transactor, gitspaceConfigStore, gitspaceInstanceStore, spaceStore, infraproviderService) - spaceController := space.ProvideController(config, transactor, provider, streamer, spaceIdentifier, authorizer, spacePathStore, pipelineStore, secretStore, connectorStore, templateStore, spaceStore, repoStore, principalStore, repoController, membershipStore, repository, exporterRepository, resourceLimiter, publicaccessService, auditService, gitspaceService, labelService) + spaceController := space.ProvideController(config, transactor, provider, streamer, spaceIdentifier, authorizer, spacePathStore, pipelineStore, secretStore, connectorStore, templateStore, spaceStore, repoStore, principalStore, repoController, membershipStore, repository, exporterRepository, resourceLimiter, publicaccessService, auditService, gitspaceService, labelService, instrumentService) pipelineController := pipeline.ProvideController(repoStore, triggerStore, authorizer, pipelineStore) secretController := secret.ProvideController(encrypter, secretStore, authorizer, spaceStore) triggerController := trigger.ProvideController(authorizer, triggerStore, pipelineStore, repoStore) @@ -300,12 +302,12 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro } repoGitInfoView := database.ProvideRepoGitInfoView(db) repoGitInfoCache := cache.ProvideRepoGitInfoCache(repoGitInfoView) - pullreqService, err := pullreq.ProvideService(ctx, config, readerFactory, eventsReaderFactory, reporter2, gitInterface, repoGitInfoCache, repoStore, pullReqStore, pullReqActivityStore, codeCommentView, migrator, pullReqFileViewStore, pubSub, provider, streamer) + pullreqService, err := pullreq.ProvideService(ctx, config, readerFactory, eventsReaderFactory, reporter2, gitInterface, repoGitInfoCache, repoStore, pullReqStore, pullReqActivityStore, principalInfoCache, codeCommentView, migrator, pullReqFileViewStore, pubSub, provider, streamer) if err != nil { return nil, err } pullReq := migrate.ProvidePullReqImporter(provider, gitInterface, principalStore, repoStore, pullReqStore, pullReqActivityStore, transactor) - pullreqController := pullreq2.ProvideController(transactor, provider, authorizer, pullReqStore, pullReqActivityStore, codeCommentView, pullReqReviewStore, pullReqReviewerStore, repoStore, principalStore, principalInfoCache, pullReqFileViewStore, membershipStore, checkStore, gitInterface, reporter2, migrator, pullreqService, protectionManager, streamer, codeownersService, lockerLocker, pullReq, labelService) + pullreqController := pullreq2.ProvideController(transactor, provider, authorizer, pullReqStore, pullReqActivityStore, codeCommentView, pullReqReviewStore, pullReqReviewerStore, repoStore, principalStore, principalInfoCache, pullReqFileViewStore, membershipStore, checkStore, gitInterface, reporter2, migrator, pullreqService, protectionManager, streamer, codeownersService, lockerLocker, pullReq, labelService, instrumentService) webhookConfig := server.ProvideWebhookConfig(config) webhookStore := database.ProvideWebhookStore(db) webhookExecutionStore := database.ProvideWebhookExecutionStore(db) @@ -443,7 +445,15 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro return nil, err } gitspaceServices := services.ProvideGitspaceServices(gitspaceeventService, infraproviderService, gitspaceService, gitspaceinfraeventService) - servicesServices := services.ProvideServices(webhookService, pullreqService, triggerService, jobScheduler, collector, sizeCalculator, repoService, cleanupService, notificationService, keywordsearchService, gitspaceServices) + consumer, err := instrument.ProvideGitConsumer(ctx, config, readerFactory, repoStore, principalInfoCache, instrumentService) + if err != nil { + return nil, err + } + repositoryCount, err := instrument.ProvideRepositoryCount(ctx, config, instrumentService, repoStore, jobScheduler, executor) + if err != nil { + return nil, err + } + servicesServices := services.ProvideServices(webhookService, pullreqService, triggerService, jobScheduler, collector, sizeCalculator, repoService, cleanupService, notificationService, keywordsearchService, gitspaceServices, instrumentService, consumer, repositoryCount) serverSystem := server.NewSystem(bootstrapBootstrap, serverServer, sshServer, poller, resolverManager, servicesServices) return serverSystem, nil } diff --git a/types/config.go b/types/config.go index 22473ea5f5..73136c9530 100644 --- a/types/config.go +++ b/types/config.go @@ -422,4 +422,9 @@ type Config struct { MaxRetries int `envconfig:"GITNESS_GITSPACE_EVENTS_MAX_RETRIES" default:"3"` } } + + Instrumentation struct { + Enable bool `envconfig:"GITNESS_INSTRUMENTATION_ENABLE" default:"false"` + Cron string `envconfig:"GITNESS_INSTRUMENTATION_CRON" default:"0 0 * * *"` + } } diff --git a/types/repo.go b/types/repo.go index ee94ff9fec..148c6d38a6 100644 --- a/types/repo.go +++ b/types/repo.go @@ -114,3 +114,9 @@ type RepositorySummary struct { TagCount int `json:"tag_count"` PullReqSummary RepositoryPullReqSummary `json:"pull_req_summary"` } + +type RepositoryCount struct { + SpaceID int64 `json:"space_id"` + SpaceUID string `json:"space_uid"` + Total int `json:"total"` +}